Write the Code. Change the World.

分类目录
3月 02

这里来安装 naiveui,将上一步的测试页面搭建完成。

官网: https://www.naiveui.com/zh-CN/os-theme

安装

pnpm add -D naive-ui

流行的组件库,都支持按需引入。我们通过 unplugin-auto-import插件来完成。

pnpm add -D unplugin-vue-components

pnpm add -D unplugin-auto-import

然后再 vite.config.js 中进行配置。

import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    AutoImport({
      imports: ['vue']
    }),
    Components({
      resolvers: [
        NaiveUiResolver()
      ]
    })
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})

通过上边的配置,就可以在项目中,直接使用 naiveui 的组件了。

现在,我们修改下 header.vue。来实现登录注册首页三个页面的跳转。

# header.vue
<template>
    <header>
        <div>
      <n-avatar round size="large" @click="goHome">
        LOGO
      </n-avatar>
    </div>

        <div class="nav-bar">
            <n-space class="left-nav">
                <n-button quaternary @click="goHome">首页</n-button>
                <n-button quaternary>产品介绍</n-button>
                <n-button quaternary>关于我们</n-button>
            </n-space>

            <n-space class="right-nav">
                <n-button type="success" size="small" style="font-size: 12px;" @click="goLogin">登录</n-button>
                <n-button type="success" size="small" style="font-size: 12px" @click="goRegister">注册</n-button>
            </n-space>
        </div>
    </header>
</template>

<script setup>

import { useRouter } from 'vue-router'

const router = useRouter()

const goHome = () => {
    router.push({name: 'home'})
}

const goLogin = () => {
  router.push({name: 'login'})
}

const goRegister = () => {
  router.push({name: 'register'})
}
</script>

<style lang="scss" scoped>
header {
    display: flex;
    align-items: center;
    box-sizing: border-box;
    padding: 0 30px;
    width: 100%;
    height: 72px;
    background-color: #fff;
    box-shadow: 0 0.125rem 0.25rem #00000013 !important;

  .nav-bar {
    display: flex;
    align-items: center;
    width: 100%;
    box-sizing: border-box;
    padding-left: 50px;

    .left-nav {
      flex:1;
    }
  }
}
</style>

效果如下:

提交代码。

git add .
git commit -m '安装 Naive以及配置顶部 Ui'

顶部ui以及路由跳转完成了。现在做注册页面的 ui 以及相关逻辑。

注册页面

对注册页面 ui 简单的进行一个布局,对表单数据只进行了基础的验证,就是只要存在就好。更详细的规则没配置。

<template>
    <div class="container">
        <div class="form-wrap">
            <n-card title="注册">
                <n-form
                    ref="formRef"
                    :model="model"
                    :rules="rules"
                    label-placement="left"
                    label-width="auto"
                    require-mark-placement="right-hanging"
                    :style="{
                        maxWidth: '640px'
                    }">
                    <n-form-item label="称呼" path="name">
                        <n-input v-model:value="model.name" :placeholder="rules.name.message" />
                    </n-form-item>
                    <n-form-item label="邮箱" path="email">
                        <n-input v-model:value="model.email" :placeholder="rules.email.message" />
                    </n-form-item>
                    <n-form-item label="密码" path="password">
                        <n-input type="password" v-model:value="model.password" :placeholder="rules.password.message" />
                    </n-form-item>
                    <n-form-item label="确认密码" path="confirmPassword">
                        <n-input type="password" v-model:value="model.confirmPassword" :placeholder="rules.confirmPassword.message" />
                    </n-form-item>

                    <n-form-item label=" " :show-feedback="false" class="register-item">
                        <n-button strong type="primary" @click="submit">注册</n-button>
                    </n-form-item>
                </n-form>
            </n-card>
        </div>
    </div>
</template>

<script setup>
import { ref, reactive } from 'vue'

const formRef = ref(null)

const model = reactive({
    name: null,
    email: null,
    password: null,
    confirmPassword: null
})

