vue-vueadmin记录

vue-vueadmin记录


相关资料


TODO


vscode 插件

  • Vuetur
  • vue
  • ESLint

chrome 插件

安装完后插件栏有个 vue icon 出现, 按 f12 调出调试工具, 顶栏有个 vue 的选项.


取消 eslint 校验

官方文档 - https://eslint.org/docs/rules/

去掉 缩进校验

参考: https://panjiachen.github.io/vue-element-admin-site/zh/guide/advanced/eslint.html#%E9%85%8D%E7%BD%AE%E9%A1%B9

.eslintrc.js 文件中的 'indent': [2, 2, { 修改为 'indent': [0, 0, {

就可以 4 个空格为缩进

去掉 单引号 双引号 校验

参考: https://eslint.org/docs/rules/quotes

.eslintrc.js 文件中的 'quotes': [2, 'single', 修改为 'quotes': [0, 'single',

去掉 代码结尾 分号 校验

参考:

.eslintrc.js 文件中的 'semi': [2, 'never'], 修改为 'semi': [0, 'never'],

去掉 no use 校验

.eslintrc.js 文件中的文件中的 'no-unused-vars': [2, { 修改为 'no-unused-vars': [0, {

去掉 空行 校验

.eslintrc.js 文件中的文件中的 'no-multiple-empty-lines': [2, { 'max': 1 修改为 'no-multiple-empty-lines': [2, { 'max': 9999

去掉 对象构建 最后一个 逗号 校验

.eslintrc.js 文件中的文件中的 'comma-dangle': [2, 修改为 'comma-dangle': [0,


生命周期


查找调用栈

在 chrome 中按 F12 键, 在 sourcesctrl + shift + F, 查找日志, 然后设置断点.


环境变量配置

参考: https://panjiachen.gitee.io/vue-element-admin-site/zh/guide/essentials/env.html#%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F

  • 配置文件为 .env.xxx

  • 环境变量必须以VUE_APP_为开头。如:VUE_APP_APIVUE_APP_TITLE

    1
    console.log(process.env.VUE_APP_xxxx)
  • 修改配置文件后必须重新 npm run dev 才生效


跨域配置

vue.config.js 文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
proxy: {
// change xxx-api/login => mock/login
// detail: https://cli.vuejs.org/config/#devserver-proxy
// [process.env.VUE_APP_BASE_API]: {
// target: `http://127.0.0.1:${port}/mock`,
// changeOrigin: true,
// pathRewrite: {
// ['^' + process.env.VUE_APP_BASE_API]: ''
// }
// },
'/hello': {
target: `http://127.0.0.1:8001`,
changeOrigin: true
}
},

webpack.config.js


import 别名设置

1
2
3
4
5
6
7
8
configureWebpack: {
name: name,
resolve: {
alias: {
'@': resolve('src') // 这也是为什么 很多地方 import 有个 @
}
}
},

状态存储 Vuex

参考: https://vuex.vuejs.org/zh/guide/state.html

访问数据

通过在根实例中注册 store 选项,该 store 实例会注入到根组件下的所有子组件中,且子组件能通过 this.$store 访问到


Element UI

页面数据使用

ui 使用多语言

参考: https://codeday.me/bug/20190430/1010561.html

main.js 中引入多语言

1
2
3
4
5
6
import locale from 'element-ui/lib/locale/lang/en'

Vue.use(Element, {
locale,
size: Cookies.get('size') || 'medium' // set element-ui default size
})

踩坑

报错: The “MyComponent” component has been registered but not used

没有使用组件命名不正确

1
2
3
4
import MyComponent from './components/MyComponent'

// 使用时的命名必须是 my-component, 不能用驼峰命名, 必须全小写, 用 - 分割. 绑定值也一样
<my-component :arg1="123" :is-show="isShow" :arg3="'hello'" @on-my-notify="onMyNotify666" />
报错: Syntax Error: SyntaxError: Assigning to rvalue

参考: https://blog.csdn.net/u014182411/article/details/80071198

html的模板中 引用的值 如: v-module 绑定的属性并没有在 data 属性中定义

报错: Attribute ‘fileNameTitle’ must be hyphenated

参考: https://blog.csdn.net/qq_35366269/article/details/90644180

  • 原因

    出现该错误的原因是组件的属性fileNameTitle使用了驼峰命名法,导致ESLint 检测出语法错误

  • 解决办法:

    将fileNameTitle改为file-name-title即可

    1
    2
    3
    <my-component :arg1="123" :isShow="isShow" :arg3="'hello'" @onMyNotify="onMyNotify666" />
    <!-- 修改为: -->
    <my-component :arg1="123" :is-show="isShow" :arg3="'hello'" @on-my-notify="onMyNotify666" />

组件

命名方式

传参 props
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
props: {
dialogStatus: { // 变量
required: true,
type: Boolean,
default: false
},
dataArr: { // 数组
required: true,
type: Array,
default: () => []
},
userData: { 对象
required: true,
type: Object,
default: () => {}
},
},

监听 watch
1
2
3
4
5
6
7
8
9
10
11
watch: {
dialogStatus(newVal, oldVal) {
this.isDialogShow = newVal
},
userData: {
immediate: true, // 解决第一次显示页面不生效问题
handler(newVal, oldVal) {
this.singleData = deepClone(newVal)
}
}
},

参考报错: [组件赋值 object 第一次不生效问题](#组件赋值 object 第一次不生效问题)


静态加载

动态加载

异步加载

父组件控制子组件显示隐藏

不能同步一个值


tree

自定义唯一 key

node-key,其值为节点数据中的一个字段名,该字段在整棵树中是唯一的。

半选状态

this.checkStrictly = false 代码动态设置时, 选中子节点时, 父节点才有半选状态


date-picker

日期拾取禁用 > 今天

参考: https://stackoverflow.com/questions/48498629/how-to-set-minimum-and-maximum-date-dynamically-in-element-ui-date-picker

  • 加入 disabledDate 属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    data () {
    return {
    datePickerOptions: {
    disabledDate (date) { // 增加 disabledDate 字段
    return date > new Date()
    }
    }
    }
    }

mock 服务器

使用 json 当做临时数据库

使用 const fs = require('fs') io 本地文件即可

hot reload 忽略 部分文件监听

  1. 修改 mock-server.js 增加忽略文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // watch files, hot reload mock server
    chokidar.watch(mockDir, {
    ignored: /mock-server/,
    ignoreInitial: true
    }).on('all', (event, path) => {

    //修改为
    // watch files, hot reload mock server
    chokidar.watch(mockDir, {
    ignored: [/mock-server/, /fakedb/], // 这样 fakedb 目录下的文件就不会被监听
    ignoreInitial: true
    }).on('all', (event, path) => {
  2. 重启 mock. done

踩坑

在 mock 目录下, 文件变化会导致 hotload 重启服务器

通常在使用 [使用 json 当做临时数据库](#使用 json 当做临时数据库) 是 io 文件后, 回导致重启服务器, 导致服务器 token 被重置, 解决办法: hot reload 忽略 部分文件监听


权限验证


添加路由

一级节点添加子节点

1
2
3
4
5
6
7
8
9
{
path: '/id_check',
component: () => import('@/layout'), // 在 一级节点, 都是 import('@/layout')
children: [
{
path: 'index222',
component: () => import('~/views/id-check/index'),
},
},

非一级 节点下添加 子节点

1
2
3
4
5
6
7
8
9
10
11
12
{
path: '/permission',
component: () => import('@/layout'),
children: [
{
path: 'user',
component: () => import('~/views/id-check/index222'), // 在 非一级节点, import 的 vue 页面必须有 <router-view /> 控件
children: [
{
path: 'index222',
component: () => import('~/views/id-check/index'),
},

index222.vue 的内容, 非一级节点 都可以使用这个模板

1
2
3
4
5
<template>
<div>
<router-view />
</div>
</template>
  • 如果没有 <router-view /> 控件, 那么该节点之下的所有子节点加载的页面都不是对应的页面, 而是加载 ~/views/id-check/index222 这个页面. ( 被这个坑了有点久 )

动态路由

  • 将前端的 路由 丢个后端, 后端鉴权后获取该用户可访问的路由表通过 json 方式发给前段, 前端在转成路由, router.addRoutes(accessRoutes) 的方式动态添加进去.

运行时 惰性加载 import 问题

  • webpack 打包不能再运行时 import 一个变量, 会报错找不到页面: __webpack_require__("xxx", 只能 import 一个常量值, 所以曲线救国的方式是用一个 map 去映射

    1
    2
    3
    4
    5
    6
    7
    8
    const routerMap = {
    'layout': () => import('@/layout'),
    '~/views/permission/page': () => import('~/views/permission/page'),
    '~/views/permission/directive': () => import('~/views/permission/directive')
    }

    item.component = routerMap[item.component] // 正确姿势
    // item.component = () => import(item.component) // 报错, 运行时变量
  • 参考

增加页面

因为 [运行时 惰性加载 import 问题](#运行时 惰性加载 import 问题) 的原因, 所以每次添加页面需要 服务端路由表增加一个 router, 在 客户端 map 映射表增加一个页面映射

服务器下发路由表 component 值问题

下发的路由中的 component 字段不要有 @ 字符, 比如 component: '@/views/excel/select-excel', 用 mock 下发时报错, 换别的语言的服务器应该不会有问题,

vue.config.js 加个别名

1
2
3
4
5
6
7
8
configureWebpack: {
resolve: {
alias: {
'@': resolve('src'),
'~': path.resolve(__dirname, 'src') // 加的别名
}
}
},

就可以这样下发 json : component: '~/views/excel/select-excel'

踩坑

从后台获取路由Map后,前台转route的时候报错

参考: https://github.com/PanJiaChen/vue-element-admin/issues/2381

报错: __webpack_require__("xxx"
1
2
3
vue-router.esm.js:1897 Error: Cannot find module 'function () {
return Promise.resolve().then(function () {
return (0, _interopRequireWildcard2.default)(__webpack_require__("./src/router sync recursive ^.*$")

webpack 打包不能再运行时 import 一个变量, 参考: [运行时 惰性加载 import 问题](#运行时 惰性加载 import 问题)

报错: must be accessed with "$data."

参考: 从后台获取路由Map后,前台转route的时候报错 - https://github.com/PanJiaChen/vue-element-admin/issues/2381

将 服务器下发的路由 转换一下


自定义代理

允许将一个 请求白名单 代理请求到指定的 服务器

  1. 在 环境配置文件 .env.development 增加一个 api 标记和指定的服务器

    1
    VUE_APP_DEBUG_API = '/debug-api'
  2. 暂时不想写


webpack 打包


部署

https://panjiachen.gitee.io/vue-element-admin-site/zh/guide/#%E7%9B%AE%E5%BD%95%E7%BB%93%E6%9E%84

1
2
3
4
5
6
7
8
9
10
11
# clone the project
> git clone git@github.com:PanJiaChen/vue-element-admin.git

# enter the project directory
> cd vue-admin-template

# install dependency
> npm install

# develop
> npm run dev

protobuf 接入

流程

  1. 安装 pb 相关库

    1
    npm install --save protobufjs protobufjs/light
  2. 将 xxx.proto 生成为 js 文件

    1
    npx pbjs -t json-module -w commonjs -o src/proto/proto.js  proto/*.proto
    • 将此命令加入 package.json, 方便以后生成

      1
      2
      3
      4
      5
      "scripts": {
      "serve": "vue-cli-service serve",
      ...
      "proto": "npx pbjs -t json-module -w commonjs -o src/proto/proto.js proto/*.proto"
      },
  3. a


js 语法糖

获取对象中的某个属性

1
2
3
4
5
6
const response = {
data: 111,
name: 222,
}

const { data } = response // 获取 data 字段

多个 then


踩坑

方法调用参数要一直

不一致会导致调用不到方法

请求 400 错误

可能是请求的参数封装成 json 不对

1
2
3
4
5
6
7
8
9
10
request({
url: ENetCmd.GetPermission,
method: 'post',
data: token

// 修改为
request({
url: ENetCmd.GetPermission,
method: 'post',
data: { token: token, arg1: '666' }

报错: TypeError: undefined is not iterable

报错: Error in mounted hook: "TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))

一般是由于 路由 为 undefined, 导致 vue 读不到, 所以登出时重置路由不能设为 undefined, 设为一个空数组就ok

1
2
3
4
5
6
const mutations = {
CLEAN_ROUTES: () => { // 不能置为 undefined, 否则读不到路由会报错
state.addRoutes = [] // addRoutes 这个是会被 router.addRoutes(accessRoutes) 进去的
state.routes = []
}
}

使用 el-image 报错: Require self-closing on Vue.js custom components (el-image)

参考: https://github.com/PanJiaChen/vue-element-admin/issues/2400

这个组件是 2.9.0 之后才有, vue-element-admin 使用的是 2.7.0, 升级依稀版本就ok

直接修改 package.json 中的版本 "element-ui": "2.12.0", 在执行命令: npm i

访问是报错: Invalid Host header

参考: https://blog.csdn.net/guzhao593/article/details/85918869

vue.config.js 文件加入 disableHostCheck: true,

1
2
3
4
5
module.exports = {
devServer: {
disableHostCheck: true, // 加入这个字段
}
}

组件赋值 object 第一次不生效问题

参考: https://blog.csdn.net/qq_37800886/article/details/82220574

解决办法: watch 监听写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
watch: {
userData(newVal, oldVal) {
this.singleData = deepClone(newVal)
}
},

// 修改为
watch: {
userData: {
immediate: true, // 增加这个 immediate 这个属性可以解决 第一次赋值 object 不生效问题
handler(newVal, oldVal) {
this.singleData = deepClone(newVal)
}
}
},

http 请求头 header 上行后变为小写的问题

参考: https://stackoverflow.com/questions/46200756/header-keys-become-lowercase-when-interacting-with-api-react-native

根据 RFC 2616, 应该 大小写不敏感

js map 的 Object.keys 遍历时, number 类型的 key 变为了 string 类型

Number 转换成功 number 类型

1
2
3
4
5
6
7
const permArr = []
Object.keys(this.appPermMap).forEach(key => {
permArr.push({
appId: Number(key), // 这里有个坑,
permissionArr: this.appPermMap[key],
})
})

子节点加载的页面不是对应的页面, 而是父节点的页面

参考: [非一级 节点下添加 子节点](#非一级 节点下添加 子节点)

父节点需要有 <router-view /> 控件