Правильная поза для разработки системы управления фоном vue

Vue.js
Правильная поза для разработки системы управления фоном vue

адрес проектаvue-admin-webappДобро пожаловать на звезду, вилка

предисловие

Я считаю, что многим людям, как и мне, очень скучно читать документы, когда они новичок в vue.После прочтения vue есть еще vueRouter, vuex, vue-cli, es6 (я не могу научиться...) После прочтения учебник, я не могу начать В реальных проектах я могу только написать несколько простых небольших демонстраций, которые должны отличаться от фактической производственной работы, поэтому я планирую создать систему управления фоном vue с нуля, используя новейший технологический стек. , и углубить мои теоретические знания. , и расширить возможности вашего проекта, поэтому я надеюсь, что эта серия руководств будет полезна для вас при разработке проектов Vue.

1. Основное введение в проект

vue-admin-webappспа-страница управления фоном, основанная наvueа такжеelement-uiДля реализации проверки авторизации при входе в систему, создания динамического маршрута и использования используется новейший стек передовых технологий.easy-mockЧтобы смоделировать данные запроса и реализовать типичный случай бизнес-модели, он может помочь вам быстро создать шаблон системы фонового управления и добавить маршруты в соответствии с фактическими потребностями бизнеса для реализации страниц управления на уровне предприятия.Я считаю, что этот проект определенно поможет вам.

- Онлайн-превью — github

- Предварительный просмотр онлайн - gitee(рекомендуется отечественным пользователям)

Текущая версия основана наwebpack 4.0+а такжеvue-cli 3.xсборка версии, требуетсяNode.jsВерсия 8.9 или выше (рекомендуется 8.11.0+), соответствующие знания можно найти на официальном сайте самостоятельно

Функция


- 登录 / 注销
  - 登录仿GeeTest-极验安全策略
  
- 页面
  - 初次进入引导用户
  - sideBar收缩和展开
  - 全屏控制
  
- 侧边栏
  - 根据不同用户权限展示相应的动态左侧菜单
  
- 权限验证
  - 管理员页面
  - 权限设置
  
- 表格操作
  - 涉及平常业务遇到的相关表格操作(参考)
  
- Excel
 - Excel导出
 - Excel导入
 - 多级表头导出
 
- Echarts
 - 滑动显示更多数据
 - 动态切换charts
 - map地图使用
 
- Icons
 - element-icon
 - 阿里iconfont
 

Готов к работе

Прежде чем начать, убедитесь, что у вас локально установлены node, webpack и git. Технологические стеки, задействованные в этом проекте, в основном включаютES6,vue,vuex,vue-router,vue-cli,axios,webpack,element-ui,easyMock, так что лучше заранее ознакомиться с этими знаниями, которые очень помогут вам понять и освоить проект

Структура каталогов

Ниже представлена ​​структура каталогов всего проекта.


├── public                     # 静态资源
│   ├── favicon.ico            # favicon图标
│   └── index.html             # html模板
├── src                        # 源代码
│   ├── api                    # 所有请求
│   ├── assets                 # 图片、字体等静态资源
│   ├── components             # 全局公用组件
│   ├── layout                 # 页面整体布局盒子
│   ├── mixins                 # 全局混入模块
│   ├── plugins                # 全局插件部分
│   ├── router                 # 路由
│   ├── store                  # 全局store管理
│   ├── style                  # 全局样式
│   ├── utils                  # 全局公用方法
│   ├── vendor                 # 公用vendor(excel导入导出)
│   ├── views                  # views所有页面
│   ├── App.vue                # 入口页面
│   ├── main.js                # 入口文件 加载组件 初始化等
├── .borwserslistrc            # 浏览器兼容相关
├── .env.xxx                   # 环境变量配置 
├── .eslintrc.js               # eslint 配置项
├── .gitignore.js              # git忽略文件设置
├── .babelrc.config.js         # babel-loader 配置
├── package.json               # package.json
├── postcss.config.js          # postcss 配置
└── vue.config.js              # vue-cli 配置

Установить

# 克隆项目
git clone git@github.com:gcddblue/vue-admin-webapp.git

# 进入项目目录
cd vue-admin-webapp

# 安装依赖
npm install

# 启动服务
npm run serve

После завершения запуска браузер будет открыт для доступаhttp://localhost:8080, Затем вы можете добавлять или изменять маршруты и писать свой собственный бизнес-код в соответствии с вашими реальными потребностями.

2. Архитектура страницы