const rules = {
    name: {
        required: true,
        trigger: ['blur', 'input'],
        message: '请输入称呼'
    },
    email: {
        required: true,
        trigger: ['blur', 'input'],
        message: '请输入邮箱'
    },
    password: {
        required: true,
        trigger: ['blur', 'input'],
        message: '请输入密码'
    },
    confirmPassword: {
        required: true,
        trigger: ['blur', 'input'],
        message: '请输入确认密码'
    }
}

const submit = () => {
    formRef.value?.validate((errors) => {
        if (errors) {
            console.error(errors)
        }
    }).then(() => {

  })
}
</script>

<style lang="scss" scoped>
.container {
    display: flex;
    justify-content: center;

    .form-wrap {
        display: flex;
        margin: 30px 0;
        min-width: 640px;
    }

    .register-item {
        margin-top: 12px;
    }
}
</style>

效果如下:

提交代码。

git add .
git commit -m '注册页面的搭建'

开始写数据请求部分的逻辑了。一般用 axios、flyio 这类库。这里用 axios。

安装、配置、使用 axios

pnpm add axios

安装好后,然后简单封装一个请求库,src/api/request.js
如下:

import axios from 'axios'

// 全局基本配置
axios.defaults.baseURL = 'http://ypb2.com/admin/api/'
axios.withCredentials = true
axios.timeout = 20000

// 请求拦截器
axios.interceptors.request.use(
    (config) => {
        config.headers = {
            Authorization: `Bearer ${GetToken()}`
        }
        return config
    },
    (error) => {
        return Promise.reject(error)
    }
)

// 响应拦截器
axios.interceptors.response.use(
    (response) => {
        return response
    },
    (error) => {
        return Promise.reject(error)
    }
)

// 获取 token
function GetToken() {
    const token = localStorage.getItem('token')
    const now = new Date().getTime() / 1000
    if (token && token.expires_at > now) {
        return token.token
    }
    return null
}

// scrf-cookie
const GetCsrfCookie = () => {
    return axios.get('csrf-cookie')
}

// 登录
const Login = (data) => {
    return axios.post('login', data)
}

// 注册
const Register = (data) => {
    return axios.post('register', data)
}

export {
    GetCsrfCookie,
    Login,
    Register
}

然后就可以在 register.vue 中用起来了

import { ref, reactive, onMounted } from 'vue'
import { Register } from '@/api/request.js'


…
onMounted(() => {
    Register(null).then()
})

当然,这样肯定是有问题的。一个是跨域,另外一个也是不符合服务端 Sanctum 认证的场景的。默认进来必须先进行一个 csrf-cookie 请求。再进行登录或注册的逻辑。

为了更贴合服务端的请求。我们将 base 设置为 admin,并且将 vue-router 的base也设置成 admin。

