Vue2.0

前言

作为前端开发工程师,咱们今天就来学习总结下主流框架之一的vue,与react都是spa(单页面应用,根html)声明式编程(对应的是原生js命令式编程)。这里我主要总结了一些个人的学习过程中知识点,尽可能的讲通俗易懂的话,更全面更术语更详细的内容还是推荐大家到Vue官网学习。
VUE官方文档

简介

渐进式框架(可以将vue作为项目的一部分嵌入其中,多框架开发一个项目,也叫混合开发),易于上手,有很多三方插件支持vue,反正用vue开发就是好。

MVVM原理

面试可能会经常问到MVVM(M:模型/就是data数据; V:视图/就是页面上的dom;VM:连接数据和视图的桥梁/就是实例化的Vue函数)。这个东西吧,是vue参考了MVVM模型,可不是尤雨曦创造出来的,更不是Vue特有,大佬也相互抄作业。
mvvm-mvc
这个图捏,主要是对比了下MVVM和MVC的区别,能看懂呢最好,看不懂也没事嗷,那谁不说了吗?知道鸡蛋好吃就行,没必要非得看看老母鸡长啥样,反正你不懂这个不会影响你用Vue。但凡事都有例外么,话说回来,这个东西你可以这么去理解,M就是饭店的大厨V就是到饭店吃饭的客人VM就是服务员,大厨(M)会做什么菜呢,写个菜单(data数据)让服务员(VM)告诉客人(V)对吧,然后呢,客人有不同口味,喜欢辣呀还是不喜欢辣(V的用户交互行为),告诉服务员(VM),然后呢服务员(VM)告诉大厨(M),客人点什么菜口味怎么样(用户交互行为),大厨做好了(后台处理好的数据)之后服务员再端给客人,客人就吃到了自己想吃的菜。这个个过程就是MVVM的执行过程

v-指令

1. v-cloak

可以解决插值表达式在网速慢的情况下闪烁的问题(页面出现插值表达式),这里就简单书写用法:

	<p v-cloak>{
   
   {msg}}</p>

	<style>
		[v-cloak]{
      
      
			display:none
		}
	</style>
2. v-text

另外一种写法就是不用插值表达式来渲染我们的变量,而是用v-text:

	<p v-text="msg"></p>

虽然v-text可以自动避免闪烁的问题,但是无法像插值表达式那样实现内容的任意拼接,并且会覆盖标签内容:

	<p>这是拼接前面的内容{
   
   {msg}}这是拼接后面的内容</p>
	<p v-text="msg">这里是v-text会被覆盖的内容</p>
3. v-html

当我们的msg变量中是一个xml表达式时(msg:<h1>我是h1标签</h1>),插值表达式和v-text都会对其原样输出(容易导致xss攻击,用户表单提交元素上一定要避免使用),这时就要使用v-html:

	<p v-html="msg"></p>
4. v-bind

是vue中用于绑定属性的指令,可以直接简写为‘:’,v-bind中可以写合法的js表达式:

	/* myTitle:这是一个自定义的标题 */
	<input type='button' value='按钮' :title='myTitle+"123"'>
	<input type='button' value='按钮' v-bind:title='myTitle'>
	/* 第一个标签的title属性为:这是一个自定义的标题123,
	第二个标签的title属性为:这是一个自定义的标题 */

这里值得注意的是,通过v-bind绑定的类名vue内部会与class类名进行合并处理。

<p class="text" :class="{active:true, otherName:false}">这是一个p标签</p>

最终p标签上会有两个类名,text和active。

5. v-once

只渲染数据的默认值,后期数据被更改页面不做响应

<div v-once>就只渲染一次动态属性,后续不会更新{
    
    {
    
    msg}}</div>
6. v-if

创建和删除元素,多元素可以外层包裹template标签包裹(配合使用)

7. v-show

不进行dom操作,只是切换元素的display样式为none
如果项目中涉及到频繁的切换,则尽量使用v-show,以减少对dom的操作,提升性能;如果长期操作不会被用户看到则使用v-if,不能配合template标签使用

