Vue3重构Vue2项目,实现模块化导入,动态加载路由

Vue的响应式原理

Vue2:是把JavaScript对象传入Vue实例作为data选项,Vue将遍历此对象所有的property,并使用Object.defineProperty把这些property全部转为getter/setter。Object.definePropperty是ES5的新特性,不支持IE8以及更低版本的浏览器。

  1. 对于对象无法检测 property的添加或者移除,解决方法有三种: 
1. Vue.set(this.object, key, value)
2. this.$set(this.object, key, value)
3. this.object = Object.assign({}, this.object, {key: value}) // 对象赋值多个属性时
  1. 对于数组不能检测数组的变动,解决方法有:
1. Vue.set(this.arraySet, index, value)
2. this.$set(this.arraySet, index, value)
  1. 异步更新队列,如果基于更新后的操作DOM节点有:
1. Vue.nextTick(() => {
       vm.$el.textContent
   })
2. this.$nextTick(() => {
       this.$el.textContent
   })

 vue3:是通过组件的data函数中返回一个普通的JavaScript对象时,Vue会将该对象包裹在一个带有get和set处理程序的Proxy中,Proxy是ES6的新特性,IE浏览器不支持

多模块导入

开发过程中经常运用到多模块导入:例如Vue Router路由配置文件,Vuex的状态管理文件,以及svg图标的导入,这时候就可以运用传入要搜索的目录、指示是否也应搜索子目录的标志以及匹配文件的正则表达式。

 Vue2+Webpack实现模块导入

以Vuex的应用程序开发的状态管理模式为例在store文件夹下新建index.js文件和modules文件夹下的多个模块,并在index.js文件内导入

import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'

Vue.use(Vuex)

// https://webpack.js.org/guides/dependency-management/#requirecontext
const modulesFiles = require.context('./modules', true, /\.js$/)

// you do not need `import app from './modules/app'`
// it will auto require all vuex module from modules file
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
  // set './app.js' => 'app'
  const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
  const value = modulesFiles(modulePath)
  modules[moduleName] = value.default
  return modules
}, {})

const store = new Vuex.Store({
  modules,
  getters
})

 Vue3+Vite实现模块导入

也是以Vuex的应用程序开发的状态管理模式为例在store文件夹下新建index.js文件和modules文件夹下的多个模块,并在index.js文件内导入,但Vite并没有require.context的方法,所以改用import.meta.globEager方法正则匹配文件名。

import getters from './getters'

const files = import.meta.globEager('./modules/*.js')
let modules = {}
for (const key in files) {
  modules[key.replace(/(\.\/modules\/|\.js)/g, '')] = files[key].default
}

const debug = process.env.NODE_ENV !== 'production'

export default createStore({
  getters,
  modules,
  strict: debug
})

项目开发中需要动态的引入文件且文件较多时可以运用此方法,避免了文件删除新增是还要手动的导入或者删除,以免报错,是代码更加的灵活高级便于维护。

菜单导航动态路由加载

由于Vue的项目重构,Vue Router出了新的版本,接下来通过vue-router 3.0.6版本和vue-router 4.0.14版本两个不同的版本分析动态加载路由配置。

1、首先就是安装vue-router插件。

npm install vue-router@3.0.6 --save
npm install vue-router@4.0.14 --save

2、在src文件夹下新建router文件夹和文件夹下新建index.js文件以及import.js文件 

vue-router 3版本代码实现

index.js文件配置初始化路由

import Vue from 'vue'
import Router from 'vue-router'
import Layout from '@/layout'