За исключением страницы входа, вся архитектура страницы состоит из трех частей.头部 侧边栏 右侧内容页Инкапсулируйте эти три компонента в файл проекта @/layout/index.js и переключите правую сторону, щелкнув левое меню.router-viewЗамена рута, соответствующий файл проекта выглядит следующим образом

3. пакет аксиос

В проекте vue мы обычно выбираем библиотеку axios для взаимодействия запроса с фоном, которая представляет собой http-библиотеку на основе обещаний, которая может работать на стороне браузера, и node.js. В этом проекте в основном реализованы перехват запросов и ответов, получение, инкапсуляция пост-запросов.

Настройка различных сред

Создавая файлы в разных средах в проекте, я создал здесь только среды разработки и продакшн, конечно, вы также можете создавать тестовые среды.env.testфайл в.env.productionНапример:

ENV = 'production'
# base api
VUE_APP_BASE_API = 'https://www.easy-mock.com/mock/5cee951f11690b5261b75566/admin'

покаVUE_APP_Переменные, начинающиеся сwebpack.DefinePluginСтатически встраивается в пакет клиента. Вы можете получить к ним доступ следующим образом в коде вашего приложения, например, я инициализирую axios в @/api/index.js:

const $axios = axios.create({
  timeout: 30000,
  // 基础url,会在请求url中自动添加前置链接
  baseURL: process.env.VUE_APP_BASE_API
})

Создавая папку api, все интерфейсы концентрируются в этой папке, а разные файлы js создаются в соответствии с разными бизнесами, чтобы лучше разделить функции интерфейсов.Код в index.js выглядит следующим образом:

import axios from 'axios'
import Qs from 'qs' // 处理post请求数据格式
import store from '@/store'
import router from '@/router'
import Vue from 'vue'
import { Loading, Message } from 'element-ui' // 引用element-ui的加载和消息提示组件

const $axios = axios.create({
  // 设置超时时间
  timeout: 30000,
  // 基础url,会在请求url中自动添加前置链接
  baseURL: process.env.VUE_APP_BASE_API
})
Vue.prototype.$http = axios // 这里并发请求以便在组件使用this.$http.all(),具体看dashborad页面

// 在全局请求和响应拦截器中添加请求状态
let loading = null

/**
 * 请求拦截器
 * 用于处理请求前添加loading、判断是否已保存token,并在每次请求头部添加token
 */
$axios.interceptors.request.use(
  config => {
    loading = Loading.service({ text: '拼命加载中' })
    const token = store.getters.token
    if (token) {
      config.headers.Authorization = token // 请求头部添加token
    }
    return config
  },
  error => {
    return Promise.reject(error)
  }
)
/**
 * 响应拦截器
 * 用于处理loading状态关闭、请求成功回调、响应错误处理
 */
$axios.interceptors.response.use(
  response => {
    if (loading) {
      loading.close()
    }
    const code = response.status
    // 请求成功返回response.data
    if ((code >= 200 && code < 300) || code === 304) {
      return Promise.resolve(response.data)
    } else {
      return Promise.reject(response)
    }
  },
  error => {
    if (loading) {
      loading.close()
    }
    console.log(error)
    if (error.response) {
      switch (error.response.status) {
        case 401:
          // 返回401 清除token信息并跳转到登陆页面
          store.commit('DEL_TOKEN')
          router.replace({
            path: '/login',
            query: {
              redirect: router.currentRoute.fullPath
            }
          })
          break
        case 404:
          Message.error('网络请求不存在')
          break
        default:
          Message.error(error.response.data.message)
      }
    } else {
      // 请求超时或者网络有问题
      if (error.message.includes('timeout')) {
        Message.error('请求超时!请检查网络是否正常')
      } else {
        Message.error('请求失败,请检查网络是否已连接')
      }
    }
    return Promise.reject(error)
  }
)

// get,post请求方法
export default {
  post(url, data) {
    return $axios({
      method: 'post',
      url,
      data: Qs.stringify(data),
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
      }
    })
  },
  get(url, params) {
    return $axios({
      method: 'get',
      url,
      params
    })
  }
}

Как и выше, вы можете обратиться к моим комментариям. Пакет конфигурации axios является очень важным модулем во всем проекте. На самом деле, в разных проектах пакет axios похож, поэтому, пока вы овладеваете навыком, вы сможет разработать новый проект в следующий раз.Легко завершить упаковку.

4. Проверка разрешений и боковая панель

