• vue容易遗忘的面试题


    1.vue设置代理

    在vue.config.js文件中做配置

    module.exports={
    
      devServer:{
         proxy:{
           'task':{
              target:'后端接口的服务地址',
               changeOring:true,//设置是否将host更替为代理url,
            secure:false,
    }
    }
    }  
    }

    二、vue项目打包上线

      1.开发环境到生产环境的转变

    项目开发结束之后,首先我们需要通知后端,获取一个线上的路径,之后将之前的开发路径切换为线上路径。

    打开项目中config文件夹里面的 dev.env.js 文件。

    'use strict'
    const merge = require('webpack-merge')
    const prodEnv = require('./prod.env')
    
    module.exports = merge(prodEnv, {
      NODE_ENV: '"development"',
      // BASE_API: '"http://192.168.1.***:3838/"' //开发者路径
      BASE_API: '"http://sdk.********.cn:3838/"'  //线上路径,替换开发者路径
    })

    打开项目中config文件夹里面的prod.env.js 文件,将后端给的线上路径填入。

    'use strict'
    module.exports = {
      NODE_ENV: '"production"',
      BASE_API: '"http://sdk.*********.cn:3838/"' //线上路径
    }

    2.设置统一的请求路径

    犹豫项目打包之后,所有的js,css,图片都会在各自统一的文件夹内,所以,之前的路径需要改掉,单个修改花费时间太长,那么应该怎么做呢。

    打开build文件夹里面的utils.js,根据需求添加,通常会添加两个../。

        if (options.extract) {
          return ExtractTextPlugin.extract({
            use: loaders,
            fallback: 'vue-style-loader',
            publicPath : '../../'  //新添加的内容,路径配置
          })
        } else {
          return ['vue-style-loader'].concat(loaders)
        }
      }
    在某种情况下,会出现html主路径引入不正确的问题,这时候我们需要配置config文件夹内部的index.js文件,修改assetsPublicPath,注意,这里的assetsPublicPath是build生产环境下的assetsPublicPath路径,而不是dev开发环境下的assetsPublicPath。

    这个时候,就可以执行 npm run build 将项目打包,置于你们后端上线了。
    三、vue动态路由
    通常我们在vue项目中都是前端配置好路由的,但在一些项目中我们可能会遇到权限控制,这样我们就涉及到动态路由的设置了。
    动态路由设置一般有两种:
      通常我们在vue项目中都是前端配置好路由的,但在一些项目中我们可能会遇到权限控制,这样我们就涉及到动态路由的设置了。
    (1)简单的角色路由设置:比如只涉及到管理员和普通用户的权限。通常直接在前端进行简单的权限设置
    (2)、复杂的路由权限设置:比如OA系统、多种角色的权限配置。通常需要后端返回路由列表,前端渲染使用
    1.简单的角色路由设置
    (1)配置项目路由权限
    // router.js
    
    import Vue from 'vue'
    import Router from 'vue-router'
    import Layout from '@/layout'
    Vue.use(Router)
    // 权限路由列表
    let asyncRoutes = [
        {
            path: '/permission',
            component: Layout,
            redirect: '/permission/page',
            alwaysShow: true, 
            name: 'Permission',
            meta: {
                title: 'Permission',
                roles: ['admin', 'editor'] // 普通的用户角色
            },
            children: [
                {
                    path: 'page',
                    component: () => import('@/views/permission/page'),
                    name: 'PagePermission',
                    meta: {
                        title: 'Page',
                        roles: ['editor']  //  editor角色的用户才能访问该页面
                    }
                },
                {
                    path: 'role',
                    component: () => import('@/views/permission/role'),
                    name: 'RolePermission',
                    meta: {
                        title: 'Role',
                        roles: ['admin']    //  admin角色的用户才能访问该页面
                    }
                }
            ]
        },
     
    ]
    // 静态路由
    let defaultRouter = [{
        path: '/404',
        name: '404',
        component: () => import('@/views/404'),
         meta: {
            title: '404'
        }
    }]
    let router = new Router({
        mode: 'history',
        scrollBehavior: () => ({ y: 0 }),
        routes: defaultRouter
    })
    export default router

    (2)新建一个公共的asyncRouter.js文件

    // asyncRouter.js
    //判断当前角色是否有访问权限
    function hasPermission(roles, route) {
      if (route.meta && route.meta.roles) {
        return roles.some(role => route.meta.roles.includes(role))
      } else {
        return true
      }
    }
    // 递归过滤异步路由表,筛选角色权限路由
    export function filterAsyncRoutes(routes, roles) {
      const res = [];
      routes.forEach(route => {
        const tmp = { ...route }
        if (hasPermission(roles, tmp)) {
          if (tmp.children) {
            tmp.children = filterAsyncRoutes(tmp.children, roles)
          }
          res.push(tmp)
        }
      })
    
      return res
    }

    (3)创建路由守卫:创建公共的permission.js文件,设置路由守卫

    import router from './router'
    import store from './store'
    import NProgress from 'nprogress' // 进度条插件
    import 'nprogress/nprogress.css' // 进度条样式
    import { getToken } from '@/utils/auth' 
    import { filterAsyncRoutes } from '@/utils/asyncRouter.js'
    
    NProgress.configure({ showSpinner: false }) // 进度条配置
    
    const whiteList = ['/login'] 
    
    router.beforeEach(async (to, from, next) => {
        // 进度条开始
        NProgress.start()
         // 获取路由 meta 中的title,并设置给页面标题
        document.title = to.meta.title
        // 获取用户登录的token
        const hasToken = getToken()
        // 判断当前用户是否登录
        if (hasToken) {
            if (to.path === '/login') {
                next({ path: '/' })
                NProgress.done()
            } else {
                // 从store中获取用户角色
                const hasRoles = store.getters.roles && store.getters.roles.length > 0  
                if (hasRoles) {
                    next()
                } else {
                    try {
                        // 获取用户角色
                        const roles = await store.state.roles
                        // 通过用户角色,获取到角色路由表
                        const accessRoutes = filterAsyncRoutes(await store.state.routers,roles)
                        // 动态添加路由到router内
                        router.addRoutes(accessRoutes)
                        next({ ...to, replace: true })
                    } catch (error) {
                        // 清除用户登录信息后,回跳到登录页去
                        next(`/login?redirect=${to.path}`)
                        NProgress.done()
                    }
                }
            }
        } else {
            // 用户未登录
            if (whiteList.indexOf(to.path) !== -1) {
                // 需要跳转的路由是否是whiteList中的路由,若是,则直接条状
                next()
            } else {
                // 需要跳转的路由不是whiteList中的路由,直接跳转到登录页
                next(`/login?redirect=${to.path}`)
                // 结束精度条
                NProgress.done()
            }
        }
    })
    
    router.afterEach(() => {
        // 结束精度条
        NProgress.done()
    })
    (4)在main.js中引入permission.js文件
    (5)在login登录的时候将roles存储到store中

    2、复杂的 路由权限设置(后端动态返回路由数据)

    (1)配置项目路由文件,该文件中没有路由,或者存在一部分公共路由,即没有权限的路由

    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: '/404',
            component: () => import('@/views/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

    (2)新建一个公共的asyncRouter.js文件

    // 引入路由文件这种的公共路由
    import { constantRoutes } from '../router';
    // Layout 组件是项目中的主页面,切换路由时,仅切换Layout中的组件
    import Layout from '@/layout';
    export function getAsyncRoutes(routes) {
        const res = []
        // 定义路由中需要的自定名
        const keys = ['path', 'name', 'children', 'redirect', 'meta', 'hidden']
        // 遍历路由数组去重组可用的路由
        routes.forEach(item => {
            const newItem = {};
            if (item.component) {
                // 判断 item.component 是否等于 'Layout',若是则直接替换成引入的 Layout 组件
                if (item.component === 'Layout') {
                    newItem.component = Layout
                } else {
                //  item.component 不等于 'Layout',则说明它是组件路径地址,因此直接替换成路由引入的方法
                    newItem.component = resolve => require([`@/views/${item.component}`],resolve)
                    
                    // 此处用reqiure比较好,import引入变量会有各种莫名的错误
                    // newItem.component = (() => import(`@/views/${item.component}`));
                }
            }
            for (const key in item) {
                if (keys.includes(key)) {
                    newItem[key] = item[key]
                }
            }
            // 若遍历的当前路由存在子路由,需要对子路由进行递归遍历
            if (newItem.children && newItem.children.length) {
                newItem.children = getAsyncRoutes(item.children)
            }
            res.push(newItem)
        })
        // 返回处理好且可用的路由数组
        return res
    }

    (3)创建路由守卫:创建公共的permission.js文件,设置路由守卫

    //  进度条引入设置如上面第一种描述一样
    import router from './router'
    import store from './store'
    import NProgress from 'nprogress' // progress bar
    import 'nprogress/nprogress.css' // progress bar style
    import { getToken } from '@/utils/auth' // get token from cookie
    import { getAsyncRoutes } from '@/utils/asyncRouter'
    
    const whiteList = ['/login'];
    router.beforeEach( async (to, from, next) => {
        NProgress.start()
        document.title = to.meta.title;
        // 获取用户token,用来判断当前用户是否登录
        const hasToken = getToken()
        if (hasToken) {
            if (to.path === '/login') {
                next({ path: '/' })
                NProgress.done()
            } else {
                //异步获取store中的路由
                let route = await store.state.addRoutes;
                const hasRouters = route && route.length>0;
                //判断store中是否有路由,若有,进行下一步
                if ( hasRouters ) {
                    next()
                } else {
                    //store中没有路由,则需要获取获取异步路由,并进行格式化处理
                    try {
                        const accessRoutes = getAsyncRoutes(await store.state.addRoutes );
                        // 动态添加格式化过的路由
                        router.addRoutes(accessRoutes);
                        next({ ...to, replace: true })
                    } catch (error) {
                        // Message.error('出错了')
                        next(`/login?redirect=${to.path}`)
                        NProgress.done()
                    }
                }
            }
        } else {
            if (whiteList.indexOf(to.path) !== -1) {
                next()
            } else {
                next(`/login?redirect=${to.path}`)
                NProgress.done()
            }
        }
    })
    
    router.afterEach(() => {
        NProgress.done()
    })
    (4)在main.js中引入permission.js文件
    (5)在login登录的时候将路由信息存储到store中
    //  登录接口调用后,调用路由接口,后端返回相应用户的路由res.router,我们需要存储到store中,方便其他地方拿取
    this.$store.dispatch("addRoutes", res.router);
    到这里,整个动态路由就可以走通了,但是页面跳转、路由守卫处理是异步的,会存在动态路由添加后跳转的是空白页面,这是因为路由在执行next()时,router里面的数据还不存在,此时,你可以通过window.location.reload()来刷新路由
    后端返回的路由格式:
    routerList = [
      {
            "path": "/other",
            "component": "Layout",
            "redirect": "noRedirect",
            "name": "otherPage",
            "meta": {
                "title": "测试",
            },
            "children": [
                {
                    "path": "a",
                    "component": "file/a",
                    "name": "a",
                    "meta": { "title": "a页面", "noCache": "true" }
                },
                {
                    "path": "b",
                    "component": "file/b",
                    "name": "b",
                    "meta": { "title": "b页面", "noCache": "true" }
                },
            ]
        }
    ]
    注意:vue是单页面应用程序,所以页面一刷新数据部分数据也会跟着丢失,所以我们需要将store中的数据存储到本地,才能保证路由不丢失。关于vue页面刷新保存页面状态,可以查看 vue如何在页面刷新时保留状态信息
  • 相关阅读:
    开不了的窗_____window.open
    IIS项目发布完整流程
    理解MVC模式
    ASP.NET MVC 基础(01)
    C#之线程和并发
    vue时间格式化
    windows 2013 datacenter 安装sql server2008 r2兼容性
    SQL Server DBA十大必备工具使生活轻松
    ORACLE主要的系统表和系统视图
    Oracle中spool命令实现的两种方法比较
  • 原文地址:https://www.cnblogs.com/qiaozhiming123/p/15924363.html
Copyright © 2020-2023  润新知