Vue.use(Router)
export const constantRoutes = [
  {
    path: '/login',
    component: () => import('@/views/login'),
    hidden: true
  },
  {
    path: '/redirect',
    component: Layout,
    hidden: true,
    children: [{
      path: '/redirect/:path*',
      component: () => import('@/views/redirect/index')
    }]
  },
  {
    path: '',
    redirect: '/home',
    component: Layout,
    hidden: true,
    children: [
      {
        path: 'home',
        name: 'home',
        component: () => import('@/views/home/index'),
        meta: {
          title: '平台介绍',
          icon: 'dashboard',
          affix: true,
          noCache: true
        }
      },
      {
        path: '/404',
        name: 'Page404',
        component: () => import('@/views/404'),
        meta: {
          title: '404'
        },
        hidden: true
      }
    ]
  }

]
const createRouter = () => new Router({
  mode: 'history',
  scrollBehavior: () => ({
    y: 0
  }),
  routes: constantRoutes
})
const router = createRouter()
export function resetRouter() {
  const newRouter = createRouter()
  router.matcher = newRouter.matcher
}

export default router

import.js提取模块配置路由组件

import.js
import Layout from '@/layout'
export default file => {
  return map[file] || null
}

const map = {
  // 风控系统
  'manage': Layout,
  'rules': () => import('@/views/rules/index.vue'),
}

通过后端接口获取配置的路由参数,通过匹配import.js文件下的路由参数动态添加路由加载对应的模块。

import router from './router'
import Layout from '@/layout'
import _import from '@/router/import'

function routerGo(getRouter) {
    getRouter = filterAsyncRouter(getRouter)
    router.addRoutes(getRouter)
}

function filterAsyncRouter(asyncRouterMap) {
    const accessedRouters = asyncRouterMap.filter(item => {
        if (item.component === 'Layout') {
            item.component = Layout
        } else {
            item.component = _import(item.name)
            if (item.name === 'customize') {
                item.hidden = true
            }
            if(item.id) {
                item.path = item.path + '/' + item.id
                // return () => import(`@/view/modules/${view}`);
            }
        }
        if (item.children && item.children.length) {
            item.children = filterAsyncRouter(item.children)
        }
        return true
    })
    return accessedRouters
}

 vue-router 4版本

由于版本的提升旧版本的api有些不适用,所以根据改动的版本开发了一套新的菜单导航动态加载路由,实现代码如下:

import { createRouter, createWebHistory } from "vue-router";
import Layout from '@/layout/index.vue'

export const routes = [
  {
    path: '/login',
    name: 'login',
    hidden: true,
    component: () => import('@/views/login/index.vue')
  },
  {
    path: '/redirect',
    component: Layout,
    hidden: true,
    children: [
      {
        path: '/redirect/:path*',
        hidden: true,
        component: () => import('@/views/redirect/index.vue')
      }
    ]
  },
  {
    path: '',
    redirect: '/home',
    component: Layout,
    hidden: true,
    children: [
      {
        path: '/home',
        name: 'home',
        hidden: true,
        component: () => import('@/views/home/index.vue'),
        meta: {
          title: '平台介绍',
          icon: 'dashboard'
        }
      }
    ]
  }
]

const router = createRouter({
  history: createWebHistory(),
  routes
})
export function resetRouter() {
  const newRouter = createRouter()
  router.matcher = newRouter.matcher
}

export default router

路由的配置也是通过后端接口获取的实现过程代码:

import router from '@/router/index.js'
import _import from '@/router/import.js'
import Layout from '@/layout/index.vue'

var getRouter

async function routerGo() {
  getRouter = await filterAsyncRouter(getRouter)
  for(let item of getRouter) {
    router.addRoute(item)
  }
  const routeName = router.currentRoute.value.fullPath
  router.push(routeName)
}

function filterAsyncRouter(asyncRouterMap) {
  const accessedRouters = asyncRouterMap.filter(item => {
    if (item.component === 'Layout') {
      item.component = Layout
    } else {
      item.component = _import(item.name)
      if (item.name === 'customize') {
        item.hidden = true
      }
      if(item.id) {
        item.path = item.path + '/' + item.id
        // return () => import(`@/view/modules/${view}`);
      }
    }
    if (item.children && item.children.length) {
      item.children = filterAsyncRouter(item.children)
    }
    return true
  })
  return accessedRouters
}

这两个版本的路由配置适用于菜单导航动态路由配置,可以通过后台配置权限控制用户管理菜单,并实现动态加载模块的形式,整体代码清晰有利于迭代维护。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值