zoukankan      html  css  js  c++  java
  • 创建一个完整的vue移动端项目配置

    vue的安装及创建一个新项目前一篇文章已经介绍过了,有需要的请看之前的文章

    移动端项目

    一、关于移动端的一些ui框架
    1.Voinc 一个基于 vue.js 和 ionic 样式的 UI 框架(https://wangdahoo.github.io/vonic-documents/#/?id=%E4%BB%8B%E7%BB%8D)
    2.Vux 基于WeUI和Vue(2.x)开发的移动端UI组件库 (https://vux.li/#/?id=%E7%AE%80%E4%BB%8B)
    3. NutUI 京东轻量级移动端Vue组件库(https://nutui.jd.com/#/index)
    4. .Mint UI 由饿了么前端团队推出的 Mint UI (http://mint-ui.github.io/docs/#/zh-cn2)
    5. Vant是有赞前端团队基于有赞统一的规范实现的 Vue 组件库(https://github.com/youzan/zent)
    6. Cube UI 滴滴 WebApp实现的移动端组件库(https://didi.github.io/cube-ui/#/zh-CN/docs/quick-start)

    二、移动端适配

    方案:lib-flexible会自动在html的head中添加一个meta name="viewport"的标签,同时会自动设置html的font-size为屏幕宽度除以10,也就是1rem等于html根节点的font-size。使用postcss-px2rem-exclude自动将css中的px转成rem

    步骤:1.项目中引入lib-flexible npm install lib-flexible --save
    2.在项目的入口main.js文件中引入lib-flexible import ‘lib-flexible/flexible.js’
    3.安装postcss-px2rem-exclude npm install postcss-px2rem-exclude --save
    4.在项目的根目录下找到文件.postcssrc.js,在里面添加如下代码

    "postcss-px2rem-exclude": { 
          remUnit: 75,
          exclude: /node_modules|folder_name/i // 忽略node_modules目录下的文件(引入的第三方ui的样式不会随之改变)
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5.在依赖文件node_modules中找到postcss-px2rem-exclude文件中的lib下的index.js添加以下代码(引入的第三方ui的样式不会随之改变)

    try {
          var flag = options.exclude.includes('/')
          if (flag) {
            var arr = options.exclude.split('/')
            options.exclude = new RegExp(arr[1], arr[2])
          }
        } catch (error) {}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    二.一 安装sass-loader(如果使用到了sass编译再安装,不使用无需安装)

    npm install --save-dev sass-loader  
    //sass-loader依赖于node-sass  ,所以继续安装node-sass
    npm install --save-dev node-sass  
    //注意1.安装node-sass会报错的原因,一般是因为网慢,所以安装node-sass的时候可以使用cnpm安装
    //注意2.sass-loader安装了但是编译还是报错,原因可能是sass-loader版本的问题(8.0.0),在package.json中把sass-loader的版本改成7.3.1,然后删除依赖项,重新安装依赖
    
    • 1
    • 2
    • 3
    • 4
    • 5

    三、给IDE装vue插件(我现在使用的是vscode,就以vscode为例)
    1.在vscode扩展里搜索Vetur
    在这里插入图片描述
    2.安装完成进行配置
    文件–>首选项–>用户代码片段–>点击新建代码片段–取名vue.json 确定
    3.删除多余代码
    4.粘贴下边的代码vue模板 (如果使用css预编译,则style的类型是scss,如不使用改为css)

    {
        "Print to console": {
            "prefix": "vue",   
            "body": [
                "<!-- $1 -->",
                "<template>",
                "<div class='$2'>$5</div>",
                "</template>",
                "",
                "<script>",
                "//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)",
                "//例如:import 《组件名称》 from '《组件路径》';",
                "",
                "export default {",
                "//import引入的组件需要注入到对象中才能使用",
                "components: {},",
                "data() {",
                "//这里存放数据",
                "return {",
                "",
                "};",
                "},",
                "//监听属性 类似于data概念",
                "computed: {},",
                "//监控data中的数据变化",
                "watch: {},",
                "//方法集合",
                "methods: {",
                "",
                "},",
                "//生命周期 - 创建完成(可以访问当前this实例)",
                "created() {",
                "",
                "},",
                "//生命周期 - 挂载完成(可以访问DOM元素)",
                "mounted() {",
                "",
                "},",
                "beforeCreate() {}, //生命周期 - 创建之前",
                "beforeMount() {}, //生命周期 - 挂载之前",
                "beforeUpdate() {}, //生命周期 - 更新之前",
                "updated() {}, //生命周期 - 更新之后",
                "beforeDestroy() {}, //生命周期 - 销毁之前",
                "destroyed() {}, //生命周期 - 销毁完成",
                "activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发",
                "}",
                "</script>",
                "<style lang='scss' scoped>",
                "//@import url($3); 引入公共css类",
                "$4",
                "</style>"
            ],
            "description": "Log output to console"
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    6.上面代码中的 “prefix”: “vue”, 就是快捷键;保存好之后新建.vue结尾的文件试试(输入vue 按tab键就可以)

    在这里插入图片描述
    四、vue路由
    1.定义组件,刚刚已经用模板定义了一个组件
    2.在router index.js文件里引入刚刚写好的组件
    在这里插入图片描述
    我在这里是用的vue-router提供的按模块加载方式
    下面2行代码,没有指定webpackChunkName,每个组件打包成一个js文件。

    const ImportFuncDemo1 = () => import('../components/ImportFuncDemo1')
    const ImportFuncDemo2 = () => import('../components/ImportFuncDemo2')
    
    • 1
    • 2

    下面2行代码,指定了相同的webpackChunkName,会合并打包成一个js文件。

    // const ImportFuncDemo = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '../components/ImportFuncDemo')
    // const ImportFuncDemo2 = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '../components/ImportFuncDemo2')
    
    • 1
    • 2

    3.配置

    
    import Vue from "vue";
    import VueRouter from "vue-router";
    Vue.use(VueRouter)
    // 按模块加载...
    const HelloWorld= () => import('../components/HelloWorld')
    
    
     const routes=[{
        path: '/',
        redirect: '/HelloWorld',
        name:'HelloWorld'
      },{
        path:'/HelloWorld',
        component: HelloWorld,
        name:'HelloWorld'
      }
    ]
    
    const router = new VueRouter({
    	 routes,
       mode: 'history',
      //  vuex的严格模式
       strict: process.env.NODE_ENV !== 'production',
      // 这个整体做的是:在路由的history模式下,一些列表页利用缓存模式来记录位置(一般是返回不刷新,前进刷新),一般用了scrollBehavior,
      //同时还用keep-alive(缓存),activated(缓存下触发的钩子)配合做列表页的返回记录位置。缓存模式也有坑,就是何时清除缓存,一般是从新进入页面就清除。
      //回到主题,滚动行为就是:例如一个列表页,滑动了很多,点进去、再返回记录刚刚的位置
    	scrollBehavior (to, from, savedPosition) {
    	    if (savedPosition) {
    		    return savedPosition
    		} else {
    			if (from.meta.keepAlive) {
    				from.meta.savedPosition = document.body.scrollTop;
    			}
    		    return { x: 0, y: to.meta.savedPosition ||0}
    		}
    	}
    })
    
    export default router
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    4.路由文件注入到main.js文件中

    import Vue from 'vue';
    import router from './router/index';
    import 'lib-flexible/flexible.js';
    import App from './App'
    
    
    new Vue({
      el: '#app',
      router,
      components: { App },
      template: '<App/>'
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    5.在 app.vue里配置router-view

    <template>
      <div id="app">
        <router-view></router-view>
      </div>
    </template>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    6.路由跳转及传参方式

     1.$router为VueRouter实例,想要导航到不同URL,则使用$router.push方法
     2.$route为当前router跳转对象,里面可以获取name、path、query、params等
    
    
    (1)设置动态路由
            {
        		path:'/shopDetails/:id',
       	 		component: shopDetails,
       			 name:'shopDetails'
             }
            跳转this.$router.push('/shopDetails/'+id)
            获取id通过   this.$route.params.id
           
    (2)通过params携带参数 ,路由属性中的name来匹配路由    
            
             {
        	 	path:'/shopDetails',
    		   	 component: shopDetails,
    		   	 name:'shopDetails'
             }
             跳转 this.$router.push({name:'shopDetails',params:{id:id}})  
             获取  this.$route.params.id
    (3)通过path匹配路由,query携带参数 这种情况下 query传递的参数会显示在url后面?id=?
             {
    	    	 path:'/shopDetails',
    		   	 component: shopDetails,
    		   	 name:'shopDetails'
             }
             跳转 this.$router.push({path:'/shopDetails',query:{id:id}})  
             获取  this.$route.query.id
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    7.query和params的区别

    1.动态路由和query属性传值 页面刷新参数不会丢失, params会丢失 2.动态路由一般用来传一个参数时居多(如详情页的id), query、params可以传递一个也可以传递多个参数 。
    2.直白的来说query相当于get请求,页面跳转的时候,可以在地址栏看到请求参数,而params相当于post请求,参数不会再地址栏中显示

    8.路由的模式

    五、axios请求

    axios文档上的教程在这里就不重复叙述了,需要的看文档,我在这里贴下我的使用教程
    axios文档地址:https://www.npmjs.com/package/axios

    1.安装 npm install axios
    2.在utils下新建一个axios文件用来配置axios

    import axios from 'axios';
    const qs = require('qs');
    const service=axios.create({
        baseURL: process.env.BASE_API,    //请求公共地址,baseURL`将被添加到`url`,所以后边请求只需api的方式即可
        timeout: 5000,    //请求响应时间
    })
    // 是否携带cookie信息,默认为false,根据项目需求设置
    service.defaults.withCredentials = true;
    // 添加一个请求拦截器
    service.interceptors.request.use(function (config) {
        // 对请求数据做些事
        if(config.method  === 'post'){  //post传参序列化
          config.data = qs.stringify(config.data);
        } 
        return config;
      }, function (error) {
        return Promise.reject(error);
      });
    
    // 添加一个响应拦截器
    service.interceptors.response.use(function (response) {
        // 对响应数据做些事
        return response;
      }, function (error) {
          console.log(error)
        // Do something with response error
        return Promise.reject(error);
      });
    export default  service;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    3.新建一个api文件,这里边存放所有的请求函数,方便查找管理

    import axios from '../utils/axios';
    // 首页banner
    export function banner(){
        return axios({
            url:'/wxchat/xxx.action', //请求的地址
            method:'POST'
        })
    }
    // post请求带参数
    export function qiang(activityStatusType){
        return axios({
            url:'/wxchat/xxx.action',
            method:'POST',
            data:{activityStatusType:activityStatusType}
        })
    }
    // get请求
    export function moneys(){
    	 return axios({
            url: '/sd-web/xxx',
            method: 'get'
        }); 
    }
    // get请求带参数
    export function moneys(ids){
    	 return axios({
            url: '/sd-web/xxx',
            method: 'get',
            params:{id:ids}
        }); 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    4.页面实际应用

     import {banner} from '../../api/api'; //在页面上引入需要的请求函数
      //在生命周期函数或者需要的方法里运用
        mounted() {
            banner().then(response => {
                this.banner=response.data.data.SlAdvertisTabList
            }).catch(err=>{
                 console.log(err)
            });
        },
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    5.跨域配置

    (1)在config文件夹写的index.js里配置跨域
    在这里插入图片描述

    proxyTable: {
        '/wxchat': {
          target: 'xxx',  //目标接口域名
          changeOrigin: true,  //是否跨域
          secure: false,  //target默认情况下,不接受运行在HTTPS上,且使用了无效证书的后端服务器。如果你想要接受, 则需设置该项为false
          // pathRewrite: { // 如果接口本身没有/wxchat需要通过pathRewrite来重写了地址      重写接口
          //   '^/wxchat: ' '   
          // }
        }
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    注:我写的这个项目里,本身存在/wechat通用前缀,所以我没有用pathRewrite重写,如果你们接口里没有通用前缀的话,是要进行重写的

    上面配置中,’^/wxchat’ 其实是一个正则表达式

    ‘^/wxchat’ 应该拆分成 ‘^’ 和 ‘/wxchat’ 两个字符串,其中 ‘^’ 匹配的是字符串最开始的位置。

    ‘/wxchat’: {}, 就是告诉node, 我接口只要是’/wxchat’开头的才用代理.所以你的接口就要这么写/wxchat/xx/xx. 最后代理的路径就是 http://xxx.xx.com/wxchat/xx/xx.
    可是不对啊, 我正确的接口路径里面没有/wxchat啊. 所以就需要 pathRewrite,用’’^/wxchat’’:’’, 把’/wxchat’去掉, 这样既能有正确标识, 又能在请求接口的时候去掉wxchat

    接口没有通用前缀的开发环境的配置

    'use strict'
    const merge = require('webpack-merge')
    const prodEnv = require('./prod.env')
    
    module.exports = merge(prodEnv, {
      NODE_ENV: '"development"',
      BASE_API: '"/wechat"',     //在跨域里配置的//wechat,接口里就不用写通用前缀了,就按照正常接口写就可以了
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    接口有通用前缀的开发环境配置

    'use strict'
    const merge = require('webpack-merge')
    const prodEnv = require('./prod.env')
    
    module.exports = merge(prodEnv, {
      NODE_ENV: '"development"',
      BASE_API: '""',     //这里为空就好了,通用前缀就写在接口里
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    六、vuex的使用

    关于vuex的使用 ,什么时候该使用vuex? 当你觉得需要全局的状态,但是通过别的方式又太麻烦的时候,你就需要了,比如说我现在做的一个app项目,header组件是一个公共组件,那么header组件里边的标题怎么能随着页面的跳转而改变呢,vuex就可以做到 (个人理解,有不同理解的可以评论)
    缺点:vuex页面重新刷新,数据会丢失 解决方法:存本地,state数据可以从本地获取

    1.vuex中,有默认的五种基本的对象:

    • state 全局要访问的值
    • getters 实时监听state值的变化,对数据获取之前的再次编译,可以理解为state的计算属性。
    • mutations 改变state里的初始值 同步的
    • actions 异步触发mutations里面的方法
    • modules:store的子模块,为了开发大型项目,方便状态管理而使用的。这里我们就不解释了,用起来和上面的一样。

    2.下载安装vuex npm install vuex --save
    3.在src下新建一个store文件夹创建一个index.js 用来配置.
    4.引入vue,vuex,使用use全局注入插件

    import Vue from 'vue';
    import Vuex from 'vuex';
    Vue.use(Vuex);
    const store=new Vuex.Store({
        // 设置全局要访问的state值
        state:{
           title:'测试标题',    //头部标题
        }
    })
    export default store;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    5.在main.js里引入store,并全局注入

    import Vue from 'vue';
    import router from './router/index';
    import store from './store';
    import 'lib-flexible/flexible.js';
    import App from './App'
    
    
    new Vue({
      el: '#app',
      router,
      store,
      components: { App },
      template: '<App/>'
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    6.在任意组件内测试刚刚写的标题

    <template>
        <div class='orderDetails'>
            {{$store.state.title}}
        </div>
    </template>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    7.如图所示,刚刚的标题已经设置成功了
    在这里插入图片描述
    8.上图所示已经成功设置了标题,那怎么让它的标题改变呢,就要用到mutations对象了,我们在mutations对象里定义一个改变标题的方法,mutations里面的参数,第一个默认为state,接下来的为自定义参数。

     // 改变state里的初始值 同步的
        mutations :{
            TITLE(state,title){
                return state.title=title
            },
        },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    9.看下测试结
    在这里插入图片描述在这里插入图片描述
    9.从图上可以看出这个已经实现了,接下来看异步操作

     // 异步触发mutations里面的方法 在外部组件里进行全局执行actions里面方法的时候,你只需要用执行this.$store.dispatch('title',132) 这样就可以全局改变改变标题的值了
        actions:{
           title({commit},title){
                commit('TITLE',title)
            },
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    就不上图了,跟之前同步操作是一样的结果

    10.vuex同步和异步的区别

    1、当点发送过快,页面中渲染的内容与state中的数据不一致,vuex里面的state变得慢,且不持续更新
    2、action中是可以做到页面中state中数据保持一致
    3、当你的操作行为中含有异步操作,比如向后台发送请求获取数据,就需要使用action的dispatch去完成了。其他使用commit即可。

    七、打包上线
    1.

    执行  npm run build 命令
    
    • 1

    2.执行完成后,你会发现你的目录下多了一个dist的文件夹,这个就是打包的数据

    3.打包之后出现页面空白的原因
    3.1 css,js路径引用错误的问题

    解决:到config文件夹中打开index.js文件。
    文件里面有两个assetsPublicPath属性,更改第一个,也就是更改build里面的assetsPublicPath属性:
    assetsPublicPath属性作用是指定编译发布的根目录,‘/’指的是项目的根目录 ,’./’指的是当前目录。
    在这里插入图片描述

    3.2 设置路由history模式

    解决:改为hash或者直接把模式配置删除,让它默认的就行 。如果非要使用history模式的话,需要你在服务端加一个覆盖所有的情况的候选资源:如果URL匹配不到任何静态资源,则应该返回一个index.html,这个页面就是你app依赖页面。

    3.3 在css中引入的背景图片的路径问题

    解决:到build文件夹中打开util.js文件,添加路径代码

    在这里插入图片描述

  • 相关阅读:
    移动web开发资源大整合
    移动WEB模拟原声APP滑动删除
    jQuery的live绑定事件在mobile safari(iphone / ipad / ipod)上失效的解决方案
    精仿公众号菜单效果
    javascript markdown 解析器
    第四天
    第三天
    第二天
    第一天
    day5
  • 原文地址:https://www.cnblogs.com/xiaoxiaoxun/p/14090091.html
Copyright © 2011-2022 走看看