8. v-for

用于数据循环渲染,记得绑定key,可以循环的数据类型有数组、对象、字符串、循环次数。

9. v-else | v-else-if

配合v-if使用,但结构不能打断

10. v-pre

不做vue语法解析,会将内容原封不动的展示出来<p v-pre>{ {count}}</p>,页面展示为{ {count}}
推荐使用场景:纯静态文本没有差值语法和变量参与的标签可以加,用于提升性能,减少vue解析

11. v-on

事件绑定机制,可以简写为‘@’,参数有:click(点击)mouseover(鼠标滑过)…在vue中事件函数要写在methods对象中:

	<input type='button' value='按钮' v-on:click='btn' >
	<input type='button' value='按钮' @click='btn'>
	/* methods:{
		btn(){
			alert('这是一个按钮')
		}
	} */

事件中获取元素对象可以在函数中传$event:

<p @click='dianji(canshu1,$event)'>点我啊</p>

@scroll 监听滚动条滚动
@wheel 监听鼠标滚轴滚动

【事件修饰符】

.stop 阻止冒泡
.prevent 阻止默认事件
.capture 添加事件侦听器时使用事件捕获模式(由外而内的触发)
.self 只当事件在该元素本身(不是子元素或父元素)触发时生效
.once 事件只触发一次
.left 左键
.right 右键
.middle 中间滚轮
.lazy 表单元素懒更新(文本域当用户输入一大段话并不实时更新数据,只有当输入框失焦才会更新data数据)
.passive 事件默认行为立即执行,无需等待事件回调执行完毕
事件修饰符可以多个连用前后位置不影响效果,其中self和stop都可以起到阻止冒泡的作用,但区别是.self只会阻止自己身上冒泡行为的触发,并不会真正阻止冒泡行为。

<!-- 阻止单击事件冒泡 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联  -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件侦听器时使用事件捕获模式 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 -->
<div v-on:click.self="doThat">...</div>

<!-- click 事件只能点击一次,2.1.4版本新增 -->
<a v-on:click.once="doThis"></a>

记住所有的 keyCode 比较困难,所以 Vue 为最常用的按键提供了别名:

<!-- 只有在 keyCode 是 13 时调用 vm.submit() -->
<input v-on:keyup.13="submit">
<input v-on:keyup.enter="submit">
<!-- 缩写语法 -->
<input @keyup.enter="submit">

vue提供的别名按键,可以使用按键原始的key值去绑定,但双单词按键要用横线命名(caps-lock),当然,也不是所有的按键都能绑定事件,比如:音量控制键、键盘光以及一些外置个性化的按键。
vue提供全部的按键别名:
.enter
.tab(特殊,必须配合keydown使用,tab本身的功能有切换当前元素焦点)
.delete (捕获 “删除” 和 “退格” 键)
.esc
.space
.up
.down
.left
.right
表单修饰符
.lazy 搭配v-model使用
.native 将组建绑定的原生事件自动绑定到组建内部第一个跟元素上(如果没有该修饰符,事件将被认为是自定义事件)
以下是系统修饰键(用法特殊)
(1) 配合keyup时,按下修饰键的同时再按下其它键,随后释放其它键,事件才被触发
(2) 配合keydown使用,正常触发事件
.ctrl
.alt
.shift
.meta
不推荐使用keyCode去指定按键(越来越个性化的键盘,上面的keycode未必一致)
可以通过Vue.config.keyCodes.自定义键名 = 键码去自定义按键别名

<!--"change" 而不是 "input" 事件中更新 -->
<input v-model.lazy="msg" >

.number

<!-- 自动将用户的输入值转为 Number 类型(如果原值的转换结果为 NaN 则返回原值)-->
<input v-model.number="age" type="number">

.trim

<!-- 自动过滤用户输入的首尾空格 -->
<input v-model.trim="msg" >
12. v-model