маршрутизация

Маршрутизация - это ключ к организации проекта Vue. После анализа прототипа проекта следующим шагом будет написание маршрута. В этом проекте он в основном разделен на два маршрута.currencyRoutesа такжеasyncRoutes

currencyRoutes: представляет собой общую маршрутизацию, что означает, что не требуется никакого авторитетного решения, и страницы отображаются пользователями с разными ролями, такими как: целевая страница, 404 и т. д.

asyncRoutes: Представляет динамическую маршрутизацию, которая должна динамически выделяться путем оценки разрешений.Метод оценки разрешений будет представлен далее.

Инструкции по настройке, связанные с маршрутизацией:

/**
 * 路由相关属性说明
 * hidden: 当设置hidden为true时,意思不在sideBars侧边栏中显示
 * mete{
 * title: xxx,  设置sideBars侧边栏名称
 * icon: xxx,  设置ideBars侧边栏图标
 * noCache: true  当设置为true时不缓存该路由页面
 * }
 */

Проверка разрешения динамически добавлять боковую панель

Этот проект обновляет боковую панель с помощью привязки маршрутизации. Все настройки боковой панели выполняются во внешнем интерфейсе. Через интерфейс доступа серверная часть возвращает массив списка, связанный с разрешениями, где значением массива является значение атрибута имени маршрута, а передняя часть рекурсивно проходитasyncRoutesОпределяет, содержит ли список разрешений соответствующее имя маршрута, и, наконец, возвращает объект массива addRoutes, который содержит все страницы маршрута разрешений роли пользователя.

Конкретная реализация состоит в том, чтобы установить глобальную защиту навигации переднего плана в маршрутизации index.js.Конкретный процесс оценки выглядит следующим образом:

// 导航守卫
router.beforeEach(async (to, from, next) => {
  document.title = getTitle(to.meta.title)
  if (to.path === '/login') {
    next()
  } else {
    if (store.getters.token) {
      const hasRoles = store.getters.roles.length > 0
      if (hasRoles) {
        next()
      } else {
        try {
          const { roles } = await store.dispatch('user/_getInfo')
          const addRoutes = await store.dispatch(
            'permission/getAsyncRoutes',
            roles
          )
          router.addRoutes(addRoutes)
          // hack method to ensure that addRoutes is complete
          // set the replace: true, so the navigation will not leave a history record
          next({ ...to, replace: true })
        } catch (error) {
          Message.error(error)
        }
      }
    } else {
      next({
        path: '/login',
        query: {
          redirect: to.fullPath
        }
      })
    }
  }
})

Тут столкнулся с багом при добавлении маршрутов через addRoutes.При переключении ролей добавленные ранее динамические маршруты нельзя удалить, поэтому это переинициализацияrouter.matcherСвойства способа достижения:

const creatRouter = () => {
  return new Router({
    routes: currencyRoutes,
    scrollBehavior() {
      return { x: 0, y: 0 }
    }
  })
}
const router = creatRouter()

// 解决addRoute不能删除动态路由问题
export function resetRouter() {
  const reset = creatRouter()
  router.matcher = reset.matcher
}

каждый раз, когда я выхожуresetRouterметод для инициализации объекта маршрутизатора и удаления ранее добавленного динамически маршрута.

Наконец, рекурсивно пройдите по объекту маршрутизации, чтобы загрузить боковую панель через компонент el-menu элемента element-ui.

5. Имитация данных

Как фронтенд-разработчик, я считаю, что все знают фиктивные данные. Его основная функция — подделывать поддельные данные, чтобы команда могла развиваться параллельно. В этом проекте используются фиктивные данные.easy-mockЧтобы реализовать запрос данных интерфейса, вы можете перейти на официальный сайт, чтобы увидеть простой учебник,easy-mockЕго преимущество в том, что не нужно создавать фиктивную папку в проекте и перехватывать ajax для реализации поддельных запросов данных, таких как традиционные фиктивные данные.Это настоящий запрос API и разрешает любой междоменный запрос.Ниже приведены все интерфейсы этого проект

где все интерфейсы создаются_resполе, чтобы определить, содержит ли запрос поле заголовка Authorzation или нет, чтобы определить, находится ли пользователь в состоянии входа в систему.Конфигурация интерфейса getCardsData следующая:

