美文网首页VueJS程序员
Vue移动端项目搭建

Vue移动端项目搭建

作者: 简不才 | 来源:发表于2018-09-28 11:46 被阅读619次

    首先新起一个项目

    vue init webpact projectName

    解决适配问题

    引入lib-flexiblepx2rem-loader,打开build文件夹,编辑utils.js

    exports.cssLoaders = function (options) {
      options = options || {}
    
      var cssLoader = {
        loader: 'css-loader',
        options: {
          minimize: process.env.NODE_ENV === 'production',
          sourceMap: options.sourceMap
        }
      }
      const px2remLoader = {
        loader: 'px2rem-loader',
        options: {
          remUnit: 37.5  //1rem=多少像素 这里的设计稿是750px。
        }
      }
      ...
    }
    

    main.js引入

    import 'lib-flexible'
    

    项目里使用设计稿标注的px,编译或者打包后会自动转化为rem

    image

    使用less

    cnpm i less less-save -S

    再编辑webpack.base.conf配置less-loader

     module: {
        rules: [
            {
                test: /\.less$/,
                loader: 'style-loader!css-loader!less-loader',
            },
            ...
        ]
      }
    

    解决移动端点击300ms延迟

    cnpm i fastclick -S

    main.js

    import FastClick from 'fastclick'
    FastClick.attach(document.body)
    

    顶部进度条

    cnpm i nprogress -S

    main.js

    import NProgress from 'nprogress' //引入自定义css是为了覆盖掉默认的进度条的颜色
    import './assets/css/nprogress.css'
    NProgress.configure({
        easing: 'ease',  // 动画方式    
        speed: 500,  // 递增进度条的速度    
        showSpinner: false, // 是否显示加载ico    
        trickleSpeed: 200, // 自动递增间隔    
        minimum: 0.3 // 初始化时的最小百分比
    })
    router.beforeEach((to, from , next) => {
        // 每次切换页面时,调用进度条
        NProgress.start();
        next()
    });
    router.afterEach(() => {  
        // 在即将进入新的页面组件前,关闭掉进度条
        NProgress.done()
    })
    

    nprogress.css

    #nprogress {
        pointer-events: none;
      }
      
      #nprogress .bar {
        background: #FE571B;
      
        position: fixed;
        z-index: 1031;
        top: 0;
        left: 0;
      
        width: 100%;
        height: 2px;
      }
      
      /* Fancy blur effect */
      #nprogress .peg {
        display: block;
        position: absolute;
        right: 0px;
        width: 100px;
        height: 100%;
        box-shadow: 0 0 10px #FE571B, 0 0 5px #FE571B;
        opacity: 1.0;
      
        -webkit-transform: rotate(3deg) translate(0px, -4px);
            -ms-transform: rotate(3deg) translate(0px, -4px);
                transform: rotate(3deg) translate(0px, -4px);
      }
      
      /* Remove these to get rid of the spinner */
      #nprogress .spinner {
        display: block;
        position: fixed;
        z-index: 1031;
        top: 15px;
        right: 15px;
      }
      
      #nprogress .spinner-icon {
        width: 18px;
        height: 18px;
        box-sizing: border-box;
      
        border: solid 2px transparent;
        border-top-color: #FE571B;
        border-left-color: #FE571B;
        border-radius: 50%;
      
        -webkit-animation: nprogress-spinner 400ms linear infinite;
                animation: nprogress-spinner 400ms linear infinite;
      }
      
      .nprogress-custom-parent {
        overflow: hidden;
        position: relative;
      }
      
      .nprogress-custom-parent #nprogress .spinner,
      .nprogress-custom-parent #nprogress .bar {
        position: absolute;
      }
      
      @-webkit-keyframes nprogress-spinner {
        0%   { -webkit-transform: rotate(0deg); }
        100% { -webkit-transform: rotate(360deg); }
      }
      @keyframes nprogress-spinner {
        0%   { transform: rotate(0deg); }
        100% { transform: rotate(360deg); }
      }
    
    image

    封装axios请求

    cnpm i axios -S

    src文件夹下新建http文件夹,并在文件夹内新建api.js

    api.js

    /* eslint-disable */
    import axios from 'axios'
    import router from 'vue-router'
    import Cookies from 'js-cookie'
    /**
    * 定义请求常量
    * TIME_OUT、ERR_OK
    */
    export const TIME_OUT = 5000;    // 请求超时时间
    export const ERR_OK = true;      // 请求成功返回状态,字段和后台统一
    // export const baseUrl = process.env.BASE_URL   // 引入全局url,定义在全局变量process.env中,开发环境为了方便转发,值为空字符串
    // 环境的切换
    console.log('process.env.NODE_ENV:'+process.env.NODE_ENV);
    if (process.env.NODE_ENV == 'development') {    
        axios.defaults.baseURL = 'http://api-campus-stg1.pingan.com:8282';
    } else if (process.env.NODE_ENV == 'production') {    
        axios.defaults.baseURL = 'http://api-campus.pingan.com';
    }
    // 请求超时时间
    axios.defaults.timeout = TIME_OUT
    
    // 封装请求拦截
    axios.interceptors.request.use(
        config => {
            config.headers['Content-Type'] = 'application/json;charset=UTF-8';
            config.headers['accessToken'] = '';
            if(Cookies.getJSON('loginMsg')){
                config.headers['accessToken'] = Cookies.getJSON('loginMsg').token
            }
            return config
        },
        error => {
            return Promise.reject(error)
        }
    )
    // 封装响应拦截,判断token是否过期
    axios.interceptors.response.use(
        response => {
            let {data} = response
            if (data.responseCode === 202) {    // 如果后台返回的错误标识为token过期,则重新登录
                // token过期移除token
                localStorage.removeItem('token')
            // 进行重新登录操作
            } else {
                return Promise.resolve(data)
            }
        },
        error => {
            return Promise.reject(error.response)
            if (error.response.status) { 
                switch (error.response.status) {                
                    // 401: 未登录
                    // 未登录则跳转登录页面,并携带当前页面的路径
                    // 在登录成功后返回当前页面,这一步需要在登录页操作。                
                    case 401:                    
                        router.replace({                        
                            path: '/login',                        
                            query: { 
                                redirect: router.currentRoute.fullPath 
                            }
                        });
                        break;
                    // 403 token过期
                    // 登录过期对用户进行提示
                    // 清除本地token和清空vuex中token对象
                    // 跳转登录页面                
                    case 403:
                        // var toast = Toast.$create({
                        //     txt: '登录过期,请重新登录',
                        //     mask: true
                        // })
                        // toast.show()
                        // 清除token
                        localStorage.removeItem('token');
                        store.commit('loginSuccess', null);
                        // 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面 
                        setTimeout(() => {                        
                            router.replace({                            
                                path: '/login',                            
                                query: { 
                                    redirect: router.currentRoute.fullPath 
                                }                        
                            });                    
                        }, 1000);                    
                        break; 
    
                    // 404请求不存在
                    case 404:
                        // var toast = Toast.$create({
                        //     txt: '网络请求不存在',
                        //     mask: true
                        // })
                        // toast.show()
                        break;
                    // 其他错误,直接抛出错误提示
                    default:
                        // var toast = Toast.$create({
                        //     txt: error.response.data.message,
                        //     mask: true
                        // })
                        // toast.show()
                }
            }
            return Promise.reject(error.response)
      }
    )
    export default axios 
    

    使用方法:

    main.js

    import axios from './http/api'
    Vue.prototype.$http = axios
    

    然后就可以在项目中以 this.$http 来进行请求

    路由懒加载(增加首屏加载速度)

    routes: [
        {
            path: '/',
            name: 'index',
            component:resolve=>require(['@/page/index'],resolve)
        },
        ...
    ]
    

    404页面

    routes: [
        {
            path: '*',
            name: '404',
            meta: {
                title: '404',
                auth:false,//需要登录
            },
            component:resolve=>require(['@/page/error'],resolve)
        }
    ]
    

    路由鉴权

    (1)router/index.js

    给每个路由新增一个auth字段来判断是否需要登录

    routes: [
        {
            path: '/',
            name: 'index',
            meta: {
                title: '首页',
                auth:true,//需要登录
            },
            component:resolve=>require(['@/page/index'],resolve)
        },
    ]
    

    main.js

    router.beforeEach((to, from , next) => {
        /* 路由发生变化修改页面title */
        if (to.meta.title) {
            document.title = to.meta.title
        }
        // 每次切换页面时,调用进度条
        NProgress.start();
        // 对路由进行验证    
        if(to.matched.some( m => m.meta.auth)){
            if(!store.state.user.isLogin) { // 未登陆
                next({path:'/login'})
                NProgress.done()
            }else{
                next()
            }
        }else{
            next()
        }
    });
    router.afterEach(() => {  
        // 在即将进入新的页面组件前,关闭掉进度条
        NProgress.done()
    })
    

    其中store.state.user.isLogin 是vuex里来判断用户登录没,具体实现方式是登录后保存token等用户信息到cookie里(js-cookie插件),并设置过期时间为1天(以实际项目为准)然后后面每次请求会带上token,如果后台返回token过期的codecommit并设置isLoginfalse,回到登录页.(不同项目判断有所不同,具体以项目为准)

    promise兼容ie

    cnpm i es6-promise -S

    main.js

    require("es6-promise").polyfill();
    

    引用vconsole

    移动端项目调式怎么可以少了这个神器.

    static文件夹下新建vconsole.js,再去git上拷贝源码下来,在index.html里引入,vconsole地址:点这里

    index.html

    <script src="./static/vconsole.js"></script>
    <script>
            var vConsole = new VConsole();
    </script>
    

    备注:静态文件放在static还是assets是有区别的,static下的文件不会被webpack处理,任何放在 static/ 中文件需要以绝对路径的形式引用,而assets会被打包到你的项目里,正因为这样,如果vconsole放在assets文件下引用,打包后会找不到路径。一句话总结: static放别人家的,assets放自己写的。

    配置开发环境生成环境接口

    https://www.jianshu.com/p/1fc65f3f4afa

    解决css移动端字母或者文字大小有时会变化的问题

    
    html{
        -ms-text-size-adjust: 100%;
        -webkit-text-size-adjust: 100%;
    }
    

    谷歌下不支持小于12px,当字体小于12px时 会变成12px 这个时候我们设置的rem及=就没有效果了 设置text-size-adjust会解决这个问题 禁用Webkit内核浏览器的文字大小调整功能

    打包后生成很大的.map文件的问题

    config/index.js文件中,设置productionSourceMap: false,就可以不生成.map文件

    查看打包后各文件的体积

    npm run build --report

    相关文章

      网友评论

        本文标题:Vue移动端项目搭建

        本文链接:https://www.haomeiwen.com/subject/drouoftx.html