可以实现表单元素中数据的双向绑定,该指令只能运用在表单元素中,如:input(radio,text,address,email…)、select、checkbox、textarea…
这个方法不可以去绑定props中传过来的值,因为props值不能直接更改,如果props数据是对象类型,则可以绑定对象里的某个值(对象的某个值被更改并不会视作更改对象,内存中的引用地址并未发生改变)
在VM实例中,如果想要获取data上的数据,或者调用methods中的方法,必须通过this.数据属性名 或 this.方法名 来进行访问,这里的this就表示我们new出来的VM实例对象:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>跑马灯</title>
    <!-- 引入vue.js-->
    <script src="./lib/vue.js"></script>
</head>
<body>
<div id="app">
    <button @click="show">浪起来</button>
    <button @click="stop">低调</button>
    <h3 v-text="message"></h3>
</div>
<script>
    var vm = new Vue({
      
      
        el:"#app",
        data:{
      
      
            message:"浩浩爱茜茜~茜茜爱浩浩~",
            timer:null
        },
        methods:{
      
      
            show(){
      
      
                if(this.timer != null) return;
                this.timer = setInterval(() => {
      
      
                    //获取到头的第一个字符
                    let start = this.message.substring(0,1);
                    //获取到后面的所有字符
                    let end = this.message.substring(1);
                    this.message = end + start;
                },300)
            },
            stop(){
      
      
                //清除定时器
                clearInterval(this.timer)
                //清除定时器之后,需要重新将定时器置为null
                this.timer = null
            }
        }
    })
</script>
</body>
</html>

收集表单数据:
<input type="text"/>,则v-model收集的是value值,用户输入的就是value值。
<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值。
<input type="checkbox"/>
1. 没有配置input的value属性,那么收集的就是checked(勾选或者未勾选,是布尔值)
2. 配置input的value属性:
a. v-model的初始值是非数组,那么收集的就是checked(勾选或者未勾选,是布尔值)
b. v-model的初始值是数组,那么收集的就是value组成的数组

vue过滤器

filters:在视图里二次处理数据的作用

<div id="app">
  {
    
    {
    
     message | capitalize }}
</div>
    
<script>
new Vue({
    
    
  el: '#app',
  data: {
    
    
    message: 'runoob'
  },
  filters: {
    
    
    capitalize: function (value) {
    
    
      if (!value) return ''
      value = value.toString()
      return value.charAt(0).toUpperCase() + value.slice(1)
    }
  }
})
</script>

过滤器可以串联:

{
    
    {
    
     message | filterA | filterB }}

计算属性-computed

应用时机:要用的属性不存在,需要通过已有的属性计算得来
原理:底层借助了Object.defineproperty方法提供的getter和setter
get函数在初次读取和依赖数据发生改变时会被调用。
相比较methods,他有缓存机制,当页面多次调用渲染,非值改变则不会重复调用计算,效率更高。
计算属性最终会出现在vm上,直接读取使用即可,如果计算属性被修改,那必须写set函数去相应修改,且要更改计算的依赖属性数据。

<div id="app">
  <p>原始字符串: {
    
    {
    
     message }}</p>
  <p>计算后反转字符串: {
    
    {
    
     reversedMessage }}</p>
</div>
 
<script>
var vm = new Vue({
    
    
  el: '#app',
  data: {
    
    
    message: '这是测试文字'
  },
  // computed: {
    
    
    // 计算属性的 getter
    // reversedMessage: {
    
    
      // 详细写法
      // get() { // 读取
			// return this.message.split('').reverse().join('')
		// }
      // set( value ) { // 更改
        // this.message = value
		// }
    // }
  // }
  // 简写
  computed: {
    
    
    // 计算属性的 getter
    reversedMessage: function () {
    
    
      // `this` 指向 vm 实例
      return this.message.split('').reverse().join('')
    }
  }
})
</script>

监听-watch

  1. 当属性变化的时候,回调函数自动调用,进行相关操作
  2. 监视的属性必须存在,才能进行监视
  3. 监视的两种方法:
