In my last article, I wrote about the integration of Vue and typescript. I found that many people are interested in the vuE-CLI project, so TODAY I am going to write about how to further improve the vue-CLI3.0 shelf and integrate the front-end shelf with basic functions, including the following features:
- Webpack packages extensions
- CSS: SASS support, normalize.css
- Rem layout
- Route design: lazy loading, pre-check, validity check
- API design
- Request body design – Prevent duplicate submission
- Vuex status management
Webpack packages extensions
The most important feature of VUE-CLI3 is zero configuration. The scaffolding hides webpack-related configuration in @vue-preload-webpack-plugin. The default configuration can meet most application scenarios, and the advantage is that we can save a lot of time to fiddle with configuration. There is a bit of a threshold, so that newcomers can focus more on vUE coding. The disadvantages are also obvious, for want of their own custom configuration, it will be a little more troublesome.
View the detailed configuration of the current WebPack
A detailed list of configurations can be viewed using Vue Inspect
Extend the WebPack configuration
When we want to modify or extend the Webpack configuration item, we can add the vue.config.js file in the root directory
/ / webpack extension
module.exports = {
baseUrl: 'production' === process.env.NODE_ENV ?
'/production-sub-path/' :
'/'.chainWebpack: config= > {
config.module
.rule('images')
.use('url-loader')
.tap(options= > Object.assign(options, { limit: 500 }));
},
devServer: {
open: 'darwin' === process.platform,
/ / host: '0.0.0.0',
port: 8088.https: false.hotOnly: false.// proxy: 'https://api.douban.com' // string | Object
proxy: 'http://localhost:3000' // string | Object
},
lintOnSave: false
};
Copy the code
The official website vue.js development standard tool introduction is very detailed, and there are Chinese versions, very easy to understand,
Sass support
- Write this in the component
<style lang="scss"></style>
SCSS syntax is supported - Import other SCSS files from the component as follows
<style lang="scss">
@import "./assets/style/app";
</style>
Copy the code
- Use custom functions and mixins in components. I have not found a way to reference them globally, so I can only reference them manually in the component files that need to be used, as shown below
<style lang="scss"> @import ".. /assets/style/functions"; @import ".. /assets/style/mixin"; The rem {height: px2rem (p 187.5); // custom function}.mimi {@include clearfix(); </style>Copy the code
- To smooth out the differences between browsers, we need to introduce normalize.css
// app.scss
@import "./node_modules/normalize.css/normalize"; // Reference third-party normalize
@import "custom_normalize"; // Custom normalize
Copy the code
Rem layout
Using REM layout on mobile is a good choice. Since we use SCSS in mobile, we can use functions to simplify our work of double-counting. The design is usually given a 2x image, 750px wide, So we can set the benchmark for the document. The getElementsByTagName (‘ HTML ‘) [0]. Style. FontSize = window. The innerWidth / 10 + ‘px’; Then write a conversion function like this:
// _functions.scss
@function px2rem($px) {
$rem: 75px;
@return ($px/$rem) + rem;
}
Copy the code
We can write it this way when we’re using it
.rem {
height: px2rem(300px); // The width is 300px.
}
Copy the code
Convert to CSS
.rem {
height: 4rem;
}
Copy the code
Routing design
Mainly includes lazy route loading, route pre-check, validity check logic, the following is a simple route I wrote
import Vue from 'vue';
import Router from 'vue-router';
// Route lazy loading
const getComponent = (name: string) = >() = >import(`./views/${name}.vue`);
Vue.use(Router);
const router = new Router({
routes: [{path: '/'.name: 'home'.component: getComponent('home')}, {path: '/about'.name: 'about'.component: getComponent('about'),
meta: {
auth: true}}, {path: The '*'.name: 'not_fount'.component: getComponent('notFount')}});/** * Route pre-check */
router.beforeEach((to, from, next) = > {
// Verify the validity
if (to.meta.auth) {
console.log('into auth');
next();
}
next();
});
export default router;
Copy the code
API design
The new service folder is used to store API scripts. The files are divided according to service modules, for example, one user-related API file and one purchase file. Api. ts is a collection of apis of each module, as shown in the following figure
// service/api.ts
export { userApi } from './user';
export { buyApi } from './buy';
// service/user.ts
export const userApi = {
/** * Get user data */
userInfo: '/node_api/read/userInfo'
};
// service/buy.ts
export const buyApi = {
/** ** buy */
shoping: '/node_api/shop/buy'
};
Copy the code
The purpose of this division is to make the project structure and business structure clear, and to avoid the problem of a single file being too long.
HTTP request secondary encapsulation
I’m using the very popular AXIos for sending HTTP, and I’ve built on that, wrapped it a little bit more simply, and then exposed the Request object for invocation. Secondary packaging is mainly to solve the following problems
-
Simplify parameters, assign default values to some common parameters, simplify external use, make it more general and conducive to troubleshooting problems.
-
Unified processing of returned packets, we usually need to do the same processing for some high-frequency scenarios, such as error codes, not logged in, etc., can be unified processing in the return response interceptor provided by it.
-
To prevent double commits, because sometimes the interface is slow to respond because of the network, because of the backend processing, so the user can click the button repeatedly in a very short period of time, and then make a new request again after the first request is not returned, we can do something in the front interceptor provided by Axios. About preventing repeated requests this east east, I have written in a previous article, the front end to prevent users from repeatedly submitting -js interested partners can see.
According to the above points, the following is the request file I encapsulated, the idea is relatively simple, not to say more
import axios from 'axios';
import qs from 'qs';
const Axios = axios.create({
baseURL: '/',
timeout: 10000,
responseType: 'json',
withCredentials: true,
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'}});const CancelToken = axios.CancelToken;
const requestMap = new Map();
// Request a pre-interceptor
Axios.interceptors.request.use(
config= > {
// Prevent duplicate submissions
const keyString = qs.stringify(Object.assign({}, { url: config.url, method: config.method }, config.data));
if (requestMap.get(keyString)) {
// Cancel the current request
config.cancelToken = new CancelToken((cancel) = > {
cancel('Please slow down a little');
});
}
requestMap.set(keyString, true);
Object.assign(config, { _keyString: keyString });
if (config.method === 'post' || config.method === 'put' || config.method === 'delete') {
/ / the serialization
config.data = qs.stringify(config.data);
}
return config;
},
error= > {
return Promise.reject(error); });// Returns the response interceptor
Axios.interceptors.response.use(
res= > {
/ / reset requestMap
const config: any = res.config;
requestMap.set(config._keyString, false);
if (res.status === 200) {
return res.data;
}
// todo popup prompt etc
console.log(` request error:${res}`);
},
error= > {
return {
code: - 1}; });/** * @description * @param URL * @param data * @param method */
const request = (url: string, data = {}, method = 'post') = > {
return Axios({
method,
url,
data,
params: method.toUpperCase() === 'GET' && data
});
};
export { request };
Copy the code
Vuex status management
Here I divide the file structure according to business modules, as shown below
It is divided into home page module and user module, and each module has its own independent state mutations, etc., and files of each module are introduced in Store. ts, as follows
import Vue from 'vue';
import Vuex from 'vuex';
import index from './indexModule/index';
import user from './userModule/user';
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
user,
index
}
});
Copy the code
Notice that there is a file called store_types.ts, which is mainly used with TS. The file is as follows
export enum UserType {
/** * Module name */
'MODULE_NAME' = 'user'./** ** increment */
'ADD_COUNT' = 'addCount'./** * Computes attributes - gets ten times the value */
'GET_TEM_COUNT' = 'getTenCount'
}
Copy the code
Take a look at the usage in components:
<script lang="ts"> import { UserType } from '@/store/store_types'; import { Component, Prop, Vue, Watch,Emit } from 'vue-property-decorator'; import { Action, Getter, Mutation, namespace, State } from 'vuex-class'; @Component export default class Test extends Vue { @State(state => state[UserType.MODULE_NAME].count) public fff! : number; @Getter(`${UserType.MODULE_NAME}/${UserType.GET_TEM_COUNT}`) public tenCount! : number; @Mutation(`${UserType.MODULE_NAME}/${UserType.ADD_COUNT}`) public addCount! : any; } </script>Copy the code
Although this is a bit convoluted, it has the advantage of being able to make the method and attribute descriptions clear through annotations
summary
The above is designed by me according to the common scenes in my work. I hope it can be helpful to my friends. Welcome to discuss the improper design in the comment area