Building mobile terminal shelf with perfect function based on vue-cli3.0

Keywords: Javascript Vue axios sass

The main functions of mobile terminal shelf based on vue-cli3.0 include

  1. Web pack packaging extension
  2. Css: sass support, normalize.css, _mixin.scss, _variables.scss
  3. vw, rem layout
  4. Cross domain setup
  5. eslint settings
  6. Introduction of cdn
  7. Routing Design, Logon Interception
  8. axios, api design
  9. vuex state management

Project address: vue-cli3-H5

demo address: https://zhouyupeng.github.io/vuecli3H5/#/

Web pack packaging extension

After vue-cli3. *, the directory structure has been greatly changed. The previous build and config folders have been removed. To achieve the configuration changes, add vue.config.js to the root directory for configuration.

Css: sass support, normalize.css, _mixin.scss, _variables.scss

The css preprocessor used is sass. For css mixin, variables are introduced globally and introduced globally. normalize.css Make HTML element styles highly consistent across browsers
vue.config.js configuration

css: {
        // Whether to use ExtractTextPlugin, a css separation plug-in
        extract: true,
        // Open CSS source maps?
        sourceMap: false,
        // css preset configuration item
        // Enable CSS modules for all css/pre-processor files.
        modules: false,
            sass: {
                data: '@import "style/_mixin.scss";@import "style/_variables.scss";' // Global introduction
            }
        }
    }

vw, rem layout

For mobile adaptation scenarios, the NetEase News Method,
Using vw + rem layout

/**
750px Design draft
    With 1rem=100px as a reference, the width of the html element can be set to width: 7.5rem, so the font-size of html is deviceWidth / 7.5
**/
html {
    font-size: 13.33333vw
}

@media screen and (max-width: 320px) {
    html {
        font-size: 42.667PX;
        font-size: 13.33333vw
    }
}

@media screen and (min-width: 321px) and (max-width:360px) {
    html {
        font-size: 48PX;
        font-size: 13.33333vw
    }
}

@media screen and (min-width: 361px) and (max-width:375px) {
    html {
        font-size: 50PX;
        font-size: 13.33333vw
    }
}

@media screen and (min-width: 376px) and (max-width:393px) {
    html {
        font-size: 52.4PX;
        font-size: 13.33333vw
    }
}

@media screen and (min-width: 394px) and (max-width:412px) {
    html {
        font-size: 54.93PX;
        font-size: 13.33333vw
    }
}

@media screen and (min-width: 413px) and (max-width:414px) {
    html {
        font-size: 55.2PX;
        font-size: 13.33333vw
    }
}

@media screen and (min-width: 415px) and (max-width:480px) {
    html {
        font-size: 64PX;
        font-size: 13.33333vw
    }
}

@media screen and (min-width: 481px) and (max-width:540px) {
    html {
        font-size: 72PX;
        font-size: 13.33333vw
    }
}

@media screen and (min-width: 541px) and (max-width:640px) {
    html {
        font-size: 85.33PX;
        font-size: 13.33333vw
    }
}

@media screen and (min-width: 641px) and (max-width:720px) {
    html {
        font-size: 96PX;
        font-size: 13.33333vw
    }
}

@media screen and (min-width: 721px) and (max-width:768px) {
    html {
        font-size: 102.4PX;
        font-size: 13.33333vw
    }
}

@media screen and (min-width: 769px) {
    html {
        font-size: 102.4PX;
        font-size: 13.33333vw
    }
}

@media screen and (min-width: 769px) {
    html {
        font-size: 102.4PX;

        #app {
            margin: 0 auto
        }
    }


}

vue.config.js configuration

loaderOptions: {
    postcss: {
        // This is the configuration of rem adaptation
        plugins: [
            require('postcss-px2rem')({
                remUnit: 100
            })
        ]
    }
}

Development time cross-domain settings