// 被监听属性可以是data里的属性,也可以是计算属性
watch:{
    
    
	被监听属性:{
    
    
		immediate: true, // 初始化时即监听,否则值改变时开始监听
		deep: false, // 深度监视 多嵌套结构
		handler(newValue,oldValue){
    
    
			console.log('新值',newValue,'旧值',oldValue)
		}
	}
}
// 简写
watch: {
    
    
	被监听属性(newVal,oldVal) {
    
    
	}
}
// 一定是字符串类型的属性书写,否则找不到
const vm = new Vue({
    
    ...})
vm.$watch('被监听属性',{
    
    
	...
})
// 如果是简写
vm.$watch('被监听属性'function(newVal,oldVal){
    
    
})

深度监视:
Vue中的watch默认不监测对象内部值的改变(一层)
配置deep: true可以监测对象内部值的改变(多层)
【vue自身可以监测队形内部值的改变,但vue提供的watch默认不可以,使用时就需要根据数据的具体结构决定是否采用深度监视】

watch&computed区别

computed能完成的功能,watch都可以完成,但computed有缓存,watch中可以进行异步操作。

vue监视数据原理

vue会监视data中所有层次的数据。

  1. 对象数据
    通过setter实现监视,且要在new vue时就传入要监测的数据。
    对象中后加的属性,vue默认不做响应式处理。如需后添加的属性做响应式处理,请使用以下方法:
    Vue.set(target, propertyName/index, value)
    vm.$set(target, propertyName/index, value)
  2. 数据数据
    通过包裹数组更新元素的方法实现,本质就是做了两件事:调用原生对应的方法对数组进行更新;重新解析模版,进而更新页面。
    在vue中修改某个元素的方法:push(),pop(),shift(),unshift(),splice(),sort(),reverse();Vue.set() 或 vm.$set()
    set()不能直接给data(根数据)添加属性!!!

表单元素使用

input 类型为text ,则v-model收集的是value值,用户输入的是value值。
input 类型为radio,则v-model收集的是value值,且要给标签配置value值。
input 类型为CheckBox:

  1. 若没有配置value值,收集的就是checked(勾选or未勾选, 是布尔值);
  2. 有配置value值:
    a. v-model初始值是非数组,那收集的依然是checked(勾选or未勾选, 是布尔值)
    b. v-model初始值是数组,那收集的value值就是value组成的数组
    注:
    v-model有三个修饰符:lazy: 失去焦点时收集数据; number:输入字符串转为有效数字; trim:输入收尾空格过滤

过滤器

定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理
语法:

  1. 注册过滤器: Vue.filter(name,callback) 或 new Vue{filters:{ 过滤器名(管道符【| 就叫管道符】前面的变量,其它参数){ return 页面上要展示的结果} }}
  2. 使用过滤器:{ { XXX | 过滤器名(其它参数) }} 或 v-bind:属性 = ‘’ XXX | 过滤器名’’
    注:
    过滤器可以接收额外参数,多个过滤器可以串联,没有改变原本的数据,是产生新的对应的数据

自定义vue指令

自定义指令调用的触发时机:

  1. 指令与元素成功绑定时
  2. 指令所在模板被重新解析时(不仅只是对应绑定变量值变更)
    语法:
  3. 局部指令
new Vue({
    
    
	directives: {
    
    
		指令名:{
    
    
			bind(){
    
    } // 与元素绑定成功时调用
			inserted(){
    
    } //指令所在元素被插入页面时调用
			update(){
    
    } // 指令所在模板结构被重新解析时调用
		}
	}
})
// 简写
new Vue({
    
    
	directives: {
    
    
		'指令名'(element, binding){
    
    
			return 
		}
	}
})
  1. 全局
Vue.directive('指令名',配置对象)

Vue.directive('指令名',回调函数)

注:
指令定义时不加v-,使用时加v-;指令名如果是多个单词,要使用kebab-case命名方式,不要用小驼峰方式。

生命周期

官网有很详细的介绍和流程图,我在这就不多赘述了,就说两个常用的吧。
mounted:发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。
beforeDestroy:清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。
关于销毁vue实例:
销毁后借助vue开发者工具看不到任何信息;自定义事件失效,但原生dom事件依然有效;一般不要在beforeDestroy操作数据,因为即使操作数据,也不会出发更新流程了。

