大家好,欢迎来到IT知识分享网。
背景
vue3的到来在前端社区尤为火爆,vue3的更新在开发,性能以及构建方面都有了较大的更新,也是未来的一个开发趋势。随着vue3的更新,尤雨溪还开发了vite构建工具,在项目开发阶段少了打包阶段,对比vue-cli,速度方面提高了好几倍
技术栈
vite+vuex4+vueRouter4+axios+antDesignVue2
资源
由于当前vue3以及周边资源(vuex,vueRouter)都处于beta阶段,官方文档也还没更新,因此只能通过GitHub,npm文档进行查阅
vue3:(vue3js.cn/docs/zh/gui…)
vuex4:(github.com/vuejs/vuex/…)
vite:(github.com/vitejs/vite)
vueRouter:(github.com/vuejs/vue-r…)
antDesignVue2:(2x.antdv.com/docs/vue/in…)
项目搭建以及基础配置
- 根据vite文档搭建初始项目
$ npm init vite-app <project-name>
$ cd <project-name>
$ npm install
$ npm run dev
IT知识分享网
- 项目结构区别 与vue2不同,vue3的
index.html
不在public
目录中,是在根目录下。vite是运行在浏览器上的,index页面中直接引入了main.js。favicon.ico图标的引入也是直接根目录引入,不是vue的<link rel="icon" href="<%= BASE_URL %>favicon.ico">
方式。 值得注意的是/favicon.ico
路径前面的/
不能省略,build后的结构是favicon.ico和index.html在同层级下
IT知识分享网<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>易工品运营中心</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
3.项目架构和基础配置
常规的项目配置跟vue2一样,根据项目需要配置即可。
vite的配置: 根目录下vite.config.js
,更多配置参考GitHub配置文件源码(github.com/vitejs/vite…)
配置中alias
下src目录的配置必须/@/
这样,带/
符号
import path from 'path'
const { VITE_API_PREFIX, VITE_SERVICE_ORIGIN } = process.env //.env文件的环境变量
module.exports = {
// open: true, //是否自动打开
proxy: { //设置代理
[VITE_API_PREFIX]: {
target: VITE_SERVICE_ORIGIN,
changeOrigin: true
}
},
minify: 'esbuild', //压缩
cssPreprocessOptions: { //css预处理
less: {
modifyVars: {
'primary-color': '#FE5F23',
'link-color': '#1890FFFF',
'info-color': '#1890FFFF'
},
javascriptEnabled: true
}
},
optimizeDeps: { //加载的其他资源
include: ['ant-design-vue/es/locale/zh_CN', 'lodash-es']
},
alias: { //src目录的配置
'/@/': path.resolve(__dirname, 'src')
}
}
代码格式化的配置
根目录下.eslintrc.js
根据需要需要配置规则,后续开发需要接着完善
IT知识分享网module.exports = {
root: true,
env: {
node: true,
},
extends: [
'plugin:vue/recommended',
'eslint:recommended',
'plugin:import/errors',
'plugin:import/warnings',
'@vue/prettier'
],
plugins: ['vue'],
parserOptions: {
parser: 'babel-eslint'
},
rules: {
indent: [1, 2],
eqeqeq: [1, 'always'],
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'import/no-unresolved': 'off',
'vue/valid-v-model': 'off',
'vue/no-deprecated-slot-attribute': 'off',
'vue/no-v-html': 'off',
'vue/no-dupe-keys': 'off',
'vue/require-default-prop': 'off',
'vue/require-prop-types': 'off',
'vue/no-template-key': 'off',
'prettier/prettier': [
'off',
{
semi: false,
singleQuote: true,
endOfLine: 'auto'
}
]
},
overrides: [{
files: ['*.vue'],
rules: {}
}],
settings: {
'import/resolver': { //配置/src目录下的索引
alias: {
map: [
['/@/', 'src']
]
}
}
}
}
.eslintignore
文件
*.sh
node_modules
*.md
*.scss
*.woff
*.ttf
/dist/
vscode配置.vscode
目录下settings.json
{
"editor.formatOnPaste": false,
"editor.formatOnType": false,
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll": true
},
"vetur.format.enable": false,
"cSpell.words": [
"Appstore",
"vuex",
"wangeditor"
]
}
技术方法的使用以及填坑总结
值得说一下的是本次的store和antdesign2,router在使用上有点区别。此外,vue3以及全家桶引入的componentApi 以及按需引入,使得项目打包体积减少许多,也是一种优化。
简单提下本次使用到的setup函数,更多详情请看文档。
setup只会执行一次,主要用在组件只需要初始化一次,在生命周期的created
和beforeCreated
钩子之前,此时还没完全实例化组件,因此在setup中是不能使用this
指向的。
setup函数还能很便捷的获取到props对象,此外还能使用常用的生命周期钩子,computed,watch…
例:
setup({title}){
console.log(title)
}
1.vuex4的使用
vuex4 采用按需引入,下面是引入createStore
创建store,其他vuex之前的api都一样。其中 modules是模块目录
import { createStore } from 'vuex'
import * as modules from './modules'
export const store = createStore({
state() {
return {
showMore: false,
distributionType: 'userRecord'
}
},
mutations: {
//搜索展开更多
showMore(state, newTarget) {
state.showMore = newTarget
}
},
modules
})
在main.js注册
vue3注册应用采用createApp
而不是vue2 直接new Vue()
方式,这样可以保证vue本身的整洁,不污染全局,需要的全局配置都挂载在app上。
import { createApp } from 'vue'
import { store } from './store'
import App from './App.vue'
const app = createApp(App)
app.use(store)
app.mount('#app')
用的比较多的就是vuex4中拿state,可以通过引入useStore
函数获取,这在vue3的setup函数中使用挺方便
import { useStore } from "vuex";
setup() {
let store = useStore();
//展开按钮
const checkShowMore = () => {
store.commit("showMore", false);
};
return {
checkShowMore
};
}
2.vueRoute4的使用
(1)创建引入
由于要做权限管理,因此,routers分成public公共路由和permits权限路由。createRouter
创建对象,createWebHashHistory
设置router为hash模式。 permitModel为权限路由模块
import { createRouter, createWebHashHistory } from 'vue-router'
import { pickUserRoutes } from './pickUserRoutes'
import { store } from '/@/store'
import * as permitModel from './modules'
const routes = {
public: [
{
path: '/',
redirect: () => {
const { menus } = store.state.user
if (menus) {
return menus[0].path
} else {
return '/login'
}
}
},
{
path: '/login',
component: () => import('/@/views/login.vue')
},
{
path: '/403',
component: () => import('/@/views/403.vue')
},
{
path: '/404',
component: () => import('/@/views/404.vue')
}
],
permits: Object.values(permitModel)
}
const newRouter = () => {
return createRouter({
history: createWebHashHistory(),
scrollBehavior: () => ({ top: 0 }),
routes: routes.public
})
}
const router = newRouter()
export { router, routes }
main.js
import { createApp } from 'vue'
import { router } from './router'
import App from './App.vue'
const app = createApp(App)
app.use(store)
app.use(router)
app.mount('#app')
(2)权限路由挂载,重置
4.x在挂载路由,重置路由上跟之前的不一样,旧版的重置路由是通过重置router.matcher
为新的路由对象matcher
。但4.x没有matcher
了。下面是登录时生成动态路由。
提一下的是,4.x没有addRoutes(Arr)
,只有addRoute(route: RouteRecordRaw): () => void
;多了router对象钩子函数isReady(): Promise<void>
,用来处理路由加载完毕后的事情
login() {
this.loading = true
let { mobile, password } = this.form
password = md5(password)
api.login({ mobile, password }).then(({ ret, data}) => {
if (ret === 0) {
const { token, role_name:roleName, allow_module: menusPath } = data
let menus = pickUserRoutes(roleName,routes.permits,menusPath) //过滤出权限路由
this.addMenu(menus) //挂载路由
this.cacheData({ token, menusPath, menus,roleName }) //存储
}
}).finally(() => this.loading = false)
},
addMenu(menus){
if(menus){
menus.forEach(route => {
this.$router.addRoute(route)
})
}
//router挂载完毕后再跳转
this.$router.isReady().then(() => {
this.$router.replace(menus?'/':'/403')
})
}
退出登录,重置路由,我的方式是通过4.x的removeRoute(name: string | symbol): void
logout() {
api.logout().then(({ret})=>{
if(ret === 0){
this.menus.forEach(route=>{
this.$router.removeRoute(route) //清空路由
})
this.clearCache(['token', 'menusPath', 'menus','roleName']) //清掉存储
this.$router.replace('/login')
}
})
}
3.antDesign2的使用(按需以入,主题色)
采用按需引入方式,不一样的是,vue2和antd1.x下按需引入需要配置babel,vue3不需要,直接引入即可。在antd
目录下新建components.js
,组件的注册封装为一个fn,在main.js
使用传入app实例。
与vue2不同,vue3的全局属性挂载在app.config.globalProperties
import 'ant-design-vue/dist/antd.less'
import { Button, message, Modal } from 'ant-design-vue'
export default app => {
app.use(Button)
app.config.globalProperties.$message = message
app.config.globalProperties.$confirm = Modal.confirm
}
main.js
引入/antd/components
import { createApp } from 'vue'
import { router } from './router'
import { store } from './store'
import App from './App.vue'
import 'normalize.css'
import antdComponent from './antd/components'
import '/@/styles/index.less'
const app = createApp(App)
app.use(store)
app.use(router)
antdComponent(app) //引入dantd组件注册
app.mount('#app')
主题色的配置:antd采用modifyVars
配置主题,查阅了vite的GitHub仓库,在vite中配置cssPreprocessOptions
预处理:
module.exports = {
cssPreprocessOptions: {
less: {
modifyVars: {
'primary-color': '#FE5F23',
'link-color': '#1890FFFF',
'info-color': '#1890FFFF'
},
javascriptEnabled: true
}
}
}
table组件扩展:列宽拖拽
由于业务场景需要,但在antDesignVue1.x中,table拖拽依赖vue-draggable-resizable
插件,但该插件暂时不支持vue3,因此借助度娘上的巨人demo,自己扩展了table列宽拖拽
mounted() {
this.setDraggable();
},
updated() {
this.setDraggable();
},
methods:{
setDraggable() {
let tableEle = document.querySelector(".ant-table-bordered");
let colEle = tableEle.getElementsByTagName("table")[0];
//用来存储当前更改宽度的Table Cell,避免快速移动鼠标的问题
var tTD;
var table = colEle;
var flag = 0;
for (let j = 0; j < table.rows[0].cells.length; j++) {
table.rows[0].cells[j].onmousedown = function() {
//记录单元格
tTD = this;
flag = j;
if (event.offsetX > tTD.offsetWidth - 10) {
tTD.mouseDown = true;
tTD.oldX = event.x;
tTD.oldWidth = tTD.offsetWidth;
}
};
table.rows[0].cells[j].onmouseup = function() {
//结束宽度调整
if (tTD === undefined) tTD = this;
tTD.mouseDown = false;
tTD.style.cursor = "default";
};
table.rows[0].cells[j].onmousemove = function() {
//更改鼠标样式
if (event.offsetX > this.offsetWidth - 10)
this.style.cursor = "col-resize";
else this.style.cursor = "default";
//取出暂存的Table Cell
if (tTD === undefined) tTD = this;
//调整宽度
if (tTD.mouseDown !== null && tTD.mouseDown === true) {
tTD.style.cursor = "default";
if (tTD.oldWidth + (event.x - tTD.oldX) > 0)
tTD.width = tTD.oldWidth + (event.x - tTD.oldX);
//调整列宽
tTD.style.width = tTD.width;
tTD.style.cursor = "col-resize";
//调整该列中的每个Cell
while (table.tagName !== "TABLE") table = table.parentElement;
let innerTable = document.getElementsByClassName(
"ant-table-scroll"
)[0];
let inTable = innerTable.getElementsByTagName("table");
for (let i = 0; i < inTable.length; i++) {
let col = inTable[i].getElementsByTagName("colgroup")[0];
let colArr = col.getElementsByTagName("col");
if (tTD.width > 70) {
colArr[flag].style.width = tTD.width + "px";
}
}
}
};
}
}
}
小结
小白鼠一个,初次在项目中使用vue3全家桶,网上关于vue3的资源也是较少,花费了不少时间查阅与学习,还在不断完善中。在尝试中学习,自我提升。欢迎纠正跟补充
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/9340.html