# vite.config.js
export default defineConfig({
  base: '/admin',
  build: {
    outDir: 'admin'
  },
  …


# router/index.js
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  base: '/admin/',
  routes: [
  …

于是,访问的地址就变成:http://ypb2.com/admin/

这样在 vite 这里是可以的。但是在 nginx 那边就不行。打开页面再刷新就找不到资源了。对 nginx 也需要配置。这里先配置好。

cd /etc/nginx/sites-enabled

sudo vim ypb2.com

# 添加下边的配置
    location ~* ^\/admin\/((?!api\/).) {
        try_files $uri $uri/ /admin/index.html;
    }

# 重启 nginx
sudo nginx -s reload

这个配置很重要的哈。到此,算是前端打包的配置完成。git 版本控制中将 admin 目录设置为忽略。提交版本控制。

git add .
git commit -m '配置输出文件夹,路由前缀等'
2月 01

视频以及动画是一个比较好的视觉体验。可是,移动端 h5 的 video 标签不能自动播放视频。下边总结下处理方案。其实,就是在网上找到别人的解决方案来解决自己的事情。

处理处理

video 标签

<video class="video" poster="xxx.jpg" autoplay loop muted 
        playsinline="true"
        x5-playsinline="true" 
        webkit-playsinline="" 
        x-webkit-airplay="allow" 
        x5-video-player-type="h5"
        preload="auto">
                <source src="xxx.mp4" type="video/mp4">
        </video>

方法1,使用类似 gif 图的方式,来实现是视频播放的效果。

https://blog.csdn.net/qq_33929420/article/details/114962347

方法2,使用 js 来手动处理播放

//其他移动端浏览器只能让用户自己触发
$(window).on('touchstart', function(){
    $("video")[0].play();
});
// 兼容微信(微信可以自动播放)
document.addEventListener("WeixinJSBridgeReady", function () {
    $("video")[0].play();
}, false);
12月 13

2022年 10月25日后发布的小程序,无论通过 wx.getUserProfile 还是 wx.getUserInfo 获取到的的用户的信息中(之前也仅能获取头像和昵称。性别地区啥的都会没有),只会有昵称为微信用户,头像为灰色头像的有用信息。说实话,对于开发者,这种搞法太过恶心。

但实践中发现有部分小程序,在用户刚打开小程序时就要求收集用户的微信昵称头像,或者在支付前等不合理路径上要求授权。如果用户拒绝授权,则无法使用小程序或相关功能。在已经获取用户的 openId 与 unionId 信息情况下,用户的微信昵称与头像并不是用户使用小程序的必要条件。为减少此类不合理的强迫授权情况,作出如下调整。

你把你审核的锅摔给开发者,你可以审核的时候不让这种小程序上架不就可以了。记得2019年的时候,就有这样的说明。必须登录注册才能使用的用户不给上架的说明。现在搞什么飞机。

官方相关说明和解决方法

https://developers.weixin.qq.com/community/develop/doc/00022c683e8a80b29bed2142b56c01

https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/userProfile.html

11月 30

数组

sort() 方法对数组的项目进行排序。
排序顺序可以是按字母或数字,也可以是升序(向上)或降序(向下)。
默认情况下,sort() 方法将按字母和升序将值作为字符串进行排序。

如:

let fruits = ["Banana", "Orange", "Apple", "Mango"];

fruits.sort();

# 输出 ['Apple', 'Banana', 'Mango', 'Orange']

fruits.reverse();
# 输出 ['Orange', 'Mango', 'Banana', 'Apple']

不过基于数字的排序,是按字符串来排序的。比如 33 排序比 123 要后。 如果非要基于数字大小来排。可以通过传入函数的方式来解决。

比如:

let arr = [1, 123, 22,5, 32];
arr.sort((a,b)=>(a-b));
# 输出 1, 5, 22, 32, 123
# 这样就可以基于数字来排序了

如果是基于数组里的 object ,也可以通过这种方式来排序。

Object 呢

对 object 按键值排序,一般在做加密验证的时候会用到。

有了数组的排序,object 也一样可以。

let param = {
    name: 'vini123',
    gender: 1,
    time: 1669796346
}

let sorted = {};
Object.keys(param).sort().forEach(key => {
    sorted[key] = param[key];
});
11月 19

在微信环境,通过分享方式(非用户搜索,非小程序盒子), 能打开目标小程序,进入目标页面的方式。除了扫小程序码还有小程序链接方式。生成小程序性链接的能力有各种控制,链接的作用和生命也各有控制。做一个体验好,效果好的分享,得细心和用心。还得处处找一切能突破微信自己的阻碍。

主要是小程序分享到朋友圈从来就没一个好的体验。可以通过海报的方式,但用户得长按海报。不是所有人都知道要长按,也不是所有人都愿意长按。其他途径,比如小程序链接。虽然用户可以点击进入,但每次都弹个窗让用户确认。从体验感来说是不好,从用户意愿度(广告)来讲,算是一次告知。可是,既然用户愿意点了,意愿度还是有的,何必弹个窗来恶心人呢。每个人都有每个人的考虑,人在屋檐下,不得不低头。

https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/qrcode-link/url-scheme/queryScheme.html

https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/url-scheme.html

开始

看了下边的各种说明,只想说在微信内,打开小程序的途径 scheme 码和 urllink 都不好。这种码 A 打开了,其他人就打不开了。怎么发朋友圈宣传。短链接看起来是最好的,可短链接不是谁都有权限生成的,只有特殊服务类目才可以。就像获取用户当前位置一样,需要特殊服务目录(这个还得去申请接口权限)才有资格用。说来说去,微信内朋友圈宣传只能短链接或海报了。只能去争取申请能获取该接口的服务了。

微信外打开小程序 scheme 码 ios 是直接可以,android 需要借助 h5。 urllink 必须都得先跳转到 h5。只是跳转到 h5,然后再跳转到小程序。不必在 h5 那边再点击再跳转。就是 scheme 码和 urllink 只能一个人打开就有点恶心。

其实还有一种方式,是可以的。就是使用微信开放标签。需要借助服务号(个人可以借助云开发的静态网站),需要额外调用 js。请看下边的链接。

https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_Open_Tag.html#%E5%BC%80%E6%94%BE%E6%A0%87%E7%AD%BE%E8%AF%B4%E6%98%8E%E6%96%87%E6%A1%A3

https://developers.weixin.qq.com/miniprogram/dev/wxcloud/guide/staticstorage/introduction.html

scheme 码

该接口用于获取小程序 scheme 码,适用于短信、邮件、外部网页、微信内等拉起小程序的业务场景。通过该接口,可以选择生成到期失效和永久有效的小程序码,有数量限制,目前仅针对国内非个人主体的小程序开放

# 重点说明
自 2022 年 4 月 11 日起,URL Scheme有效期最长 30 天,不再支持永久有效的URL Scheme、不再区分短期有效URL Scheme与长期有效URL Scheme。若在微信外打开,用户可以在浏览器页面点击进入小程序。每个独立的URL Scheme被用户访问后,仅此用户可以再次访问并打开对应小程序,其他用户无法再次通过相同URL Scheme打开该小程序。 在本次规则调整生效前已经生成的URL Scheme,如果有效期超过30天或长期会被降级为30天有效,只能被1个用户访问,开始时间从调整日期开始计算。

每天生成 URL Scheme 和 URL Link 总数量上限为50万

iOS系统支持识别 URL Scheme,可在短信等应用场景中直接通过 Scheme 跳转小程序。
Android系统不支持直接识别 URL Scheme,用户无法通过 Scheme 正常打开小程序,开发者需要使用 H5 页面中转,再跳转到 Scheme 实现打开小程序

urllink

获取小程序 URL Link,适用于短信、邮件、网页、微信内等拉起小程序的业务场景。通过该接口,可以选择生成到期失效和永久有效的小程序链接,有数量限制,目前仅针对国内非个人主体的小程序开放

# 重点说明
自 2022 年 4 月 11 日起,URL Link有效期最长 30 天,不再支持永久有效的URL Link、不再区分短期有效URL Link与长期有效URL Link。若在微信外打开,用户可以在浏览器页面点击进入小程序。每个独立的URL Link被用户访问后,仅此用户可以再次访问并打开对应小程序,其他用户无法再次通过相同URL Link打开该小程序。 在本次规则调整生效前已经生成的URL Link,如果有效期超过30天或长期会被降级为30天有效,只能被1个用户访问,开始时间从调整日期开始计算。 

每天生成 URL Scheme 和 URL Link 总数量上限为50万

只能生成已发布的小程序的 URL Link。
在微信内或者安卓手机打开 URL Link 时,默认会先跳转官方 H5 中间页,如果需要定制 H5 内容,可以使用云开发静态网站。

short link

获取小程序 Short Link,适用于微信内拉起小程序的业务场景。目前只开放给电商类目(具体包含以下一级类目:电商平台、商家自营、跨境电商)。通过该接口,可以选择生成到期失效和永久有效的小程序短链

通过服务端接口可以获取打开小程序任意页面的 Short Link。适用于微信内拉起小程序的业务场景。

目前只开放给电商类目小程序,具体包含以下一级类目:电商平台、商家自营、跨境电商。

最终

说了好多啰嗦的话。微信内推广,宣传,短链接肯定是最好用的。可得去申请服务类目。官方说只对电商开放。不过,看到其他非电商类目的也可以(比如招聘)。