组件

  1. 定义组件(创建)
    使用vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别:
    el不要写,最终所有的组件都要经过一个vm的管理,由vm中el决定服务哪个容器。
    data必须写成函数,避免组件被重复调用时,对象数据存在引用关系。
    template可以配置组件结构,但注意根节点。
  2. 注册组件
    局部注册:靠new Vue时候传入的components选项
    全局注册:靠Vue.components(‘组件名’,组件)
  3. VueComponent.prototype.proto === Vue.prototype, 让组件实例对象可以访问到Vue原型上的属性、方法。

props

让组件接收外来数据。

// 父组件传值
<ParentComponent propKey='propValue' />
// 子组件接收数据
只接收:
props: ['propKey']
限制类型:
props: {
    
    propKey:String(js数据类型)}
限制类型、限制必要性、指定默认值:
props:{
    
    propKey:{
    
    type:String,required:true,default: '默认值'}}

props是只读,Vue底层会监测对props的修改,如果进行了修改,救护发出警告,如果业务需求确实需要修改,可以复制props的内容到data中一份,然后修改data中的数据。(可以通过v-bind传props值,这样会保持原有数据类型,否则默认都为字符串类型)

插槽

让父组件可以向子组件指定位置插入html结构,也是一种组建通信的方式,适用于父组件 ===>子组件
分为默认插槽、具名插槽、作用域插槽。
默认插槽:

// 父组件
<Category>
	<div>
		这里是具体的html内容
	</div>
</Category>
// 子组件
<template>
	<div>
		<slot>插槽默认内容</slot>
	</div>
</template>

具名插槽:

// 父组件
<Category>
	<div slot='center'>
		这里是具体的html内容
	</div>
	<div v-slot:center>
		这里是具体的html内容
	</div>
</Category>
// 子组件
<template>
	<div>
		<slot name='center'>插槽默认内容</slot>
	</div>
</template>

作用域插槽:
数据在组件的自身,但是数据生成的结构需要组件的使用者来决定(父组件使用子组件数据来渲染结构)

// 父组件
<Category>
	<div slot-scope='{listData}'>
		// 第一种slot-scope方式,可解构也可不解构
		<ul>
			<li v-for="v in listData" :key='v'>{
    
    {
    
    v}}</li>
		</ul>
	</div>
</Category>

<Category>
	<div scope='scopeData'>
	// 第二种scope方式,可解构也可不解构
		<ul>
			<li v-for="v in scopeData.listData" :key='v'>{
    
    {
    
    v}}</li>
		</ul>
	</div>
</Category>
// 子组件
<template>
	<div>
		<slot :listData='list'>插槽默认内容</slot>
	</div>
</template>

<script>
	export default {
    
    
		name:'Catagory',
		data(){
    
    
			return {
    
    
				list: [11,222,33,14]
			}
		}
	}
</script>

mixin(混入)

功能:可以把多个组件公用的配置提取成一个混入对象。
使用:
定义一个公共js文件用于存储公共逻辑。

// mixin.js文件
export default{
    
    
	data(){
    
    ...}
	methods:{
    
    ...}
	...
}

局部组件混入:mixins:[‘XXX’]
全局混入:Vue.mixin(XXX),但存在一个弊端就是每个组件都会触发造成滥用,不利于性能优化

插件

功能:用于增强Vue
本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的自定义数据。
定义插件:
对象.install = function(Vue,options) {
Vue.filter(…) // 全局过滤器
Vue.directive(…) // 全局指令
Vue.mixin(…) // 全局混入
Vue.prototype. m y M e t h o d = f u n c t i o n ( ) . . . V u e . p r o t o t y p e . myMethod = function() {...} Vue.prototype. myMethod=function()...Vue.prototype.myProperty = XXX
}
使用插件: Vue.use()

自定义事件(组件间)

适用于子组件给父组件传递事件
绑定自定义——
第一种方式:

<Children @funHandler='test'/>
<Children v-on:funHandler='test'/>

第二种方式:

