一、全家桶
vue3+vite
vue-router
pinia 状态管理、pinia-plugin-persist 数据存储
axios 接口请求
postcss-px-to-viewport 移动端适配
vant4 移动端UI库
二、开始
1、创建项目 vue3_h5
yarn create vite vue3_h5 --template vue
2、风格规范
组件名:单文件组件的文件名—单词大写开头 (PascalCase)、横线连接 (kebab-case)。
紧密耦合的组件名:子组件应该以父组件名作为前缀命名。
Prop名:命名使用 camelCase,在模板中使用 kebab-case。
指令缩写,用 :
表示 v-bind:
,用 @
表示 v-on:
。
Props顺序:依次指令、属性和事件。
组件选项顺序:
export default {
name: '',
components: {},
props: {},
data() {},
computed: {},
watch: {},
created() {},
mounted() {},
unmounted() {},
methods: {},
};
三、项目配置
1. postcss-px-to-viewport 移动端适配
功能:将px单位转换为视口单位的 (vw, vh, vmin, vmax) 的 PostCSS 插件。
postcss-px-to-viewport:插件文档。
vite postcss:Vite自身已经集成PostCSS。
配置参考:在Vite中配置方法。
// vite.config.js文件
import postcsspxtoviewport from 'postcss-px-to-viewport'
css: {
postcss: {
plugins: [
postcsspxtoviewport({
unitToConvert: 'px', // 要转化的单位
viewportWidth: 375, // UI设计稿的宽度
unitPrecision: 6, // 转换后的精度,即小数点位数
propList: ['*'], // 指定转换的css属性的单位,*代表全部css属性的单位都进行转换
viewportUnit: 'vw', // 指定需要转换成的视窗单位,默认vw
fontViewportUnit: 'vw', // 指定字体需要转换成的视窗单位,默认vw
selectorBlackList: ['ignore-'], // 指定不转换为视窗单位的类名,
minPixelValue: 1, // 默认值1,小于或等于1px则不进行转换
mediaQuery: true, // 是否在媒体查询的css代码中也进行转换,默认false
replace: true, // 是否转换后直接更换属性值
// exclude: [/node_modules/], // 设置忽略文件,用正则做目录名匹配
exclude: [],
landscape: false // 是否处理横屏情况
})
]
}
},
2. 配置别名、开发服务器配置
// vite.config.js文件
import { resolve } from 'path';
import postcsspxtoviewport from 'postcss-px-to-viewport'
resolve:{
alias:{
'@':resolve('./src')
}
},
server:{
proxy: {
[VITE_API_BASE_URL]: {
target: VITE_BASE_URL,
changeOrigin: true,
rewrite: (path) => {
return path.replace('/api/', '/');
}
}
},
port:8000, // 服务器端口
open: true, // 服务器启动时自动在浏览器中打开
cors: true // 允许跨域
},
3. 安装UI库-vant3
(1)安装UI库vant3 yarn add vant
(2)按需自动导入UI库组件:见步骤【4】。
(3)直接在模板中使用使用 Vant 组件
<van-button type="primary" />
Vant 中unplugin-vue-components 会解析模板并自动注册对应的组件。
说明:Vant中个别组件以函数的形式提供(Toast,Dialog,Notify 和 ImagePreview),使用 unplugin-vue-components 插件来自动引入组件样式,则无法正确识别。
(4)函数形式组件,使用时需要在具体页面引入使用。
引入组件:
import { Toast,Dialog } from 'vant';
-
还需要引入组件的样式。【手动引入、插件】
- A. 需要在公共模块中,手动引入组件的样式。
import 'vant/es/toast/style';// Toast import 'vant/es/dialog/style';// Dialog
- B. 插件vite-plugin-style-import配置自动引入样式:步骤【5】——【不推荐!】
- A. 需要在公共模块中,手动引入组件的样式。
4. unplugin-vue-components 按需自动导入组件
插件文档:https://github.com/antfu/unplugin-vue-components
功能:导入自定义组件、自动导入UI库。
原理:插件会生成一个ui库组件以及指令路径components.d.ts文件。
自动导入参考:https://juejin.cn/post/7012446423367024676#heading-8
安装:yarn add unplugin-vue-components -D
配置:
// vite.config.js文件
import Components from 'unplugin-vue-components/vite'
import {VantResolver} from 'unplugin-vue-components/resolvers'
plugins: [
Components({
// 指定组件位置,默认是src/components
dirs: ['src/components'],
// ui库解析器,也可以自定义
resolvers: [
VantResolver(),
],
// 配置文件生成位置
dts: 'src/components.d.ts'
})
],
5. vite-plugin-style-import 按需自动导入样式
vite-plugin-style-import:https://github.com/vbenjs/vite-plugin-style-import/blob/main/README.zh_CN.md
功能:按需导入组件库样式。
警告:【不推荐!】vant组件样式前后存在覆盖问题。
安装:yarn add vite-plugin-style-import -D
安装consola:用于 Node.js 和浏览器的优雅控制台记录器。
import {createStyleImportPlugin, VantResolve} from 'vite-plugin-style-import'
// vite.config.js文件
createStyleImportPlugin({
resolves: [
VantResolve(),
],
// 自定义规则
libs: [
{
libraryName: 'vant',
esModule: true,
resolveStyle: (name) => {
return `../es/${name}/style/index`
}
}
]
})
6. unplugin-auto-import 自动导入vue3的hooks
功能:支持vue, vue-router, vue-i18n, @vueuse/head, @vueuse/core等自动引入。
表现:不需要引入import { ref, computed } from 'vue'
原理:安装的时候会自动生成auto-imports.d文件(默认是在根目录)。
// vite.config.js文件
import AutoImport from 'unplugin-auto-import/vite';
AutoImport({
dts: 'src/auto-imports.d.ts',
imports: [
'vue',
'pinia',
'vue-router',
],
})
7. pinia状态管理
安装pinia
yarn add pinia
pinia-plugin-persist
:持久化存储插件。参考配置
// store/index.js
import { createPinia } from 'pinia'
import piniaPersist from 'pinia-plugin-persist'
const store = createPinia()
store.use(piniaPersist)
export default store
// main.js
import store from './store'
app.use(store)
8. vue-router路由
安装vue-router
yarn add vue-router
配置
// router/index.js
import { createRouter, createWebHashHistory } from 'vue-router';
const routes = [
{
path: '/',
redirect: '/home',
component: () => import('@/views/home/index.vue'),
},
{
name: 'home',
path: '/home',
component: () => import('@/views/home/index.vue'),
},
{
name: 'detail',
path: '/detail',
component: () => import('@/views/detail/index.vue'),
},
];
const router = createRouter({
history: createWebHashHistory('/'),
routes: routes,
});
export default router;
// main.js
import router from './router/index'
app.use(router)
注意:使用createWebHashHistory模式,在浏览器访问链接才能找到正确路径。
9. axios网络请求
安装axios
npm install axios
配置
import axios from 'axios';
import { showToast,showLoadingToast,closeToast } from 'vant';
// 运行时获取环境变量,使用import.meta.env
const { VITE_API_BASE_URL, VITE_BASE_URL, VITE_NODE_ENV } = import.meta.env
// 创建实例时配置默认值
const instance = axios.create({
baseURL: VITE_NODE_ENV === 'production' VITE_BASE_URL : VITE_API_BASE_URL,
withCredentials: true,
timeout: 5000,
headers:{
'Content-Type': 'application/x-www-form-urlencoded'
}
});
// 添加请求拦截器
instance.interceptors.request.use(
(config) => {
if(config.url.indexOf('&__act=export_string')>=0){
config.headers['Content-Type'] = 'application/json';
}
// 不传递默认开启loading
if (!config.hideLoading) {
showLoadingToast({
forbidClick: true,
});
}
return config;
},
(error) => {
return Promise.reject(error);
},
);
// 添加响应拦截器
instance.interceptors.response.use(
(response) => {
closeToast();
if(response.data.data == undefined){
showToast('接口请求失败,请稍后再试!');
}
const res = response.data.data[0];
if (res.code !== 200) {
showToast(res.errmsg);
return Promise.reject(res.errmsg || 'Error');
} else {
return Promise.resolve(response);
}
},
(error) => {
if (error.message?.includes('timeout')) {
showToast('请求超时!');
}
return Promise.reject(error.message);
},
);
const request = (config)=> {
return new Promise((resolve, reject) => {
instance
.request(config)
.then((res) => resolve(res.data))
.catch((err) => reject(err));
});
};
export default request;
10. unplugin-vue-define-options [网络下载问题,未用到]
功能:组件内显示定义 name 属性,覆盖推导出的文件名称。
参考:https://juejin.cn/post/7142797517355221023
安装
yarn add unplugin-vue-define-options -D
配置 vite
// vite.config.ts
import DefineOptions from 'unplugin-vue-define-options/vite'
import Vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [Vue(), DefineOptions()],
})
3.编写定义
// 默认写法
<script>
export default {
name: "MyComponent"
}
</script>
<script setup lang="ts">
</script>
// 添加插件后
<script setup lang="ts">
defineOptions({
name: "MyComponent"
})
</script>
11. sass作为css预处理
安装
yarn add sass -D
Vite提供了对 .scss 文件的内置支持,没有必要安装特定的 Vite 插件,但必须安装预处理器依赖。对 variables、common.scss作全局引入。
// vite.config.ts
css: {
preprocessorOptions: {
// 引入公用的样式
scss: {
additionalData: `@import "@/styles/common.scss";@import "@/styles/variable.scss";`,
}
}
}
- 通过
<style lang="sass">
自动开启。
12. autoprefixer 浏览器前缀处理插件
安装
yarn add autoprefixer
配置
// vite.config.ts
import autoprefixer from 'autoprefixer'
css: {
postcss: {
plugins: [
autoprefixer({
overrideBrowserslist:[
"Android > 4.1",
"iOS >= 7.1",
'Chrome > 31',
"ff >= 31",
'ie>= 8',
],
grid:true
})
],
}
},
13. 打包文件夹分离
vite默认打包后,js 和 css 是全部混在一起的,将 js 和 css 文件夹分离。
// vite.config.ts
build: {
brotliSize: false,
// 消除打包大小超过500kb警告
chunkSizeWarningLimit: 2000,
// 在生产环境移除console.log
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
},
assetsDir: 'static/assets',
// 静态资源打包到dist下的不同目录
rollupOptions: {
output: {
chunkFileNames: 'static/js/[name]-[hash].js',
entryFileNames: 'static/js/[name]-[hash].js',
assetFileNames: 'static/[ext]/[name]-[hash].[ext]'
}
}
}
注意:组件xx.vue需要使用不同name命名,不可都用xx/index.vue,否则打包固定文件名,会缺少样式。