{
  code: 0,
  data: {
    vistors: '@integer(10000, 100000)',
    message: '@integer(100, 1000)',
    order: '@integer(0, 1000)',
    profit: '@integer(1000, 100000)'
  },
  _res: function({
    _req,
    Mock
  }) {
    if (!_req.header.authorization) {
      return {
        status: 401,
        data: {
          msg: '未授权'
        }
      }
    } else {
      return {
        status: 200
      }
    }
  }
}

Фальшивые данные могут сыграть роль в продвижении проекта при разработке проекта.Вы можете заранее договориться с обслуживающим персоналом и сначала получить поле фальшивых данных, а затем смоделировать свои собственные фальшивые данные, чтобы вы не Не нужно ждать, пока обслуживающий персонал разработает интерфейс, и проект застрянет. Как правило, в проекте создайте.env.developmentа также.env.productionФайл представляет среды разработки и производства, в которых могут быть определены URL-адреса запросов различных интерфейсов среды.

# base api
VUE_APP_BASE_API = 'https://www.easy-mock.com/mock/5cee951f11690b5261b75566/admin'

Инициализируйте в аксиомах пакета, как это

const $axios = axios.create({
  // 设置超时时间
  timeout: 30000,
  // 基础url,会在请求url中自动添加前置链接
  baseURL: process.env.VUE_APP_BASE_API
})

Таким образом, адрес запроса может автоматически переключаться в соответствии с различными средами без изменения каждого интерфейса запроса по отдельности.

6. Войти

Инкапсулируя функцию входа в магазин, при нажатии на вход вызовитеthis.$store.dispatch('user/_login', this.ruleForm)Этот метод действия, когда фоновая проверка интерфейса будет успешной, вернетtokenполе, внешний интерфейс позвонитlocalStroageинтерфейс будет такимtokenСохраните его локально, и сохраняйте этот токен в перехватчике перед каждым запросом в будущемAuthorizationВ этом поле заголовка фону нужно только проверить токен, чтобы узнать информацию о пользователе. Вы можете не только токенизировать студентов,Описание токена Crazy ClickОчень подробно описано, почему http должен добавлять toekn и token.

Здесь я также использовал имитациюgeetestПроверка поведения, проверьте реальную работу, сдвинув изображение. Принцип использует функцию рисования канв h5 для рисования нижнего изображения и изображения ползунка, а затем отслеживает событие mouseMove. Когда разница между координатой y скользящего блока и инициализированное изображение меньше 10, срабатывает функция проверки успеха.

7. Оптимизация и советы

Используйте миксины

Если ваши несколько компонентов используют один или несколько методов, нам не нужно каждый раз вставлять и копировать, разве это не очень мало, мы можем инкапсулировать эти методы в файл js, когда один из моих компонентов должен вызвать, когда этот метод

import aMixin from '@/mixins/a-mixin'
export default {
  name: 'page1',
  mixins: [newsMixin]  //调用mixins属性,将aMixin这个模块的数据及方法等都添加进这个组建吧
}

Правила использования миксинов

Метод Object.freeze

Какая польза от этого метода? Он может заморозить объект, чтобы предотвратить изменение объекта. Каков эффект оптимизации этого метода в проекте Vue? Все знают, что Vue принимаетзахват данныхкаким-то образом обходить объекты данных, превращать эти свойства в методы получения и установки для отслеживания и уведомления об изменениях данных, поэтому, когда вы сталкиваетесь с огромным массивом или объектом и уверены, что данные не будут изменены, вы можете использоватьObject.freeze()способ организовать преобразование Vue этих огромных данных, что может значительно повысить производительность, например:

new Vue({
    data: {
        // vue不会对list里的object做getter、setter绑定
        list: Object.freeze([
            { value: 1 },
            { value: 2 }
        ])
    },
    mounted () {
        // 界面不会有响应
        this.list[0].value = 100;

        // 下面两种做法,界面都会响应
        this.list = [
            { value: 100 },
            { value: 200 }
        ];
        this.list = Object.freeze([
            { value: 100 },
            { value: 200 }
        ]);
    }
})

Автоматически импортировать модули

Когда нам нужно импортировать несколько модулей для компонента или js-файла, общепринятой практикой является импорт каждого модуля, что, очевидно, довольно громоздко.require.contextФункция пригодится.Как пользоваться этой функцией?Официальное введение здесьОн в основном используется для автоматизации импорта модулей.В интерфейсном проекте, если вы столкнетесь с ситуацией, когда многие модули импортируются из папки, вы можете использовать этот API.Он будет проходить указанные файлы в папке, а затем импортировать автоматически, так что вам не нужно каждый раз использовать этот API Явный вызов импорта для импорта модуля