devServer: {
        open: true, // Whether to open browser after starting service
        host: '127.0.0.1',
        port: 8088, // Service port
        https: false,
        hotOnly: false,
        proxy: 'https://easy-mock.com/'// Setting Agent
    }

After configuration, the baseUrl of axios in the local development environment is written as', that is, an empty string.
Publish online if the front-end code is not placed with the back-end api Homology Next, the background also needs to do cross-domain processing.

eslint standard settings

Used is JavaScript standard Code specifications, a good coding style can help reduce friction between teams, code reading is more refreshing, more readable, don't feel bored, use it well.
This is the full text of the JavaScript standard code specification

Custom configuration, modify in. eslintrc.js. Here is the configuration I gave. Four spaces are indented, the end semicolon is not checked, the single var declaration is closed and self-configurable.

rules: {
    'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    indent: [
        'error',
        4,
        {
            SwitchCase: 1
        }
    ],
    semi: 0, // Do not check the ending semicolon.
    // Mandatory use of single quotation marks
    quotes: ['error', 'single'],
    // Close the space rule between the function name and the following parentheses
    'space-before-function-paren': 0,
    // Close the var declaration, each of which takes up one line of rules.
    'one-var': 0
    }

Introduction of cdn

For vue, vue-router, vuex, axios and other libraries that are not often changed, we let webpack not pack them. By introducing cdn, we can reduce the size of the code and the bandwidth of the server.
Here we use 360 cdn, with a public CDN review article Point me

vue.config.js configuration

const externals = {
    vue: 'Vue',
    'vue-router': 'VueRouter',
    vuex: 'Vuex',
    'mint-ui': 'MINT',
    axios: 'axios'

}

const cdn = {
    // development environment
    dev: {
        css: [
            'https://lib.baomitu.com/mint-ui/2.2.13/style.min.css'
        ],
        js: []
    },
    // production environment
    build: {
        css: [
            'https://lib.baomitu.com/mint-ui/2.2.13/style.min.css'
        ],
        js: [
            'https://lib.baomitu.com/vue/2.6.6/vue.min.js',
            'https://lib.baomitu.com/vue-router/3.0.1/vue-router.min.js',
            'https://lib.baomitu.com/vuex/3.0.1/vuex.min.js',
            'https://lib.baomitu.com/axios/0.18.0/axios.min.js',
            'https://lib.baomitu.com/mint-ui/2.2.13/index.js'
        ]
    }
}

configureWebpack: config => {
        if (isProduction) {
            // Modules in externals are not packaged
            Object.assign(config, {
                externals: externals
            })
       
        } else {
            // Modify the configuration for the development environment.
        }
    },
chainWebpack: config => {
    // Finer-grained modifications are made to the web pack configuration within vue-cli.
    // Add CDN parameters to the HTML Web pack Plugin configuration, as detailed in the public/index.html modification
    config.plugin('html').tap(args => {
        if (process.env.NODE_ENV === 'production') {
            args[0].cdn = cdn.build
        }
        if (process.env.NODE_ENV === 'development') {
            args[0].cdn = cdn.dev
        }
        return args
    })
}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <!-- DNS Pre parse -->
    <link rel="dns-prefetch" href="//lib.baomitu.com" />
    <meta name="viewport"
        content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=0,minimal-ui,viewport-fit=cover" />
    <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
    <!-- Use CDN Accelerated CSS File, configured in vue.config.js lower -->
    <% for (var i in
    htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.css) { %>
    <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="preload" as="style" />
    <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet" />
    <% } %>

    <title>vuedemo</title>
</head>

<body>
    <noscript>
        <strong>We're sorry but vuedemo doesn't work properly without JavaScript
            enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- Use CDN Accelerated JS File, configured in vue.config.js lower -->
    <% for (var i in
    htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js) { %>
    <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
    <% } %>

    <!-- built files will be auto injected -->
</body>

</html>

