Vue 基础


Vue

  1. 指令与属性
  2. 组件
  3. 生命周期
  4. 响应式原理
  5. diff算法
  6. vue-router
  7. Vuex
  8. 其他

指令与属性

指令

v-text

  • 声明式操作视图,将data中属性的值设置到绑定v-text指令的标签上
  • 原理:当改变data中某个属性的值时,获取绑定v-text指令的节点的所有属性,将该节点的文本设置为v-text绑定的data中的值。
    • 发布订阅模式的本质是解决一对多的问题,在vue中实现数据变化之后的精准更新(依赖data中某个属性的节点才更新)。

v-model

  • 视图变化反应到数据
    • 事件监听反向修改(有缺陷,不能精确更新)
  • 双向绑定原理
    • vue.js是采用==数据劫持+发布者-订阅者模式==的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调来渲染视图。
    • 在这里插入图片描述
      • observe对象指的是把数据处理成响应式的对象;
      • watcher指的其实就是数据变化之后的更新函数 (vue中的watcher有两种,一种是用来更新视图的watcher,一种是通过watch配置项声明的watcher);
      • dep指的就是使用发布订阅实现的收集更新函数和触发更新函数的对象;
      • 发布订阅模式的本质是解决一对多的问题,在vue中实现数据变化之后的精准更新(依赖data中某个属性的节点才更新)。
    • 过程:
      1. 定义一个Vue实例后,先递归将data对象中所有的属性通过Object.defineProperty()设置访问器属性getter和setter;
      2. compile解析模板指令:将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变化,通知watcher,然后更新视图;
      3. Watcher订阅者是Observer和Compile之间通信的桥梁;
      4. 数据模型变化反映到视图上:当data中的数据发生变化时,触发setter,setter通知dep对象,dep对象通知watcher,watcher将更新后的数据更新到视图上;
      5. 视图数据更新反映到数据模型上:

👉References

v-show v-if的区别

  1. 控制手段不同:v-show控制元素的display属性来实现隐藏与显示。v-if通过添加或删除dom元素来实现。
  2. 不管显示与否,v-show都会渲染。而只有满足条件的时候,v-if才会渲染。、v-show由false变为true时不会触发组件的生命周期。v-if由false变为true时会触发组件的beforeCreated、created、beforeMounted、mounted钩子,由true变为false时会触发组件的beforeDestroy、destroy钩子。
  3. v-show有更高的渲染消耗,v-if有更高的切换消耗。

使用场景:

  1. 需要频繁切换使用v-show;
  2. 在运行时条件很少改变,使用v-if较好。

属性

computed和watch区别(重点)

computed

computed 是一个计算属性,类似于 filter,对 data 中的属性进行处理,通过已有属性得出 data 中不存在的属性

computed 具有缓存性,computed 的值在 getter 执行后是会缓存的,只有在它依赖的属性值改变之后,下一次获取 computed 的值时重新调用对应的 getter 来计算,底层借助了 Object.defineProperty 的 getter 和 setter。

get 的作用:有人初次读取计算属性或依赖的属性发生变化时,get 会被自动调用,返回计算出的属性值。多次调用时,会读取缓存,只调用一次 get

set 的作用:当修改计算属性时,会调用 set

如果确定只会读取计算属性的值,不会修改时,可以简写,不写 get 和 set,直接在计算属性对象中返回计算方法。

computed 中的函数必须用 return 返回最终的结果

computed:{
    // 因为计算的过程可能会很复杂,所以vue要求计算属性写为对象的形式
    fullName:{
        // get的作用:当有人调取fullName时,get就会被调用,返回值作为fullName的值,多次调用fullName时,会读取缓存,只调用一次get,
        // 但所依赖的值发生变化时,会重新调用get(),都是自动调用的
        // get什么时候调用?1、初次读取fullName时,2、所依赖的数据发生变化时
        get(){
            return this.firstName + '-' + this.lastName   //this指向vm
        },
            // set什么时候调用?当fullName值被修改时
            set(value){
                const arr = value.split('-'); //输入'李-四',通过-分开,第一个值是姓,第二个值是名
                this.firstName = arr[0];
                this.lastName = arr[1];
            }
    }
}
watch
  1. 属性监听,监听属性的变化,监听 props,$emit 或本组件的值,当数据变化时来执行回调进行后续操作;

  2. watch 中的函数是不需要调用的;

  3. 没有缓存性,页面渲染时值没有变化也会重新执行;

  4. 监视还包括深度监视,此时必须使用完整形式;