<Children ref='childCom'/>
mounted () {
    
    
	this.$refs.childCom.$on('funHandler',this.test);
}

如果想让自定义事件只触发一次,可以使用.once修饰符,或$once方法
触发自定义事件——
this.$emit('funHandler',数据)
解绑自定义事件——
this.$off('funHandler')
注意:通过this.$refs.childCom.$on('funHandler',this.test)绑定事件,事件如果不是写在methods中则使用箭头函数,否则this指向会出现问题。

全局事件总线

相当于开启了一个全局的第三方组件,所有的组建均可与他进行通信。

new Vue({
    
    
  router,
  store,
  render: h => h(App),
  beforeCreate(){
    
    
    Vue.prototype.$bus = this // 开启全局总线
  }
}).$mount('#app')

传递数据组件

this.$bus.$emit('busHandler','全局总线事件触发')

读取数据组件

this.$bus.$on('busHandler',(data)=>alert(data))
// 最好在销毁之前解绑自定义事件
beforeDestroy(){
    
    
    this.$bus.$off('busHandler')
},

transition动画

元素进入样式:
v-enter:进入的起点
v-enter- active:进入的过程中
v-enter-to:进入的终点
元素离开的样式:
v-leave:离开的起点
v-leave-active: 离开的过程中
v-leave-to:离开的终点
使用<transition></transition>包裹要过度的元素,并配置name属性,如果不配置name属性则为默认的v:

<transition name='hello' appear>
	<h1 v-show='isShow'>你好啊!</h1>
</transition>


<style>
	.hello-enter,hello-leave-to{
    
    
		transform: translateX(-100%)
	}
	.hello-enter-active,.hello-leave-active{
    
    
		animation: .5s linear;
	}
	.hello-leave,hello-enter-to{
    
    
		transform: translateX(0)
	}
</style>

配置列表元素动画则使用<transition-group></transition-group>,每个元素指定key

配置代理

方法一
在vue.config.js中添加如下配置:

devServer: {
    
    
	proxy: 'http://localhost:5000';
}

优点:配置简单,请求资源时直接发给前端(8080)即可。
缺点:不能配置多个代理,不能灵活控制请求是否走代理。
工作方式:当请求了前端不存在的资源时,该请求会转发给服务器(优先匹配前端资源)
方法二
编写vue.config.js配置具体代理规则:

module.exports = {
    
    
	devServer: {
    
    
		proxy: {
    
    
			'/api1': {
    
     // 匹配以api1开头的请求路径
				target: 'http://localhost:5000', // 代理目标的基础路径
				changeOrigin: true, // 隐藏真实端口
				pathRewrite: {
    
    '^/api1':''} // 重写路径去除代理标识字段
			},
			'/api2': {
    
     // 匹配以api1开头的请求路径
				target: 'http://localhost:5001', // 代理目标的基础路径
				changeOrigin: true, // 隐藏真实端口
				pathRewrite: {
    
    '^/api2':''} // 重写路径去除代理标识字段
			},
		}
	}
}

优点:可以配置多个代理,而且可以灵活的控制请求是否走代理。
缺点:配置略微繁琐,请求资源时必须加前缀。

VUEX模块化+命名空间

目的:让代码更好维护,让多种数据分类更加明确
修改store.js

const countAbout = {
    
    
	namespaced: true, // 开启命名空间
	state: {
    
    x:1},
	mutations: {
    
    ...},
	actions: {
    
    ...},
	getters: {
    
    
		bigSum(state){
    
    
			return state.sum * 10
		}
	}
}

const personAbout = {
    
    
	namespaced: true, // 开启命名空间
	state: {
    
    ...},
	mutations: {
    
    ...},
	actions: {
    
    ...}
}

const store = new Vuex.Store({
    
    
	modules: {
    
    
		countAbout,
		personAbout
	}
})

开启命名空间后,组建中读取state数据:

this.$store.state.personAbout.list // 方式一,直接读取
...mapState('countAbout',['sum', 'school', 'subject']) // 方式二,借助mapState读取

