See other chapters:
Use Vue cli 3 to build a project (Part 1)
We have learned a mature scaffold( vue-cli ), the author hopes to quickly build the system (or project) through this scaffold. The best way to start building is to learn from excellent projects and follow the gourd.
Here through research vue-admin-template Project, introduce element UI, axios, mock, iconfont, nprogress, permission control, layout, multi environment (. env), cross domain, vue.config.js one by one, and build our own architecture step by step.
Tip: Vue element admin is an excellent background and front-end solution. It shares some components or experiences that you usually use. Vue admin template is a simple version of it.
Note: due to the long length, it is decided to split the text into two parts
Template project - Vue admin template
The Vue admin template is developed based on the Vue cli webpack template and introduces the following dependencies:
- Element UI is hungry? vue pc UI framework
- axios is a popular and easy-to-use request library that supports Promise
- JS cookie is a lightweight JavaScript library to handle cookies
- normalize.css format CSS
- nprogress lightweight global progress bar control
- vuex official status management
- Vue router official route
- iconfont Icon Font
- Permission control
- lint
Tip: Vue cli webpack template:
- This template is the main template of Vue cli verison 2. *
- Vue cli 3 contains all the functionality (and more) provided by this template
- Vue cli 3 is here, and this template is now considered deprecated
Download the project and start:
> git clone https://github.com/PanJiaChen/vue-admin-template.git vue-admin-template > cd vue-admin-template vue-admin-template> npm i vue-admin-template> npm run dev > vue-admin-template@4.4.0 dev > vue-cli-service serve ...
Create project
Our project - myself Vue admin template
Creating projects through Vue cli
// Project defaults are ` [Vue 2] less`, `babel`, `router`, `vuex`, `eslint` $ vue create myself-vue-admin-template
The directory structure is as follows:
myself-vue-admin-template - mode_modules - public - favicon.ico - index.html - src - assets - logo.png - components - HelloWorld.vue - router - index.js - store - index.js - views - Aobut.vue - Home.vue - App.vue - mains.js - .browerslistrc - .editorconfig - .eslintrc.js - .gitignore - babel.config.js - package-lock.json - package.json - README.md
Our project Vs template project
The project Vue admin template has more directories and files than myself Vue admin template, and others are the same:
vue-admin-template + build + mock + src/api + src/icons + src/layout + src/styles + src/utils + src/permission.js + src/settings.js + .env.development + .env.production + .env.staging + .travis.yml + jest.config.js + jsconfig.json + postcss.config.js + README-zh.md + vue.config.js
The @ vue/cli used is 4.x:
// myself-vue-admin-template "devDependencies": { "@vue/cli-plugin-babel": "~4.5.0", "@vue/cli-plugin-eslint": "~4.5.0", "@vue/cli-plugin-router": "~4.5.0", "@vue/cli-plugin-vuex": "~4.5.0", "@vue/cli-service": "~4.5.0",
// vue-admin-template "devDependencies": { "@vue/cli-plugin-babel": "4.4.4", "@vue/cli-plugin-eslint": "4.4.4", "@vue/cli-plugin-unit-jest": "4.4.4", "@vue/cli-service": "4.4.4", "@vue/test-utils": "1.0.0-beta.29",
element-ui
How do template projects use element UI
// package.json "dependencies": { "element-ui": "2.13.2", }
// main.js // ps: irrelevant code not shown import Vue from 'vue' import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' // Internationalization - English import locale from 'element-ui/lib/locale/lang/en' // lang i18n import App from './App' // set ElementUI lang to EN Vue.use(ElementUI, { locale }) // If you want the Chinese version of element UI, declare it as follows // Vue.use(ElementUI) new Vue({ el: '#app', render: h => h(App) })
- The introduction of Element here is complete, and the other is on-demand
- The Element component uses Chinese by default, and English is used here
- The internationalization of element is actually the internationalization of components in element (see the file node_modules / element UI / lib / locale / Lang / EN)
Add element UI
The idea is as follows:
- Complete introduction of element
- No translation is required. Chinese is used by default
- Install the element UI using the plug-in provided by Vue cli
Direct installation via Vue cli
myself-vue-admin-template> vue add vue-cli-plugin-element 📦 Installing vue-cli-plugin-element... ✔ Successfully installed plugin: vue-cli-plugin-element // to configure ? How do you want to import Element? Fully import ? Do you wish to overwrite Element's SCSS variables? No ? Choose the locale you want to load zh-CN ✔ Successfully invoked generator for plugin: vue-cli-plugin-element
Note: you can also use the Vue cli GUI to install the plug-in Vue cli plugin element
Then you can view the code modified by Vue cli through git status:
myself-vue-admin-template> git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: package-lock.json modified: package.json modified: src/App.vue modified: src/main.js Untracked files: (use "git add <file>..." to include in what will be committed) src/plugins/ no changes added to commit (use "git add" and/or "git commit -a")
The core code is the same as that in the template project, except that the introduction of element is encapsulated in the plugins/element.js file.
Start the service, and the page displays:
... if Element is successfully added to this project, you'll see an <el-button> below // {1} ...
We will see an element button under the line ({1}), indicating that the element UI was successfully introduced.
axios
How do template projects use axios
// package.json "dependencies": { "axios": "0.18.1", }
Encapsulate axios:
// src/utils/request.js import axios from 'axios' import { MessageBox, Message } from 'element-ui' // create an axios instance const service = axios.create({ baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url // withCredentials: true, // send cookies when cross-domain requests timeout: 5000 // request timeout }) // request interceptor service.interceptors.request.use( config => { ... }, error => { ... } ) // response interceptor service.interceptors.response.use( response => { const res = response.data // if the custom code is not 20000, it is judged as an error. if (res.code !== 20000) { Message({ message: res.message || 'Error', type: 'error', duration: 5 * 1000 }) // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired; if (res.code === 50008 || res.code === 50012 || res.code === 50014) { // to re-login MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', { confirmButtonText: 'Re-Login', cancelButtonText: 'Cancel', type: 'warning' }).then(() => { ... }) } return Promise.reject(new Error(res.message || 'Error')) } else { return res } }, error => { console.log('err' + error) // for debug Message({ message: error.message, type: 'error', duration: 5 * 1000 }) return Promise.reject(error) } ) export default service
// api/table.js import request from '@/utils/request' export function getList(params) { return request({ url: '/vue-admin-template/table/list', method: 'get', params }) }
// views/table/index.vue <script> import { getList } from '@/api/table' ... </script>
Add axios
Vue cli installation plug-in
myself-vue-admin-template> vue add vue-cli-plugin-axios 📦 Installing vue-cli-plugin-axios... ... ✔ Successfully installed plugin: vue-cli-plugin-axios
\myself-vue-admin-template> git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: package-lock.json modified: package.json modified: src/main.js Untracked files: (use "git add <file>..." to include in what will be committed) src/plugins/axios.js
Among them, the Plugin in axios.js indicates that it has been discarded in vscode, so simply move the information about Axios in the template project
Copy axios in template project
Tip: first restore the code of installing axios from Vue cli
myself-vue-admin-template> npm i -D axios@0.18.1
Create a new request.js (from the template project utils/request, comment out the code related to permissions):
// utils/request.js import axios from 'axios' import { MessageBox, Message } from 'element-ui' // import store from '@/store' // import { getToken } from '@/utils/auth' // create an axios instance const service = axios.create({ baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url // withCredentials: true, // send cookies when cross-domain requests timeout: 5000 // request timeout }) // request interceptor service.interceptors.request.use( config => { // do something before request is sent // if (store.getters.token) { // // let each request carry token // // ['X-Token'] is a custom headers key // // please modify it according to the actual situation // config.headers['X-Token'] = getToken() // } return config }, error => { // do something with request error console.log(error) // for debug return Promise.reject(error) } ) // response interceptor service.interceptors.response.use( /** * If you want to get http information such as headers or status * Please return response => response */ /** * Determine the request status by custom code * Here is just an example * You can also judge the status by HTTP Status Code */ response => { const res = response.data // if the custom code is not 20000, it is judged as an error. if (res.code !== 20000) { Message({ message: res.message || 'Error', type: 'error', duration: 5 * 1000 }) // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired; if (res.code === 50008 || res.code === 50012 || res.code === 50014) { // to re-login MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', { confirmButtonText: 'Re-Login', cancelButtonText: 'Cancel', type: 'warning' }).then(() => { // store.dispatch('user/resetToken').then(() => { // location.reload() // }) }) } return Promise.reject(new Error(res.message || 'Error')) } else { return res } }, error => { console.log('err' + error) // for debug Message({ message: error.message, type: 'error', duration: 5 * 1000 }) return Promise.reject(error) } ) export default service
Tip: VUE_APP_BASE_API, please refer to multi environment - > base in this chapter_ url
Create a new table.js and define a request:
// api/table.js import request from '@/utils/request' export function getList(params) { return request({ url: '/vue-admin-template/table/list', method: 'get', params }) }
Reference api/table.js in About.vue:
// views/About.vue ... <script> import { getList } from '@/api/table' export default { created() { this.fetchData() }, methods: { fetchData() { getList().then(response => { console.log('Load data', response); }) } } } </script>
Tip: the following information may be encountered when saving the code. You can disable eslint loader during production build by configuring lintOnSave
myself-vue-admin-template\src\views\About.vue 7:1 error More than 1 blank line not allowed no-multiple-empty-lines 12:10 error Missing space before function parentheses space-before-function-paren 16:14 error Missing space before function parentheses space-before-function-paren 18:38 error Extra semicolon semi 20:7 error Block must not be padded by blank lines padded-blocks ✖ 5 problems (5 errors, 0 warnings) 5 errors and 0 warnings potentially fixable with the `--fix` option.
// vue.config.js module.exports = { lintOnSave: process.env.NODE_ENV !== 'production' }
Introduce About.vue into App.vue, restart the server, and find that the page (about. Vue) will report 404 error, so next we have to introduce mock.
Tip: please refer to the add mock section of this article.
After adding the mock, start the service. The page will no longer output 404 and other prompts. The console will output the simulated data in the mock. So far, it indicates that both axios and mock have taken effect.
mock
How do template projects use mock
The npm package used here is mockjs. The requests to be intercepted are uniformly placed in the mock directory. Finally, mock is introduced into main.js.
There are about the repair of mock defects and mock-serve.js, which is a little complicated.
Here are some core codes:
// main.js /** * If you don't want to use mock-server * you want to use MockJs for mock api * you can execute: mockXHR() * * Currently MockJs will be used in the production environment, * please remove it before going online ! ! ! */ if (process.env.NODE_ENV === 'production') { const { mockXHR } = require('../mock') mockXHR() }
// mock/index.js const Mock = require('mockjs') const { param2Obj } = require('./utils') const user = require('./user') const table = require('./table') const mocks = [ ...user, ...table ] // for front mock // please use it cautiously, it will redefine XMLHttpRequest, // which will cause many of your third-party libraries to be invalidated(like progress event). function mockXHR() { // mock patch // https://github.com/nuysoft/Mock/issues/300 Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send ... } module.exports = { mocks, mockXHR }
// vue.config.js devServer: { before: require('./mock/mock-server.js') },
// api/table.js import request from '@/utils/request' export function getList(params) { return request({ url: '/vue-admin-template/table/list', method: 'get', params }) }
// views/table/index.vue import { getList } from '@/api/table'
Add mock
The author uses another method to install it directly through Vue cli plug-in:
myself-vue-admin-template> vue add vue-cli-plugin-mock 📦 Installing vue-cli-plugin-mock... ✔ Successfully installed plugin: vue-cli-plugin-mock
The modified documents are:
myself-vue-admin-template> git status modified: package-lock.json modified: package.json Untracked files: (use "git add <file>..." to include in what will be committed) mock/
According to the introduction of Vue click plugin mock in npm, there are two ways to write mock here. The automatically generated code uses writing method 1. In order to be the same as that in the template project, the author changes mock/index.js to writing method 2.
// Writing method I module.exports = { 'GET /api/user': { // obj id: 1, username: 'kenny', sex: 6, }, ... }; // Writing method 2 module.exports = [ { path: '/api/user', handler: (req, res) => { return res.json({ username: 'admin', sex: 5 }); }, }, ... ];
mock has been installed and can be used directly. For specific usage, see the section adding axios above.
Tip: mock can be further optimized, just like a template project:
- The mock file is divided into modules and integrated through mock/index.js
- mock works only in the development environment
// vue-admin-template/src/main.js if (process.env.NODE_ENV === 'production') { const { mockXHR } = require('../mock') mockXHR() }
// vue-admin-template/mock/index.js const Mock = require('mockjs') const user = require('./user') const table = require('./table') const mocks = [ ...user, ...table ] module.exports = { mocks, mockXHR }
iconfont
In the past, icons were pictures. Later, Sprite pictures appeared. For example, many small icons were placed in one picture to reduce requests. In later projects, font libraries, such as font awesome and iconfont, are used instead of local images.
The landing page in the template project uses four icons
// login/index.vue <svg-icon icon-class="user"/> <svg-icon icon-class="password" /> <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
Add iconfont
Download from the official website and have a preliminary experience
go iconfont Select two icons on the official website and put them in the shopping cart, then click to download the code. After decompression, double-click to open index.html to tell us how to use it. We choose the third method (Symbol).
Add iconfont to the project
New SvgIcon.vue:
// src/components/SvgIcon.vue <template> <svg class="svg-icon" aria-hidden="true"> <use :xlink:href="iconName"></use> </svg> </template> <script> export default { name: 'icon-svg', props: { iconClass: { type: String, required: true } }, computed: { iconName() { return `#icon-${this.iconClass}` } } } </script> <style> .svg-icon { width: 1em; height: 1em; vertical-align: -0.15em; fill: currentColor; overflow: hidden; } </style>
Put iconfont.js into src/utils folder and modify main.js:
... import './utils/iconfont.js' //Introducing svg components import IconSvg from '@/components/SvgIcon' //Global registration icon svg Vue.component('icon-svg', IconSvg)
Use icon, for example, in About.vue:
<template> <div class="about"> <h1>This is an about page</h1> <icon-svg icon-class="password" /> <icon-svg icon-class="user" /> </div> </template>
reform
iconfont.js is as follows:
!function(e){var t,n,o,c,i,d='<svg><symbol id="icon-password" viewBox="0 0 1024 1024"><path d="M780.8 354.58H66..." ></path></symbol><symbol id="icon-user" viewBox="0 0 1032 1024"><path d="M494.8704..." ></path></symbol></svg>',...
If you need to add a third picture, you have to modify the iconfont.js file. Moreover, it is not intuitive which svg you need to use. It depends on the code.
svg files are directly imported into the template project, and there is no iconfont.js file. There are two related packages:
"devDependencies": { // Create SVG sprites "svg-sprite-loader": "4.1.3", // SVG vector graphics file optimization tool based on Nodejs "svgo": "1.2.2", },
We also change iconfont to this method. First, remove the previous code introduced into iconfont, and then install the plug-in Vue cli plugin SVG sprite through Vue cli:
myself-vue-admin-template> vue add vue-cli-plugin-svg-sprite 📦 Installing vue-cli-plugin-svg-sprite... ... ✔ Successfully installed plugin: vue-cli-plugin-svg-sprite ? Add SVGO-loader to optimize your icons before the sprite is created? Yes 🚀 Invoking generator for vue-cli-plugin-svg-sprite... 📦 Installing additional dependencies...
After the plug-in is successfully installed, we view the changed files:
myself-vue-admin-template> git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: package-lock.json // We learned that three packages were installed: svgo, svgo loader, Vue cli plugin SVG sprite modified: package.json modified: vue.config.js Untracked files: (use "git add <file>..." to include in what will be committed) // svg encapsulated components src/components/SvgIcon.vue
Tip: vue.config.js will add the following content:
module.exports = { // slightly chainWebpack: config => { config.module .rule('svg-sprite') .use('svgo-loader') .loader('svgo-loader') } }
Next, we need to register svg components globally:
// main.js import SvgIcon from '@/components/SvgIcon'// svg component // register globally Vue.component('svg-icon', SvgIcon)
Finally, we have to test whether iconfont works.
First download and save the svg file to the assets/icons directory, and then modify About.vue:
<template> <div class="about"> <h1>This is an about page</h1> <svg-icon name="password" /> <svg-icon name="open" /> </div> </template>
Restart the service, and the page successfully displays two svg images. So far, our iconfont has been successfully introduced.
nprogress
In the template project, if you try to switch, there will be a progress bar at the top of the page, which uses nprogress (the slender progress bar of Ajax'y application. Inspired by Google, YouTube and Medium).
Template item:
"dependencies": { "nprogress": "0.2.0", }
Add nprogress
Since the Vue cli UI cannot find the corresponding plug-in of nprogress, we can only install it honestly through npm:
$ npm i -D nprogress
Next, use nprogress to add the following code to About.vue and restart the service to see the effect:
// About.vue <script> import NProgress from 'nprogress' // progress bar import 'nprogress/nprogress.css' // progress bar style // Turn off the load spinner by setting it to false. NProgress.configure({ showSpinner: false }) // NProgress Configuration export default { created () { // Simply call start() and done() to control the progress bar. NProgress.start(); // You can try calling NProgress.done() directly or not setTimeout(function(){ NProgress.done() }, 10000) }, } </script>
Tip: directly search the keyword NProgress in the template project to find the above code. NProgress.start() and NProgress.done() appear in the permission.js file in the template project and are also in the route.
normalize.css
normalize.css, a modern alternative to CSS Reset
Add normalize.css
$ npm i -D normalize.css
Introduce normalize.css into the entry file
// main.js import 'normalize.css/normalize.css' // A modern alternative to CSS resets
When the service is restarted, the margin of the body will be reset to 0, indicating that it has taken effect.
js-cookie
JS cookie, a simple and lightweight JavaScript API for handling cookies.
How do template projects use js cookies
Relevant codes are as follows:
// package.json "dependencies": { "js-cookie": "2.2.0", },
// src/utils/auth.js import Cookies from 'js-cookie' const TokenKey = 'vue_admin_template_token' export function getToken() { return Cookies.get(TokenKey) } export function setToken(token) { return Cookies.set(TokenKey, token) } export function removeToken() { return Cookies.remove(TokenKey) }
Add JS cookie
$ npm i -D js-cookie
Use the following in About.vue:
// About.vue <script> import Cookies from 'js-cookie' export default { created () { Cookies.set('sex', 'man') alert(Cookies.get('sex')) }, } </script>
Restart the service, and the man page pops up, indicating that the import is successful.
other
npm must use TLS 1.2 or higher
The errors reported by npm i on a certain day are as follows:
npm notice Beginning October 4, 2021, all connections to the npm registry - including for package installation - must use TLS 1.2 or higher. You are currently using plaintext http to connect. Please visit the GitHub blog for more information: https://github.blog/2021-08-23-npm-registry-deprecating-tls-1-0-tls-1-1/
You can view this article: npm registry is deprecating TLS 1.0 and TLS 1.1
Uncaught (in promise) Error: Redirected when going from
Uncaught (in promise) Error: Redirected when going from "/login" to "/" via a navigation guard.
You can view this article: Uncaught (in promise) Error: Redirected when going from
See other chapters: