(I) Project configuration

** Project Configuration policy ** 1. Basic configuration: Specify application context and port number. vue.config.js const port=7070; Module. export={publicPath:"/best-practice",// devServer:{port}} 2. ConfigureWebpack :configureWebpack 1) sets an alias for the component store path. vue.config.js const path=require('path') module.exports={ resolve:{ alias:{ comps:path.join("_dirname",'src/components') Exports = {configureWebpack: {name: "Vue project best practice"}} 2) Set a webpack config for page title, vue.config.js module.exports = {configureWebpack: {name: "Vue project best practice"}}; /public/index.html <title><%= webPackconfig. name %></title> 3) Conditionally configured based on the environment, Vue.config. js // Pass a function to configureWebpack // can be modified directly, Or return a configuration object is used to merge configureWebpack: config = > {config.resolve.alias.com ps = path. Join (_dirname, "SRC/components"); If (process.en.node_env ==='development'){config.name='vue project Best Practice'}else{config.name='vue Best Practice'}} 4)chainWebpack is called chain operation, which can control the internal configuration of webpack more fine-grained. 4.1 Download ICONS and save them in SRC/ICONS/SVG. 4.2 Installation Dependencies: Svg-sprite-loader (NPM I SVG-sprite-loader) 4.3 Modifying rules and Adding Rules, Vue. Config. js // resolve to define an absolute path fetch function const path = require('path'); function resolve(dir) { return path.join(__dirname, Dir)} chainWebpack(config) {// configure SVG rules to exclude SVG files in the ICONS directory // target to exclude SVG rules exclude:['path/to/icon'] Config.module.rule (" SVG ").exclude. Add (resolve(" SRC/ICONS ")) Rule (' ICONS ').test(/\.svg$/).include.add(resolve('./ SRC/ICONS ')).end()  .use('svg-sprite-loader') .loader('svg-sprite-loader') .options({symbolId: 'icon-[name]'})} 4.4 Use icon, App.vue <template> <svg> <use xlink:href="#icon-wx" /> </svg> </template> <script> import '@/icons/svg/wx.svg' </script> # create ICONS /index.js const req = require.context('./ SVG ', false, /\.svg$/) req.keys().map(req); # create SvgIcon components/SvgIcon.vue <template> <svg :class="svgClass" v-on="$listeners"> <use :xlink:href="iconName" /> </svg> </template> <script> export default { name: 'SvgIcon', props: { iconClass: { type: String, required: true }, className: { type: String, default: '' } }, computed: { iconName() { return `#icon-${this.iconClass}` }, svgClass() { if (this.className) { return 'svg-icon ' + this.className } else { return 'svg-icon' } </script> <style scoped> .svg-icon { width: 1em; height: 1em; Vertical - align: 0.15 em. fill: currentColor; overflow: hidden; } </style> 5) Environment variables and modes If you want to do different configurations for multiple environments, you can use the mode provided by VUe-CLI. The default developement, production, test three patterns, is in the form of the corresponding configuration file. Env. Development 5.1 defines a development time of the available configuration items, Foo =bar # VUE_APP_DONG=dong Modify mode option to override mode name, package.json "serve": "vue-cli-service serve --mode dev"Copy the code

(2) Authority

Routes are classified into two types: constantRoutes and asyncRoutes. The former is a default route that can be accessed directly, while the latter requires login, role acquisition, filtering, and dynamic addition to the Router.

1.1) Route definition, router/index.js

2) Create a user Login page, views/ login.vue

3) Route guard: create./ SRC /permission.js and introduce it in main.js

4) Maintain user login status: Routing guard = “User login =” obtain token and cache

Import router from './router' import store from './store' const whiteList = ['/login'] // No token whiteList required router.beforeEach(async (to, from, Next) => {const hasToken = localstorage.getitem ('token') // Logged in if (hasToken) {if (to.path === = '/login') {// If the login page is not necessary, Redirected to the homepage next ('/')} else {const hasRoles = store. The getters. Roles && store. Getters. Roles. The length > 0; If (hasRoles) {// The user has obtained role information. Const {roles} = await store.dispatch('user/getInfo') const {roles} = await store.dispatch('user/getInfo') // Filter out accessible routes based on the current user role const accessRoutes = await store.dispatch('permission/generateRoutes', Router.addroutes (accessRoutes) router.addroutes (accessRoutes) router.addroutes (accessRoutes) to, replace: True})} catch (error) {// error resetToken and re-log await store.dispatch('user/resetToken') next(' /login? Redirect = ${to. The path} `) alert (error | | 'unknown error')}}}} else {/ / not login the if (whiteList. IndexOf (to. The path). == -1) {// next()} else {// Redirect to the login page next(' /login? redirect=${to.path}`) } } })Copy the code

2. Obtain the routing table asynchronously. After logging in, the user can request the accessible routing table from the back end, so as to dynamically generate the accessible page. The operation is the same as before, and there is an additional step to return the back end to the component name in the routing table and the local component mapping step:

Const map = {//xx: require('@/views/xx.vue'). Default: () => import('@/views/xx.vue') // asyncRoutes const asyncRoutes = [{path: '/xx', Component: }] // iterate over asyncRoutes, Function mapComponent(asyncRoutes) {asyncRoutes. ForEach (route => {route.component= map[route.component]; if(route.children) { route.children.map(child => mapComponent(child)) } }) } mapComponent(asyncRoutes)Copy the code

3. Button permission

Some buttons and links on a page sometimes require more fine-grained permission control. In this case, you can encapsulate an instruction V-Permission and put it on the button to be controlled to achieve push-button level permission control

3.1 create instructions, SRC/directives/permission. Js

import store from "@/store"; Inserted (el, binding) {const Permission = {inserted(el, binding) {// Get the value of the instruction: array of roles required by the button const {value:pRoles} = binding; // Retrieve user roles const roles = store.getters && store.getters. Roles; If (pRoles && pRoles instanceof Array && pRoles. Length > 0) {const hasPermission = roles.some(role) {if (pRoles && pRoles instanceof Array && pRoles  => { return pRoles.includes(role); }); // Delete the current dom if (! hasPermission) { el.parentNode && el.parentNode.removeChild(el); }} else {throw new Error(' need to specify button request role array, such as v-Permission ="['admin','editor']" '); }}}; export default permission;Copy the code

3.1 Instructions can only delete the elements of the mounted instruction, not the additional generated elements unrelated to the instruction. This can only be done through V-if.

<template>
<el-tab-pane v-if="checkPermission(['admin'])">
</template>
<script>
export default {
    methods: {
     checkPermission(permissionRoles) {
         return roles.some(role => {
         return permissionRoles.includes(role);
      });
    }
   }
 }
</script>
Copy the code