开启命名空间后,组建中读取getters数据:

this.$store.getters['personAbout/firstPersonName'] // 方式一,自己直接读取
...mapActions('countAbout',['bigSum'])

开启命名空间后,组建中调用dispatch

this.$store.dispatch('personAbout/addPersonWang'.person)
...mapActions('countAbout',{
    
    incerementOdd:'jiaOdd',incerementAwait:'jiaAwait'})

开启命名空间后,组建中调用commit

this.$store.commit('personAbout/ADD_PERSON',person) // 方式一,直接commit
...mapMutations('countAbout',{
    
    incerementOdd:'JIA',incerementAwait:'JIAN'})

路由

query传参

传递

<router-link :to="/home/message/detail?id=666&title=你好">跳转</router-link>
<router-link
	:to="{
    
    
		path:'/home/message/detail',
		query:{
    
    
			id:666,
			title: '你好'
		}
	}"
>跳转</router-link>

接收

this.$route.query.id
this.$route.query.title

命名路由

可以简化路由的跳转。
1.给路由命名:

{
    
    
	path: 'demo',
	component: Demo,
	children: [
		{
    
    
			path: 'test',
			component: Test,
			children: [
				{
    
    
					path: 'hello',
					name: 'welcome', // 给路由起名字
					component: Hello
				}
			]
		}
	]
}

2.简化跳转:

<router-link to="/demo/test/hello">跳转</router-link>
<router-link :to="{name:'welcome'}">跳转</router-link>
<router-link :to="{
    
    
	name:'welcome',
	query: {
    
    
		id=999,
		title='你好'
	}
}"
>跳转</router-link>

params穿参

1.配置路由,声明接收params参数

{
    
    
	path: 'demo',
	component: Demo,
	children: [
		{
    
    
			path: 'test',
			component: Test,
			children: [
				{
    
    
					path: 'hello/:id/:title', // 动态路由
					name: 'welcome', // 给路由起名字
					component: Hello
				}
			]
		}
	]
}

2.传递参数

<router-link :to="/demo/test/hello/666/你好">跳转</router-link>
<router-link :to="{
    
    
	name:'welcome',
	params: {
    
    
		id: 666,
		title: '你好'
	}
}"
>跳转</router-link>

路由携带params参数时若使用to绑定对象值写法,则只能使用name配置!
3.接收参数

this.$route.params.id
this.$route.params.title

路由的props配置

作用:让路由组建更方便的接收到参数

{
    
    
	name: 'xiangqing',
	path: 'detail/:id',
	component: Detail,
	// 第一种写法,props值为对象,该对象中所有的key-value的组合最终都会通过props传给detail组件
	// props: {a:900}
	// 第二种写法: props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给detail组件
	// props: true
	// 第三种写法: props值为函数,该函数返回的对象中每一组key-value都会通过props传给detail组件
	props(route){
    
    
		return {
    
    
			id:route.query.id,
			title: route.query.title
		}
	}
}

<router-link>的replace属性

1.作用:控制路由跳转时操作浏览器历史记录的模式
2.浏览器的历史记录有两种写入方式:分别为push和replace,push是追加历史记录,replace是替换当前记录。路由跳转时候默认为push
3.如何开启replace模式:<router-link replace to=""></router-link>

编程式路由导航

作用:不借助<router-link>实现路由跳转,让路由跳转更加灵活

this.$router.push({
    
    
	name: 'xiangqing',
	params: {
    
    
		id: XXXX,
		title: XXXX
	}
})
this.$router.replace({
    
    
	name: 'xiangqing',
	params: {
    
    
		id: XXXX,
		title: XXXX
	}
})
this.$router.forward() // 前进
this.$router.back() // 后退
this.$router.go() // 正数前进,负数后退,0刷新

缓存路由组件

作用:让不展示的路由组件保持挂载,不被销毁

// include的值是每个组件的组建名 组建内name属性对应的值
<keep-alive include="News">
	<router-view></router-view>
</keep-alive>
// 缓存多个组件
<keep-alive include="['News','Message']">
	<router-view></router-view>