require.contextФункция принимает три параметра:

  1. directory {String} - путь для чтения файла из
  2. useSubdirectories {Boolean} - Обходить ли подкаталоги файлов
  3. gExp {RegExp} - регулярное выражение для соответствия файлу

Такие как

require.context('./test', false, /.test.js$/)
#上面的代码遍历当前目录下的test文件夹的所有.test.js结尾的文件,不遍历子目录

require.contextПосле выполнения функция возвращает функцию, и эта функция содержит три свойства:

  1. разрешить {Function} — принимает запрос параметра, запрос представляет собой относительный путь соответствующего файла в тестовой папке и возвращает относительный путь соответствующего файла относительно всего проекта.
  2. keys {Function} - возвращает массив имен модулей, которые успешно совпадают
  3. id {String} - id среды исполнения, возвращает строку

Мы часто просматриваем массив, возвращаемый ключами, для обработки пути, что довольно удобно, и, наконец,require.contextВозвращаемая функция принимает элемент пути ключей, возвращенных в массив, в качестве параметра и возвращает модуль этого файла пути.

Ниже то, что я используюrequire.contextФункция динамически генерирует объект модуля.

import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
const path = require('path')

Vue.use(Vuex)

const files = require.context('./modules', false, /\.js$/)
let modules = {}
files.keys().forEach(key => {
  let name = path.basename(key, '.js')
  modules[name] = files(key).default || files(key)
})
const store = new Vuex.Store({
  modules,
  getters
})
export default store

cdn импорт

Для некоторых редко изменяемых библиотек модулей, таких как:vue vueRouter vuex echarts element-uiподожди, мы позволимwebpackне упаковывать их, а передатьcdnВведено, чтобы вы могли уменьшить размер кода, уменьшить пропускную способность сервера и кэшировать их через cdn для повышения производительности веб-сайта.

Конкретная реализация заключается в измененииvue.config.js, добавить для объектного модуляexternalsПолная конфигурация выглядит следующим образом:

const cdn = {
	css: [
		// element-ui css
   'https://unpkg.com/element-ui/lib/theme-chalk/index.css'
	],
	js: [
		// vue
    'https://unpkg.com/vue/2.5.22/vue.min.js',
    // element-ui
    'https://unpkg.com/element-ui/lib/index.js',
    // vue
    'https://unpkg.com/vuex/3.1.0/vuex.min.js'
	]
}
# 不打包vue、element-ui、vuex
module.exports = {
	externals: {
		vue: 'Vue',
  	'element-ui':'ELEMENT',
  	vuex: 'Vuex'
  },
  chainWebpack: config => {
  	config.plugin('html')
        .tap(args => {
          args[0].cdn = cdn
          return args
        })
  }
}

Изменить следующийindex.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <% if (process.env.NODE_ENV === 'production') { %>
    	<!-- 引入样式 -->
      <% for(var css of htmlWebpackPlugin.options.cdn.css) { %>
        <link rel="stylesheet" href="<%=css%>">
      <% } %>
      <!-- 引入js -->
      <% for(var js of htmlWebpackPlugin.options.cdn.js) { %>
        <script src="<%=js%>"></script>
      <% } %>      
    <% } %>
    <title>vue-admin-webapp</title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but vue-admin-webapp doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

Хорошо, большое объявление

Многостраничная конфигурация vue cli3

Следите за другими моими статьямиПравильная поза для использования vue cli3 для настройки многостраничных проектов

проект инициализации vue cli3

Следите за другими моими статьямиСоздайте проект с vue cli3 в правильном положении

Суммировать

Я разрабатывал этот проект с перерывами, пока был на работе. Я не написал слишком много технических постов. Мои навыки письма и логической организации все еще довольно плохие. Пожалуйста, простите меня. Сначала я думал, что это должно быть довольно гладко, прежде чем я начал это делать.Я не ожидал, что когда я реализовывал это шаг за шагом, это все еще отличалось от моей первоначальной идеи.В течение этого периода я столкнулся с множеством ошибок , большинство из которых были вызваны невнимательностью к деталям.Хорошая память не так плоха, как плохое письмоВ этом предложении практика — это истина. Делайте больше и исследуйте больше. В конце концов, я бы подумал об использованииuni-appЭтот фреймворк используется для разработки мультиплатформенной (applet, android, ios, h5) мобильной версии системы управления фоном vue, с нетерпением жду...