isHot:{
    // immediate:true,
    // deep:true,	//监测多级结构中所有属性的变化
    // 当配置项只有handler的时候才可以使用简写形式
    handler(newValue,oldValue){     //监测更改前与更改后的值
        console.log('isHot被修改了!',newValue, oldValue);  
    }
}, 

对比

computed 和 watch 之间的区别:

  1. 当我们要进行数值计算,而且依赖于其他数据,那么把这个数据设计为 computed
  2. 如果你需要在某个数据变化时做一些事情,使用 watch 来观察这个数据变化。

使用场景

computed:当一个属性受多个属性影响的时候使用,例:购物车商品结算功能

watch:当一条数据影响多条数据的时候使用,例:搜索数据

两个重要的小原则:

​ 1.所有被Vue管理的函数,最好写成普通函数,这样,this才指向的是vm或者组件实例对象

​ 2.所有不被Vue所管理的函数(定时器的回调函数,ajax的回调函数等等),最好写成箭头函数,这样的this指向才是vm或者组件实例对象

总结

计算属性本质上是 computed watcher,而侦听属性本质上是 user watcher。就应用场景而言,计算属性适合用在模板渲染中,某个值是依赖了其它的响应式对象甚至是计算属性计算而来;而侦听属性适用于观测某个值的变化去完成一段复杂的业务逻辑。

为什么 vue 中的 data 是一个函数?

组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份data,就会造成一个变了全都会变的结果

nextTick 的原理是什么?

将回调推迟到下一个 DOM 更新周期之后执行。在更改了一些数据以等待 DOM 更新后立即使用它。

原理分析

由于Vue DOM更新是异步执行的,即修改数据时,视图不会立即更新,而是会监听数据变化,并缓存在同一事件循环中,等同一数据循环中的所有数据变化完成之后,再统一进行视图更新。为了确保得到更新后的DOM,所以设置了 Vue.nextTick()方法。

JS执行是单线程的,它是基于事件循环的。

  1. 所有同步任务都在主线程上执行,形成一个执行栈。
  2. 主线程之外,会存在- -个任务队列,只要异步任务有了结果,就在任务队列
    中放置一个事件。
  3. 当执行栈中的所有同步任务执行完后,就会读取任务队列。那些对应的异步
    任务,会结束等待状态,进入执行栈。
  4. 主线程不断重复第三步。

样式穿透

突破scoped的样式隔离,按需改变组件中引入的第三方组件

  1. 在父组件中使用>>>改变子组件样式(只作用于css);
  2. 在父组件中使用/deep/改变子组件样式(只作用于less);
  3. 在父组件中使用::v-deep改变子组件样式(只作用于sass);

组件

  1. 组件间通信
  2. 单向数据流

组件间通信

组件间通信的分类可以分成以下

  • 父子组件之间的通信
  • 兄弟组件之间的通信
  • 祖孙与后代组件之间的通信
  • 非关系组件间之间的通信

整理vue中8种常规的通信方案:

  1. 通过 props 传递
  2. 通过 $emit 触发自定义事件
  3. 使用 ref
  4. EventBus(全局事件总线)
  5. $parent 或$root
  6. attrs 与 listeners
  7. provide 与 inject
  8. Vuex
  • 父子组件通信
    • props$emit
    • ref
  • 兄弟组件通信
    • $bus
    • $parent
  • 祖先与后代组件通信
    • attrslisteners
    • provideinject
  • 复杂关系的组件通信
    • vuex存放共享的变量

1.1 props传递数据

  • 适用场景:父组件传递数据给子组件
  • 子组件设置props属性,定义接收父组件传递过来的参数
  • 父组件在使用子组件标签中通过字面量来传递值

Children.vue

props:{  
    // 字符串形式  
 name:String // 接收的类型参数  
    // 对象形式  
    age:{    
        type:Number, // 接收的类型为数值  
        defaule:18,  // 默认值为18  
       require:true // age属性必须传递  
    }  
} 

Father.vue

<Children name="jack" age=18 />  

1.2 $emit触发自定义事件

  • 适用场景:子组件传递数据给父组件
  • 子组件通过$emit触发自定义事件,$emit第二个参数为传递的数值
  • 父组件绑定监听器获取到子组件传递过来的参数

