初试vue3+vite+ant-design-vue2.0开发后台项目总结[亲测有效]

初试vue3+vite+ant-design-vue2.0开发后台项目总结[亲测有效]vue3的到来在前端社区尤为火爆,vue3的更新在开发,性能以及构建方面都有了较大的更新,也是未来的一个开发趋势。随着vue3的更新,尤雨溪还开发了vite构建工具,在项目开发阶段少了打包阶段,对比vue-cli,速度方面提高了好几倍 与vue2不同,vue3的index.ht…

大家好,欢迎来到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…)

项目搭建以及基础配置

  1. 根据vite文档搭建初始项目
$ npm init vite-app <project-name>
$ cd <project-name>
$ npm install
$ npm run dev

IT知识分享网

  1. 项目结构区别 与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一样,根据项目需要配置即可。

初试vue3+vite+ant-design-vue2.0开发后台项目总结[亲测有效]

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只会执行一次,主要用在组件只需要初始化一次,在生命周期的createdbeforeCreated钩子之前,此时还没完全实例化组件,因此在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

(0)
上一篇 2023-02-14 15:00
下一篇 2023-02-14 17:00

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信