前言
到现在 Vue3.0 正式发布快有一个年头了,同时后续也发布的更快的打包工具 Vite 也更新到了 2.x版本,相信有很多小伙伴也已经在公司的新项目中应用起来,体验这一快感,下面这篇文章总结下项目中基于 Vite2.x + Vue3.0 常用小基操。
注册组件
在开发项目多数情况少不了使用 UI 框架组件来快速开发搭建我们的页面,一般使用组件库时,为了减小包体积(tree-shshaking 技术),都采用按需加载的方式。
以 Vant 组件使用为例,通常我们会:
import { createApp } from "vue";
import App from "./App.vue";
const app = createApp(App);
// 引入组件
import {
Progress,
Picker,
Popup,
....
} from "vant";
// app.use() 注册
app.use(Progress)
.use(Picker)
.use(Picker)
...
.mount("#app");
简单的引用几个组件还好,看起来没有拉面条,想想就这样引入算了,如果有二十三十个就显得很长也会让 main.ts
越来越大,基于模块化开发思想,最好单独封装到一个配置文件中。
创建一个 config 文件夹下 vant.config.ts 文件名中
import {
Progress,
Picker,
Popup,
....
} from "vant";
const components = {
Progress,
Picker,
Popup,
....
}
// .use 内部会自动寻找 install 方法进行调用注册挂载
const componentsInstallHandler = {
install(app) {
Object.keys(components).forEach(key => app.use(components[key]))
}
}
export default componentsInstallHandler
main.ts 中
// ...省略 createApp 引入
// 导入
import vantComponentsInstall from "./config/vant.config";
app
.use(vantComponentsInstall)
.mount("#app");
这样操作完是不是舒服多了~
组件全局注册
自己编写了一个比如 <Header/>
组件想要全局使用,这时候可以调用 createApp() 返回的 component 函数进行全局注册
// ...省略 createApp 引入
import Header from '@/components/Header/Index.vue'
app.component('Header', Header)
过滤器
在 3.x 中,过滤器已删除,不再支持。相反地,可以用方法调用或计算属性代替它。
<template>
<div>
{{computedFunc('computed')}}
</div>
</template>
<script lang="ts">
import { computed, defineComponent} from "vue";
export default defineComponent({
setup() {
// 使用 闭包 接受传递参数
const computedFunc = () => {
return val => val
}
return {
computedFunc
}
}
})
</script>
全局过滤器
比如多个组件中数据渲染值都需要解密后才能正确显示,不可能每一个组件里面都写 computed,这时候可以通过 全局属性 在所有组件中使用它:
// main.ts
const app = createApp(App)
app.config.globalProperties.$filters = {
decrypt(value) {
return mdDecrypt(value)
},
然后,就可以通过 $filters
对象修改所有的模板:
<template>
<p>{{ $filters.decrypt(encryptVal) }}</p>
</template>
自定义 UI 框架主题色
每个设计师采用的主题色不一样,UI 框架默认的主题色不是我们想要的,想必我们需要自定义配置一下。下面以 Vant 为例:
import { defineConfig } from 'vite'
export default defineConfig({
css: {
preprocessorOptions: {
less: {
javascriptEnabled: true,
// 需要自定义样式变量名称
modifyVars: {
'blue': '#00C6B8',
'gray-7': '#333333',
'gray-4': '#00C6B8',
...
},
},
},
},
})
服务代理 server
在开发测试调用后端服务地址,少不了需要 server 代理,Vue2.x 配合 Vue-CLI 可以在 config/index.js 添加 proxyTable
修改添加, Vite 中又是怎么添加的呢,Vite 官网也有说明,下面看看如何配置:
import { defineConfig } from 'vite'
export default defineConfig({
server: {
port: 3006, // 设置端口,默认 3000
open: true, // 设置启动时,自动打开浏览器
cors: true, // 允许跨域
host:'10.x.x.x', // 本地 IP 访问,如何移动端手机调试就需要填写本地 IP 了
proxy: {
'/api': {
target: 'http://10.x.x.x.x',
changeOrigin: true,
secure: false,
rewrite: path => path.replace('/api/', '/')
}
// 配置多个继续添加
'/api2': {
...
}
},
},
})
配置别名
写法有很多种,可以是一个对象,或一个 { find, replacement }
具体可以看 options
import vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
export default defineConfig({
resolve: {
alias: [
{
find: "@",
replacement: resolve(__dirname, "src"),
},
{
find: "@ASS",
replacement: resolve(__dirname, "src/assets"),
},
]
},
server: {
....
},
})
移动端 rem 自适应
结合使用 amfe-flexible
和 postcss-pxtorem
实现移动端适配。
amfe-flexible
amfe-flexible
是配置克伸缩布局方案,主要将 1rem设为viewWidth/10。
postcss-pxtorem
postcss-pxtorem 是 postcss的插件,用于将像素单位生成 rem 单位。
npm 安装
npm i amfe-flexible -D
npm i postcss-pxtorem -D
安装完毕后,在 main.ts 中导入 amfe-flexible 插件
// ...
import 'amfe-flexible/index.js'
postcss-pxtorem 配置
配置 postcss-pxtorem 方式有三种,可以在 vite.config.ts、.postcssrc.ts、postcss.copnfig.ts 其中之一配置即可。
vite.config.ts 中配置如下:
import { defineConfig } from 'vite'
export default defineConfig({
css: {
... ,
loaderOptions: {
postcss: {
plugins: [
require('postcss-pxtorem')({
rootValue: 37.5, // 根据设计稿宽度除以10进行设置,这边假设设计稿为375,即rootValue设为37.5,我这里设置
propList: ['*'] // // propList是设置需要转换的属性,这边*为所有都进行转换。
})
]
}
}
},
})
根目录创建 .postcssrc.ts 或者 postcss.copnfig.ts 配置如下:
module.exports = {
plugins: {
autoprefixer: {
overrideBrowserslist: [
'Android 4.1',
'iOS 7.1',
'Chrome > 31',
'ff > 31',
'ie >= 8',
'last 10 versions', // 所有主流浏览器最近10版本用
],
},
postcss-pxtorem: {
rootValue: 37.5,
propList: ['*'],
},
},
}
配置完毕重启看看效果:
还可以 引入 rem.js 方式,不过需要编写样式的时候自己 px 转 rem ,好在 vscode 扩展商店中有px to rem 插件一件转换,这里展开了,可以自行 google 一下就有了。
环境变量
有时候项目开发中需要部署有三种运行环境中比如 测试环境(test)、开发环境(dev)、生成环境(prod),请求的接口地址也需要更换,如何动态的更换呢? Vite 在一个特殊的 import.meta.env
对象上暴露环境变量,可以通过暴露的环境变量来判断是运行在哪一个环境中。
npm run dev 运行 import.meta.env
暴露的变量值为 development
npm run build import.meta.env
暴露的变量值为 production
还有一种 测试环境(test)如何拿到呢?
可以通过 package.json 配置 scripts run 命令
"scripts": {
"dev": "vite",
"build": "vite build",
"test:build": "vite build --mode test",
},
运行 npm run test:build import.meta.env
暴露变量值为 test 了 --mode xxx 名称可以自定义
请求 URL 统一管理 config.ts:
export const DEV_BASE_URL = "https://xxx"
export const TEST_BASE_URL = "https://xxx"
export const PRO_BASE_URL = "https://xxx"
以封装 axios
设置 baseURL 为例:
import { DEV_BASE_URL, PRO_BASE_URL, TEST_BASE_URL, TIMEOUT } from "./config";
const envMap = {
development: DEV_BASE_URL,
production: PRO_BASE_URL,
test: TEST_BASE_URL,
};
const base_URL = envMap[import.meta.env.MODE];
// axios
const instance = axios.create({
baseURL: base_URL,
timeout: 30000,
});
hooks 使用
升级 Vue3 后,让人最脑壳痛应该不是 Compostion API 语法,而是提供了给我们全新的组织代码的思维方式。
刚开始 Vue3.0 正式发布学习完之后,代码也是遵循 Compostion API 正确用法,可是当组件庞大,逻辑复杂,代码量也是很多,发现比 Options API 写法维护性更差,也是慢慢写成了 拉面条...
下面结合真实业务需求讲解一下
比如有一个获取验证码方法,点击获取完毕60s倒计时后才能重新获取,正常霹雳巴拉我们会这么写:
example.vue
<template>
<button @click="onGetCode">{{ codeText }}</button>
</template>
<script lang="ts">
import { defineComponent, reactive, toRefs } from "vue";
export default defineComponent({
setup(props, ctx) {
const state = reactive({
isGetCode: false,
codeText: '获取验证码',
countDown: 60,
phone: ''
})
// 点击后倒计时
const countTime = () => {
state.isGetCode = true
let timer
timer = setInterval(
(function setIntervalFunc() {
if (countDown !== 0) {
state.codeText = `重新发送${countDown.value--}`
} else {
state.isGetCode = false
state.codeText = '获取验证码'
state.countDown = 60
clearInterval(timer)
}
return setIntervalFunc
})(),
1000
)
}
// 获取验证码请求
const onGetCode = async () => {
const { success, message } = await getPhoneCode(encrypt(state.phone))
if (success) {
countTime()
Toast.success(message)
}
}
return {
...toRefs(state),
onGetCode
}
}
})
</script>
从新上面代码看没有问题啊,Compostion API 不就是这么用啊,梭哈完毕,可是再想想,如何这个页面只是其中一个逻辑,还有十个逻辑,都内聚在一起,依次继续写在后面,写到后面不就是我们所说的拉面条了吗?
所以可以单独将逻辑拆分到一个文件中
// useVerificationCode.js
import { reactive, toRefs } from "vue";
export default const useVerificationCode = () => {
const state = reactive({
isGetCode: false,
codeText: '获取验证码',
countDown: 60,
phone: ''
})
// 点击后倒计时
const countTime = () => {
state.isGetCode = true
let timer
timer = setInterval(
(function setIntervalFunc() {
if (countDown !== 0) {
state.codeText = `重新发送${countDown.value--}`
} else {
state.isGetCode = false
state.codeText = '获取验证码'
state.countDown = 60
clearInterval(timer)
}
return setIntervalFunc
})(),
1000
)
}
// 获取验证码请求
const onGetCode = async () => {
const { success, message } = await getPhoneCode(encrypt(state.phone))
if (success) {
countTime()
Toast.success(message)
}
}
return {
...toRefs(state)
onGetCode,
}
}
再看看改造后:
// example.vue
<template>
<button @click="onGetCode">{{ codeText }}</button>
</template>
<script lang="ts">
import { defineComponent } from "vue";
// 引入 useVerificationCode.js
import useVerificationCode from "./useVerificationCode.js";
export default defineComponent({
setup(props, ctx) {
// 获取验证码
const { onGetCode, isGetCode, codeText, countDown, phone } = useVerificationCode()
// ...
// ...
return {
onGetCode,
isGetCode,
codeText,
countDown,
phone
}
}
})
</script>
这样是不是清爽许多了,以前错误的观点,就是只有复用的逻辑才应该封装到 hook 中,在 官方的给例子 中,并不是强调逻辑复用,而是逻辑关注点分离,到这里相信大家都明白该怎么写了。但是在简单逻辑的组件中,过度抽离就没必要了。
总结
目前自己应用 Vue3.0 开发中的小项目中还没有遇到过大坑,面向百度、文档都能轻松解决,赶紧用起来吧,两个字 好使,Vite 编译是真的快~,尤大给力( ̄▽ ̄)。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!