Children.vue

this.$emit('add', good) 

Father.vue

<Children @add="cartAdd($event)" />  

1.3 ref

  • 父组件在使用子组件的时候设置ref
  • 父组件通过设置子组件ref来获取数据

Father.vue

<Children ref="foo" />  
  
this.$refs.foo  // 获取子组件实例,通过子组件实例我们就能拿到对应的数据 

1.4 EventBus

  • 使用场景:兄弟组件传值
  • 创建一个中央事件总线EventBus
  • 兄弟组件通过$emit触发自定义事件,$emit第二个参数为传递的数值
  • 另一个兄弟组件通过$on监听自定义事件

main.js

new Vue({
	......
	beforeCreate() {
		Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
	},
    ......
}) 

组件A.vue

/* 组件A */
methods(){
  demo(data){......}
}
......
mounted() {
 // 绑定自定义事件,留下回调函数    
  this.$bus.$on('xxxx',this.demo)
}

组件B.vue

this.$bus.$emit('xxxx',数据)

最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件。

1.5 $parent或$root

  • 通过共同祖辈$parent或者$root搭建通信桥连

兄弟组件

this.$parent.on('add',this.add)

另一个兄弟组件

this.$parent.emit('add')

1.6 $attrs与$listeners

  • 适用场景:祖先传递数据给子孙
  • 设置批量向下传属性$attrs$listeners
  • 包含了父级作用域中不作为 prop 被识别 (且获取) 的特性绑定 ( class 和 style 除外)。
  • 可以通过 v-bind="$attrs" 传⼊内部组件
// child:并未在props中声明foo  
<p>{{$attrs.foo}}</p>  
  
// parent  
<HelloWorld foo="foo"/>  
// 给Grandson隔代传值,communication/index.vue  
<Child2 msg="lalala" @some-event="onSomeEvent"></Child2>  
  
// Child2做展开  
<Grandson v-bind="$attrs" v-on="$listeners"></Grandson>  
  
// Grandson使⽤  
<div @click="$emit('some-event', 'msg from grandson')">  
{{msg}}  
</div> 

1.7 provide与inject

  • 在祖先组件定义provide属性,返回传递的值
  • 在后代组件通过inject接收组件传递过来的值

祖先组件

provide(){  
    return {  
        foo:'foo'  
    }  
} 

后代组件

inject:['foo'] // 获取到祖先组件传递过来的值  

1.8 Vuex

  • 适用场景: 复杂关系的组件数据传递
  • Vuex作用相当于一个用来存储共享变量的容器

  • state用来存放共享变量的地方
  • getter,可以增加一个getter派生状态,(相当于store中的计算属性),用来获得共享变量的值
  • mutations用来存放修改state的方法。
  • actions也是用来存放修改state的方法,不过action是在mutations的基础上进行。常用来做一些异步操作

单向数据流

当父组件给子组件传递数据的时候,子组件只允许对数据进行读取,不允许修改数据,因为当子组件修改了父组件传过来的数据时,其他引用父组件数据的组件也会被修改,从而导致报错,然而也不知道是当前组件报错还是父组件报错还是修改父组件信息的子组件的错误;如果要修改可以通过this.$emit方法派发自定义事件,在父组件中修改;


生命周期

  1. 生命周期的节点方法
  2. 讲讲vue的生命周期
  3. 父子组件生命周期顺序
  4. 父子组件生命周期执行顺序,为什么要这样执行
  5. created mounted生命周期区别

Vue中实例从创建到销毁的过程就是生命周期,即指从创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程。

Vue生命周期总共可以分为8个阶段:创建前后, 载入前后,更新前后,销毁前销毁后,以及一些特殊场景的生命周期

生命周期 描述
beforeCreate 组件实例被创建之初
created 组件实例已经完全创建
beforeMount 组件挂载之前
mounted 组件挂载到实例上去之后
beforeUpdate 组件数据发生变化,更新之前
updated 组件数据更新之后
beforeDestroy 组件实例销毁之前
destroyed 组件实例销毁之后
activated keep-alive 缓存的组件激活时
deactivated keep-alive 缓存的组件停用时调用
errorCaptured 捕获一个来自子孙组件的错误时被调用

beforeCreate -> created

  • 初始化vue实例,进行数据观测