Routing Design, Logon Interception

const router = new Router({
    routes: [
        {
            path: '/',
            name: 'home',
            component: Home,
            meta: {
                auth: false, // Do you need to log in?
                keepAlive: true // Whether to cache components
            }
        },
        {
            path: '/about',
            name: 'about',
            component: () =>
                import(/* webpackChunkName: "about" */ './views/About.vue'),
            meta: {
                auth: true,
                keepAlive: true
            }
        },
        {
            path: '/login',
            name: 'login',
            component: () =>
                import(/* webpackChunkName: "login" */ './views/login.vue'),
            meta: {
                auth: false,
                keepAlive: true
            }
        },
        {
            path: '*', // Redirection when not matched to routing
            redirect: '/',
            meta: {
                // auth: true,
                // keepAlive: true
            }
        }
    ]
})

// Global Routing Hook Function is Global Effective
router.beforeEach((to, from, next) => {
    let auth = to.meta.auth
    let token = store.getters['login/token'];

    if (auth) { // Need to log in
        if (token) {
            next()
        } else {
            next({
                name: 'login',
                query: {
                    redirect: to.path
                }
            })
        }
    } else {
        next()
    }
})

Set whether to log in and cache the current component in meta.
In router.beforeEac routing hook function, the login authority is judged. Those who are not logged in jump to the login page, and pass the current page to the login page, then jump back to the page after login.

Page caching is handled in app.vue

<keep-alive>
    <router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>

axios, api design

The design of axios is mainly request interceptor, response interceptor, and secondary encapsulation of get and post.

axios.defaults.timeout = 12000 // Request timeout
axios.defaults.baseURL = process.env.VUE_APP_BASE_API

axios.defaults.headers.post['Content-Type'] =
    'application/x-www-form-urlencoded;charset=UTF-8' // Setting of post request header
// axios request interceptor
axios.interceptors.request.use(
    config => {
        // Here you can set the token to be sent
        let token = store.getters['login/token'];
        token && (config.headers.token = token)
        Indicator.open('Data loading')
        return config
    },
    error => {
        return Promise.error(error)
    }
)
// Axios response interceptor
axios.interceptors.response.use(
    response => {
        // If the return status code is 200, the interface request is successful and the data can be obtained normally.
        // Otherwise, throw an error and write the response interceptor in conjunction with the interface state convention returned by your business and the background
        Indicator.close()
        console.log('response', response);
        if (response.status === 200 && response.data.code === 0) {
            return Promise.resolve(response)
        } else {
            Toast({
                message: response.data.msg,
                position: 'middle',
                duration: 2000
            });
            return Promise.reject(response)
        }
    },
    error => {
        Indicator.close()
        const responseCode = error.response.status
        switch (responseCode) {
            // 401: Not logged in
            case 401:
                break
            // 404 request does not exist
            case 404:
                Toast({
                    message: 'Network request does not exist',
                    position: 'middle',
                    duration: 2000
                });
                break
            default:
                Toast({
                    message: error.response.data.message,
                    position: 'middle',
                    duration: 2000
                });
        }
        return Promise.reject(error)
    }
)
/**
 * Encapsulate the get method to correspond to the get request
 * @param {String} url [The url address of the request]
 * @param {Object} params [Parameters carried on request]
 */
function get (url, params = {}) {
    return new Promise((resolve, reject) => {
        axios
            .get(url, {
                params: params
            })
            .then(res => {
                resolve(res.data)
            })
            .catch(err => {
                reject(err.data)
            })
    })
}
/**
 * post Method, corresponding to post request
 * @param {String} url [The url address of the request]
 * @param {Object} params [Parameters carried on request]
 */
function post (url, params) {
    return new Promise((resolve, reject) => {
        axios
            .post(url, qs.stringify(params))
            .then(res => {
                resolve(res.data)
            })
            .catch(err => {
                reject(err.data)
            })
    })
}

