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文件,添加路径代码

在这里插入图片描述