created

  • 完成数据观测,属性与方法的运算,watchevent事件回调的配置
  • 可调用methods中的方法,访问和修改data数据触发响应式渲染dom,可通过computedwatch完成数据计算
  • 此时vm.$el 并没有被创建

created -> beforeMount

  • 判断是否存在el选项,若不存在则停止编译,直到调用vm.$mount(el)才会继续编译
  • 优先级:render > template > outerHTML
  • vm.el获取到的是挂载DOM

beforeMount

  • 在此阶段可获取到vm.el
  • 此阶段vm.el虽已完成DOM初始化,但并未挂载在el选项上

beforeMount -> mounted

  • 此阶段vm.el完成挂载,vm.$el生成的DOM替换了el选项所对应的DOM

mounted

  • vm.el已完成DOM的挂载与渲染,此刻打印vm.$el,发现之前的挂载点及内容已被替换成新的DOM

beforeUpdate

  • 更新的数据必须是被渲染在模板上的(eltemplaterender之一)
  • 此时view层还未更新
  • 若在beforeUpdate中再次修改数据,不会再次触发更新方法

updated

  • 完成view层的更新
  • 若在updated中再次修改数据,会再次触发更新方法(beforeUpdateupdated

beforeDestroy

  • 实例被销毁前调用,此时实例属性与方法仍可访问

destroyed

  • 完全销毁一个实例。可清理它与其它实例的连接,解绑它的全部指令及事件监听器
  • 并不能清除DOM,仅仅销毁实例

使用场景分析

生命周期 描述
beforeCreate 执行时组件实例还未创建,通常用于插件开发中执行一些初始化任务
created 组件初始化完毕,各种数据可以使用,常用于异步数据获取
beforeMount 未执行渲染、更新,dom未创建
mounted 初始化结束,dom已创建,可用于获取访问数据和dom元素
beforeUpdate 更新前,可用于获取更新前各种状态
updated 更新后,所有状态已是最新
beforeDestroy 销毁前,可用于一些定时器或订阅的取消
destroyed 组件已销毁,作用同上

父子组件的生命周期

父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted->父beforeUpdate->子beforeUpdate->子updated->父updated->父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

References

  1. 面试官:请描述下你对vue生命周期的理解?在created和mounted这两个生命周期中请求数据有什么区别呢? | web前端面试 - 面试官系列 (vue3js.cn)
  2. Vue——父子组件的生命周期(执行顺序)_默默花上开的博客-CSDN博客_父子组件生命周期

虚拟DOM

什么是虚拟DOM

虚拟 DOM (Virtual DOM )这个概念相信大家都不陌生,从 ReactVue ,虚拟 DOM 为这两个框架都带来了跨平台的能力(React-NativeWeex)。

实际上它只是一层对真实DOM的抽象,是以JavaScript 对象 (VNode 节点) 作为基础的树,用对象的属性来描述节点,最终可以通过一系列操作使这棵树映射到真实DOM上。

Javascript对象中,虚拟DOM 表现为一个 Object对象。并且最少包含标签名 (tag)、属性 (attrs) 和子元素对象 (children) 三个属性,不同框架对这三个属性的命名可能会有差别。

创建虚拟DOM就是为了更好将虚拟的节点渲染到页面视图中,所以虚拟DOM对象的节点与真实DOM的属性一一照应。

通过VNodevue可以对这颗抽象树进行创建节点,删除节点以及修改节点的操作, 经过diff算法得出一些需要修改的最小单位,再更新视图,减少了dom操作,提高了性能。

为什么需要虚拟DOM

  1. 通过diff 算法,减少 JavaScript 操作真实 DOM 所带来的性能消耗。
  2. 虚拟 DOM 最大的优势在于抽象了原本的渲染过程,实现了跨平台的能力,而不仅仅局限于浏览器的 DOM,可以是安卓和 IOS 的原生组件,可以是小程序,也可以是各种GUI。

DOM是很慢的,其元素非常庞大,页面的性能问题,大部分都是由DOM操作引起的。

直接操作写真实的DOM会使页面性能下降,因为DOM节点的属性很多,直接操作DOM节点是比较耗时的,频繁操作还会出现页面卡顿,影响用户的体验。

真实的DOM节点,哪怕一个最简单的div也包含着很多属性,可以打印出来直观感受一下: img

举个例子:

你用传统的原生apijQuery去操作DOM时,浏览器会从构建DOM树开始从头到尾执行一遍流程

当你再一次操作时,需要更新10个DOM节点,浏览器没这么智能,收到第一个更新DOM请求后,并不知道后续还有9次更新操作,因此会马上执行流程,最终执行10次流程

而Vue通过VNode,同样更新10个DOM节点,虚拟DOM不会立即操作DOM,而是将这10次更新的diff内容保存到本地的一个js对象中,最终将这个js对象一次性attachDOM树上,避免大量的不需要的计算。

很多人认为虚拟 DOM 最大的优势是 diff 算法,减少 JavaScript 操作真实 DOM 的带来的性能消耗。虽然这是虚拟 DOM 带来的一个优势,但并不是全部。虚拟 DOM 最大的优势在于抽象了原本的渲染过程,实现了跨平台的能力,而不仅仅局限于浏览器的 DOM,可以是安卓和 IOS 的原生组件,可以是小程序,也可以是各种GUI。

如何实现虚拟DOM(源码)

createElement 创建 VNode 的过程,每个 VNodechildrenchildren 每个元素也是一个VNode,这样就形成了一个虚拟树结构,用于描述真实的DOM树结构

👉面试官:什么是虚拟DOM?如何实现一个虚拟DOM?说说你的思路 | web前端面试 - 面试官系列 (vue3js.cn)

diff算法

  1. Vue 中 key 的作用,为什么有高效性?(就地复用、Diff 算法
  2. vue的diff算法

diff 算法是一种通过同层的树节点进行比较的高效算法。在 vue 中,用于虚拟 dom 渲染成真实 dom 的新旧 VNode 节点比较

  • 比较只会在同层级进行, 不会跨层级比较;
  • 在diff比较的过程中,循环从两边向中间比较;

首先,我们拿到新旧节点的数组,然后初始化四个指针,分别指向新旧节点的开始位置和结束位置,进行两两对比,若是 新的开始节点和旧开始节点相同,则都向后面移动,若是结尾节点相匹配,则都前移指针。若是新开始节点和旧结尾节点匹配上了,则会将旧的结束节点移动到旧的开始节点前。若是旧开始节点和新的结束节点相匹配,则会将旧开始节点移动到旧结束节点的后面。若是上述节点都没配有匹配上,则会进行一个兜底逻辑的判断,判断开始节点是否在旧节点中,若是存在则复用,若是不存在则创建。最终跳出循环,进行裁剪或者新增,若是旧的开始节点小于旧的结束节点,则会删除之间的节点,反之则是新增新的开始节点到新的结束节点。

之前也是对vue的diff算法一知半解,现在对diff算法有了更深刻的理解。

ps: 之前被问过 vue 的diff算法是深度优先遍历还是广度优先算法,从图里是无法的得知的,在patchVnode过程中会调用updateChildren,所以 vue 的diff算法是个深度优先算法

👉References

  1. 面试官:你了解vue的diff算法吗?说说看 | web前端面试 - 面试官系列 (vue3js.cn)

  2. 面试官:说说vue的diff算法 - 掘金 (juejin.cn)


响应式原理

  1. Vue 响应式原理
  2. 使用过哪些vue指令
  3. v-show v-if的区别
  4. vue里style标签添加scoped属性是干嘛的?
    • 使用scoped,那么style标签里的样式只对当前组件生效,而不会影响到父子组件。
    • 样式穿透
  5. vue的watch,watch可以监听路由吗?可以监听url的参数吗?可以监听未双向绑定的数据吗?
    • watch可以监听路由;
    • 可以监听url的参数
    • watch只能监听双向绑定的数据
  6. Vue MVVM实现思路

data

  1. Vue实例,通过data传入的对象,Vue会遍历它所有的property,然后通过Object.defineProperty将每个属性修改为getter/setter,对外不可见。每个组件实例都有一个watcher实例,它会在组件渲染时将“接触”过的数据property记录为依赖,之后当依赖更新时(即触发setter),会通知watcher,从而让依赖这个数据的组件重新渲染。

  2. Vue更新DOM是异步执行的。只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。Vue 在内部对异步队列尝试使用原生的 Promise.thenMutationObserversetImmediate,如果执行环境不支持,则会采用 setTimeout(fn, 0) 代替。例如,当你设置 vm.someData = 'new value',该组件不会立即重新渲染。当刷新队列时,组件会在下一个事件循环“tick”中更新。多数情况我们不需要关心这个过程,但是如果你想基于更新后的 DOM 状态来做点什么,这就可能会有些棘手。虽然 Vue.js 通常鼓励开发人员使用“数据驱动”的方式思考,避免直接接触 DOM,但是有时我们必须要这么做。为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback)。这样回调函数将在 DOM 更新完成后被调用。


Vuex

  1. state了解吗
  2. props和state的区别
  3. vuex中mutation中可以执行异步吗

Vuex 是一个专为 Vue 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。

  1. Vuex 的状态存储是响应式的;当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新

  2. 改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation, 这样使得我们可以方便地跟踪每一个状态的变化 。

Vuex主要包括以下几个核心模块:

  1. State:定义了应用的状态数据

  2. Getter:在 store 中定义“getter”(可以认为是 store 的计算属性),就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来, 且只有当它的依赖值发生了改变才会被重新计算

  3. Mutation:是唯一更改 store 中状态的方法,且必须是同步函数 。(为什么?因为任何在回调函数中进行的状态的改变都是不可追踪的)

  4. Action:用于提交 mutation,而不是直接变更状态,可以包含任意异步操作

​ 5. Module:允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中。


vue-router

  1. 多路复用怎么实现的
  2. 路由的实现
  3. vue中的router有哪两种类型?(hash、history)区别是什么?
  4. vue的history和hash模式,底层是咋做的
  5. . 描述VueRouter如何实现单页
  6. 前端路由怎么实现的,原理。
  7. 前端路由有哪几种。

前端路由就是将之前服务端根据 url 的不同返回不同的页面的任务交给前端来做。

前端路由的实现原理其实很简单,本质上就是检测 URL 的变化,通过拦截 URL然后解析匹配路由规则。

前端路由

👉从路由到 vue-router 源码,带你吃透前端路由 - 掘金 (juejin.cn)

vue-router如何实现SPA

vue-router是Vue的官方路由,用来构建单页应用。

  1. 首先全局注册vue-router插件;
  2. 配置路由规则,即路由映射,不同的路径对应不同的组件
  3. 创建router实例。将router挂载到vue实例上,然后暴露该router实例。
  4. 在需要显示的组件中创建标签
  5. 当页面地址发生变化时,router-view会显示对应的内容。

路由守卫(重点)

路由守卫分为全局路由守卫、组件路由守卫、路由独享守卫

全局路由守卫:全局路由守卫为整个route设置。

独享路由守卫:独享路由守卫是在路由配置界面给某一个路由单独配置的守卫。

组件路由守卫:组件路由守卫是写在每个单独vue文件中的路由守卫。

全局路由守卫:(直接挂载到router实例上)

全局前置路由守卫(beforeEach):初始化的时候被调用、每次路由切换之前被调用,常用做登陆验证。

全局后置路由守卫(afterEach):初始化的时候被调用、每次路由切换之后被调用。

//语法:
router.beforeEach((to,from,next)=>{})
//全局前置路由守卫
router.beforeEach((to,from,next)=>{
  if(to.path == '/login' || to.path == '/register'){
    next();
  }else{
    alert('您还没有登录,请先登录');
    next('/login');
  }
})

独享路由守卫:(为每个路由单独添加)

钩子函数:

beforeEnter:在beforeEach之后执行,与它功能一样,只是,将其写进其中一个路由对象中,只在这个路由下起作用。

image-20220329151826414

组件路由守卫

钩子函数:

beforeRouteEnter	//	通过路由操作进入组件被触发
beforeRouteLeave	//	通过路由操作离开组件被触发

$route$router的区别(重点)

1、router是VueRouter的一个实例对象。这个对象是一个全局的对象,包含了所有路由的关键属性和对象。

举例:

history对象;比如:$router.push({path:‘home’}),本质是向history栈中添加一个路由,在我们看来是切换路由,但本质是添加一个history记录。

方法:$router.replace({path:‘home’}) //替换路由,没有历史记录。

2、route是一个跳转的路由对象,每一个路由都会有一个route对象,是一个局部的对象。可以获取对应的name、path、params

路由跳转方式

1、编程式:采用这种方式就需要导入 VueRouter 并调用了。

2、声明式:简单来说,就是使用 router-link 组件来导航,通过传入 to 属性指定跳转地址(router-link 默认会被渲染成一个a标签)。


状态管理


文章作者: elegantlee
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 elegantlee !
评论
  目录