To facilitate the management of api paths, all requests are placed in the api folder, such as

import { get, post } from '@/axios/http.js'
function getIndex (params) {
    return get('/mock/5cb48c7ed491cd741c54456f/base/index', params)
}
function login(params) {
    return post('/mock/5cb48c7ed491cd741c54456f/base/login', params)
}
export {
    getIndex,
    login
}

Other

Remove console.log

Install uglify js-webpack-plugin plug-in

 // On-line compression removes console and other information
config.plugins.push(
    new UglifyJsPlugin({
        uglifyOptions: {
            compress: {
                warnings: false,
                drop_console: true,
                drop_debugger: false,
                pure_funcs: ['console.log'] // Remove console
            }
        },
        sourceMap: false,
        parallel: true
    })
)

Setting alias directory alias

Files from different places are often referenced in projects, which can be introduced more easily after configuration.

config.resolve.alias
            .set('assets', '@/assets')
            .set('components', '@/components')
            .set('view', '@/view')
            .set('style', '@/style')
            .set('api', '@/api')
            .set('store', '@/store')

Environmental variables and patterns

In the front-end development process of a product, it will generally go through local development, test script, development self-test, test environment, pre-online environment, and then it can be officially released. There may be differences for each environment, such as server address, interface address, websorket address... Wait. When switching between different environments, we need different configuration parameters, so we can use environment variables and patterns to facilitate our management.

.env                # Loaded in all environments
.env.local          # Loaded in all environments, but ignored by git
.env.[mode]         # Load only in the specified mode
.env.[mode].local   # Loaded only in the specified mode, but ignored by git

The custom variable VUE_APP_starts with two special variables:

  1. NODE_ENV - will be one of "development", "production" or "test". The exact value depends on the mode in which the application runs.
  2. BASE_URL - will match the baseUrl option in vue.config.js, that is, the underlying path to which your application will be deployed.

As we define. env

NODE_ENV = 'development'
BASE_URL = '/'
VUE_APP_BASE_API = ''

.env.production

NODE_ENV = 'production'
BASE_URL = './'
VUE_APP_BASE_API = 'https://easy-mock.com/'

Defined values can be obtained in a project using process.env.VUE_APP_*, such as process.env.VUE_APP_BASE_API.

Global introduction of filter

Write the filters used in many places in one js and reuse the code.

// Filter date format, pass in timestamp, and return different formats according to parameters
const formatTimer = function(val, hours) {
    if (val) {
        var dateTimer = new Date(val * 1000)
        var y = dateTimer.getFullYear()
        var M = dateTimer.getMonth() + 1
        var d = dateTimer.getDate()
        var h = dateTimer.getHours()
        var m = dateTimer.getMinutes()
        M = M >= 10 ? M : '0' + M
        d = d >= 10 ? d : '0' + d
        h = h >= 10 ? h : '0' + h
        m = m >= 10 ? m : '0' + m
        if (hours) {
            return y + '-' + M + '-' + d + ' ' + h + ':' + m
        } else {
            return y + '-' + M + '-' + d
        }
    }
}
export default {
    formatTimer
}

Introduction of main.js

import filters from './filters/index'
// Injection global filter
Object.keys(filters).forEach(item => {
    Vue.filter(item, filters[item])
})

Use

{{1555851774 | formatTimer()}}

Using mock.js in vue

Check out my previous articles Click on me

wepback Visual Resource Analysis Tool Plug-in - -- webpack-bundle-analyzer

It is used to analyze which modules introduce which code and optimize the code purposefully.

In a packaging environment, use the command npm run build --report

if (process.env.npm_config_report) {
    config.plugins.push(new BundleAnalyzerPlugin())
}

Code address

Project address: vue-cli3-H5

demo address: https://zhouyupeng.github.io/vuecli3H5/#/

Posted by justravis on Tue, 23 Apr 2019 09:15:34 -0700