</keep-alive>

与缓存路由组建相关的两个生命周期钩子

作用: 路由组建所独有的两个钩子,用于捕获路由组建的激活状态。
activated路由组建被激活时触发
deactivated路由组建失活时触发

路由守卫

作用:对路由进行权限控制
分类:全局守卫、独享守卫、组件内守卫

  1. 全局守卫:
// 全局前置守卫,初始化时执行、每次路由切换前执行
router.beforeEach((to,from,next)=>{
    
    
	if(to.meta.isAuth){
    
     // 判断当前路由是否需要进行权限控制 meta为路由自定义信息配置对象
		if(localStorage.getItem('login') === 'true'){
    
     // 权限控制的具体规则
			next()
		}
		else {
    
    
			next({
    
    name: 'login'}) // 未开启权限的其他逻辑
		}
	}else {
    
    
		next()
	}
})
// 全局路由后置守卫,初始化时执行、每次路由切换后执行
router.afterEach((to,from)=>{
    
    
	if(to.meta.title){
    
    
		doucument.title = to.meta.title // 修改网页标题
	}else{
    
    
		...
	}
})
  1. 独享守卫:
beforeEnter(to,from,next){
    
    
	... // 基本和全局前置路由首位相似,唯一不同点在于该守卫针对单个路由进行配置,与path、name、meta等参数同级
}
  1. 组件内守卫:
// 进入守卫:通过路由规则,进入该组件时被调用
beforeRouteEnter(to,from,next){
    
    },
// 离开守卫:通过路由规则,离开该组件时被调用
beforeRouteLeave(to,from,next){
    
    }

路由器的两种工作模式

页面url里#及其后面的内容就是hash值。
hash值不会包含在http请求中,即:hash值不会带给服务器。
hash模式:
地址中永远带着#,不美观
若以后讲地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
兼容性较好。
history模式:
地址干净、美观。
兼容性和hash模式相比略差。
应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。

额外知识点

  1. eval()会计算字符串并返回结果,但在开发中不推荐使用
console.log(eval('2+3')); // 5
  1. vue.js与vue.runtime.XXX.js的区别:
    vue.js是完整版的vue。包含核心功能+模版解析器。
    vue.runtime.XXX.js没有模版解析器,所以不能使用template配置项。需要使用render函数接收到createElement函数去指定具体内容。
  2. ref属性
    被用来给元素或子组件注册引用信息(id的替代者)
    应用在html标签上获取的是真实的dom元素,应用在组件标签上是组件实例对象(vc)
    使用方式:
<h1 ref="XXX"></h1>
// 获取; 通过this.$refs.XXX
  1. nextTick
    在下一次dom更新结束后执行指定的回调,一般用于当改变数据后,要基于更新后的dom进行某些操作,要在nextTick所指定的回调函数中执行。
this.$nexTick(function(){
    
    })

个人开发问题总结

路由配置重定向后导航标签高亮失效
路由表:

const routes = [
  {
    
    
    path: '/home',
    name: 'home',
    component: HomeView
  },
  {
    
    
    path: '/about',
    name: 'about',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
  },
  {
    
    
    path: '/',
    redirect: '/home',
  },
]
const router = new VueRouter({
    
    
  routes,
  mode: 'history',
  linkActiveClass: 'active'
})

页面:

<template>
  <div id="app">
    <nav>
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link> | 
      <router-link :to="{name:'keyCode'}">键盘监听</router-link>
    </nav>
    <router-view/>
  </div>
</template>

在这里插入图片描述
解决:
将Home导航选项的to属性值与路由表的path对应一致,而不是与重定向路径保持一致

<template>
  <div id="app">
    <nav> 
      <router-link to="/home">Home</router-link> |
      <router-link to="/about">About</router-link> | 
      <router-link :to="{name:'keyCode'}">键盘监听</router-link>
    </nav>
    <router-view/>
  </div>
</template>

不断充电,持续更新,点点关注不迷路,随更随看~

猜你喜欢

转载自blog.csdn.net/vh_YUNYANGYUMO/article/details/115299742