zoukankan      html  css  js  c++  java
  • 基于vue-cli3.0构建功能完善的移动端架子,主要功能包括

     

    1. webpack 打包扩展
    2. css:sass支持、normalize.css、_mixin.scss、_variables.scss
    3. vw、rem布局
    4. 跨域设置
    5. eslint设置
    6. cdn引入
    7. 路由设计、登录拦截
    8. axios、api 设计
    9. vuex状态管理

    项目地址: vue-cli3-H5

    demo地址: zhouyupeng.github.io/vuecli3H5/#…

    webpack 打包扩展

    vue-cli3.*后目录结构大改,去除了以往的build,config文件夹,要实现配置的改动在根目录下增加vue.config.js进行配置

    css:sass支持、normalize.css、_mixin.scss、_variables.scss

    使用的css预处理器是sass,对于css mixin,变量这里做了全局引入,并且引入normalize.css 使HTML元素样式在跨浏览器上表现得的高度一致性 vue.config.js配置

    css: {
            // 是否使用css分离插件 ExtractTextPlugin
            extract: true,
            // 开启 CSS source maps?
            sourceMap: false,
            // css预设器配置项
            // 启用 CSS modules for all css / pre-processor files.
            modules: false,
                sass: {
                    data: '@import "style/_mixin.scss";@import "style/_variables.scss";' // 全局引入
                }
            }
        }
    复制代码

    vw、rem布局

    对于移动端适配方案使用的是网易新闻的方法, 使用vw + rem布局

    /**
    750px设计稿
        取1rem=100px为参照,那么html元素的宽度就可以设置为 7.5rem,于是html的font-size=deviceWidth / 7.5
    **/
    html {
        font-size: 13.33333vw
    }
    
    @media screen and (max- 320px) {
        html {
            font-size: 42.667PX;
            font-size: 13.33333vw
        }
    }
    
    @media screen and (min- 321px) and (max-360px) {
        html {
            font-size: 48PX;
            font-size: 13.33333vw
        }
    }
    
    @media screen and (min- 361px) and (max-375px) {
        html {
            font-size: 50PX;
            font-size: 13.33333vw
        }
    }
    
    @media screen and (min- 376px) and (max-393px) {
        html {
            font-size: 52.4PX;
            font-size: 13.33333vw
        }
    }
    
    @media screen and (min- 394px) and (max-412px) {
        html {
            font-size: 54.93PX;
            font-size: 13.33333vw
        }
    }
    
    @media screen and (min- 413px) and (max-414px) {
        html {
            font-size: 55.2PX;
            font-size: 13.33333vw
        }
    }
    
    @media screen and (min- 415px) and (max-480px) {
        html {
            font-size: 64PX;
            font-size: 13.33333vw
        }
    }
    
    @media screen and (min- 481px) and (max-540px) {
        html {
            font-size: 72PX;
            font-size: 13.33333vw
        }
    }
    
    @media screen and (min- 541px) and (max-640px) {
        html {
            font-size: 85.33PX;
            font-size: 13.33333vw
        }
    }
    
    @media screen and (min- 641px) and (max-720px) {
        html {
            font-size: 96PX;
            font-size: 13.33333vw
        }
    }
    
    @media screen and (min- 721px) and (max-768px) {
        html {
            font-size: 102.4PX;
            font-size: 13.33333vw
        }
    }
    
    @media screen and (min- 769px) {
        html {
            font-size: 102.4PX;
            font-size: 13.33333vw
        }
    }
    
    @media screen and (min- 769px) {
        html {
            font-size: 102.4PX;
    
            #app {
                margin: 0 auto
            }
        }
    
    
    }
    复制代码

    vue.config.js配置

    loaderOptions: {
        postcss: {
            // 这是rem适配的配置
            plugins: [
                require('postcss-px2rem')({
                    remUnit: 100
                })
            ]
        }
    }
    复制代码

    开发时跨域设置

    devServer: {
            open: true, // 启动服务后是否打开浏览器
            host: '127.0.0.1',
            port: 8088, // 服务端口
            https: false,
            hotOnly: false,
            proxy: 'https://easy-mock.com/' // 设置代理
        }
    复制代码

    配置完后,本地开发环境的axios的baseUrl要写为 '' ,即空字符串。 发布到线上时如果前端代码不是和后台api放在同源下的,后台还需做跨域处理,

    eslint standard设置

    使用的是JavaScript standard 代码规范,一个好的编码风格它可以帮助减少团队之间的摩擦,代码阅读起来也更加清爽,更加可读性,不要觉得烦,用了都说好。 这是 JavaScript standard 代码规范的全文

    自定义配置,在.eslintrc.js里修改,这里是我给出的配置,4个空格缩进,不检查结尾分号,关闭单var 声明,可自行配置

    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, // 不检查结尾分号,
        // 强制使用单引号
        quotes: ['error', 'single'],
        // 关闭函数名与后面括号间必须空格规则
        'space-before-function-paren': 0,
        // 关闭var 声明,每个声明占一行规则。
        'one-var': 0
        }
    复制代码

    cdn引入

    对于 vue、vue-router、vuex、axios等等这些不经常改动的库、我们让webpack不对他们进行打包,通过cdn引入,可以减少代码的大小、也可以减少服务器的带宽 这里使用的是360的cdn,附上一份公共cdn评测文章 点我

    vue.config.js配置

    const externals = {
        vue: 'Vue',
        'vue-router': 'VueRouter',
        vuex: 'Vuex',
        'mint-ui': 'MINT',
        axios: 'axios'
    
    }
    
    const cdn = {
        // 开发环境
        dev: {
            css: [
                'https://lib.baomitu.com/mint-ui/2.2.13/style.min.css'
            ],
            js: []
        },
        // 生产环境
        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) {
                // externals里的模块不打包
                Object.assign(config, {
                    externals: externals
                })
           
            } else {
                // 为开发环境修改配置...
            }
        },
    chainWebpack: config => {
        // 对vue-cli内部的 webpack 配置进行更细粒度的修改。
        // 添加CDN参数到htmlWebpackPlugin配置中, 详见public/index.html 修改
        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预解析 -->
    	<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" />
    	<!-- 使用CDN加速的CSS文件,配置在vue.config.js下 -->
    	<% 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>
    	<!-- 使用CDN加速的JS文件,配置在vue.config.js下 -->
    	<% 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>
    
    复制代码

    路由设计、登录拦截

    const router = new Router({
        routes: [
            {
                path: '/',
                name: 'home',
                component: Home,
                meta: {
                    auth: false, // 是否需要登录
                    keepAlive: true // 是否缓存组件
                }
            },
            {
                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: '*', // 未匹配到路由时重定向
                redirect: '/',
                meta: {
                    // auth: true,
                    // keepAlive: true
                }
            }
        ]
    })
    
    // 全局路由钩子函数 对全局有效
    router.beforeEach((to, from, next) => {
        let auth = to.meta.auth
        let token = store.getters['login/token'];
    
        if (auth) { // 需要登录
            if (token) {
                next()
            } else {
                next({
                    name: 'login',
                    query: {
                        redirect: to.path
                    }
                })
            }
        } else {
            next()
        }
    })
    
    复制代码

    在meta中设置是否需要登录以及是否缓存当前组件, 在router.beforeEac路由钩子函数中对登录权限判断,没有登录的跳到登录页面,并且把当前页面传过去,登录后跳回这个页面。

    对于页面缓存的在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 设计

    对于axios的设计主要是请求拦截器, respone拦截器,以及get,post的二次封装

    axios.defaults.timeout = 12000 // 请求超时时间
    axios.defaults.baseURL = process.env.VUE_APP_BASE_API
    
    axios.defaults.headers.post['Content-Type'] =
        'application/x-www-form-urlencoded;charset=UTF-8' // post请求头的设置
    // axios 请求拦截器
    axios.interceptors.request.use(
        config => {
            // 可在此设置要发送的token
            let token = store.getters['login/token'];
            token && (config.headers.token = token)
            Indicator.open('数据加载中')
            return config
        },
        error => {
            return Promise.error(error)
        }
    )
    // axios respone拦截器
    axios.interceptors.response.use(
        response => {
            // 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据
            // 否则的话抛出错误 结合自身业务和后台返回的接口状态约定写respone拦截器
            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:未登录
                case 401:
                    break
                // 404请求不存在
                case 404:
                    Toast({
                        message: '网络请求不存在',
                        position: 'middle',
                        duration: 2000
                    });
                    break
                default:
                    Toast({
                        message: error.response.data.message,
                        position: 'middle',
                        duration: 2000
                    });
            }
            return Promise.reject(error)
        }
    )
    /**
     * 封装get方法,对应get请求
     * @param {String} url [请求的url地址]
     * @param {Object} params [请求时携带的参数]
     */
    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方法,对应post请求
     * @param {String} url [请求的url地址]
     * @param {Object} params [请求时携带的参数]
     */
    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)
                })
        })
    }
    
    复制代码

    为了方便管理api路径,这里把所以请求都放在了api文件夹下,如

    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
    }
    
    复制代码

    其他

    去除console.log

    装uglifyjs-webpack-plugin插件

     // 上线压缩去除console等信息
    config.plugins.push(
        new UglifyJsPlugin({
            uglifyOptions: {
                compress: {
                    warnings: false,
                    drop_console: true,
                    drop_debugger: false,
                    pure_funcs: ['console.log'] // 移除console
                }
            },
            sourceMap: false,
            parallel: true
        })
    )
    复制代码

    设置alias目录别名

    在项目中经常会引用各个地方的文件,配置后可以更加方便的引入了

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

    环境变量和模式

    在一个产品的前端开发过程中,一般来说会经历本地开发、测试脚本、开发自测、测试环境、预上线环境,然后才能正式的发布。对应每一个环境可能都会有所差异,比如说服务器地址、接口地址、websorket地址…… 等等。在各个环境切换的时候,就需要不同的配置参数,所以就可以用环境变量和模式,来方便我们管理。

    .env                # 在所有的环境中被载入
    .env.local          # 在所有的环境中被载入,但会被 git 忽略
    .env.[mode]         # 只在指定的模式中被载入
    .env.[mode].local   # 只在指定的模式中被载入,但会被 git 忽略
    复制代码

    自定义的变量VUE_APP_开头,两个特殊的变量:

    1. NODE_ENV - 会是 "development"、"production" 或 "test" 中的一个。具体的值取决于应用运行的模式。
    2. BASE_URL - 会和 vue.config.js 中的 baseUrl 选项相符,即你的应用会部署到的基础路径。

    如我们定义的.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/'
    复制代码

    在项目中可以用process.env.VUE_APP_*,如process.env.VUE_APP_BASE_API获取到定义的值

    全局引入filter

    把多个地方用到的过滤器写在一个js里面,复用代码。

    // 过滤日期格式,传入时间戳,根据参数返回不同格式
    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
    }
    
    复制代码

    main.js引入

    import filters from './filters/index'
    // 注入全局过滤器
    Object.keys(filters).forEach(item => {
        Vue.filter(item, filters[item])
    })
    复制代码

    使用

    {{1555851774 | formatTimer()}}
    复制代码

    vue中使用mock.js

    查看我以前写的文章点击我

    wepback的可视化资源分析工具插件---webpack-bundle-analyzer

    用来分析哪些模块引入了哪些代码,进行有目的性的优化代码

    在打包环境中加,使用命令npm run build --report

    if (process.env.npm_config_report) {
        config.plugins.push(new BundleAnalyzerPlugin())
    }
    复制代码
    111

    代码地址

    项目地址: vue-cli3-H5

    demo地址: zhouyupeng.github.io/vuecli3H5/#…


    作者:web_zhou
    链接:https://juejin.im/post/5cbf32bc6fb9a03236393379
    来源:掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 相关阅读:
    CentOS7安装MySql5.7
    环境变量配置
    Spring 注解
    MySQL
    常用命令
    Android Studio & IntelliJ IDEA常见问题与设置
    order by、group by、having的区别
    把WebStrom添加到右键菜单
    解决github访问速度慢的问题
    docker修改时区
  • 原文地址:https://www.cnblogs.com/zhangycun/p/10766325.html
Copyright © 2011-2022 走看看