Vue面试题(三阶段)

Day01

一、响应式原理

vue2响应式的原理是借助数据劫持发布订阅者模式

①数据劫持:

目的:能够感知到数据的改变。

数据劫持是:使用ES5的Object.defineProperty()。把data配置项中的所有数据进行遍历,转成setter和getter(或者说,给每个属性增加set和get函数)既就是:访问器属性。

②发布订阅者模式:

目的:当数据改变时,(直接和间接)使用该数据的模板处都会有相应的改变(模板会重新渲染)。

可能对方会进一步追问:能不能说的详细点。怎么回答?
      1)、
在vue构造函数里,循环变量data中所有属性。首先,保存属性的值,再利用Object.defineProperty()给每个属性增加set和get方法。然后,每个属性需要一个订阅对象,遍历dom树,让所有使用该属性的dom元素都订阅该属性。
      2)、当修改某个属性的值时,该属性的set函数就被调用,同时会调用所有订阅该属性的订阅者(函数)

class Vue {
    constructor(obj) {
        this.$el = obj.el;
        this.$data = obj.data;
        // 2.1、订阅(暂时写死,只订阅msg的变化)
        let observer1 = new Observer();
        observer1.addSubscribe(function (newVal) {
            document.getElementById("p01").innerHTML = newVal;
            document.getElementById("p02").innerHTML = newVal;
            document.getElementById("p03").innerHTML = newVal;
            console.log(newVal);
        });
        // 把data中的属性赋给this对象
        for (let key in obj.data) {
            // 保存数据(data中的每个属性的数据)。
            let value = obj.data[key];
            // 2.1、订阅(应该放在此处)
            // 1、数据劫持。
            Object.defineProperty(this, key, {
                set: function (val) {
                    console.log("val", val);
                    if (value == val) {
                        return;
                    }
                    value = val;
                    // 2.2、发布(更新使用key的dom元素)
                    observer1.publish(val);
                },
                get: function () {
                    return value
                }
            })
        }
        console.log("this", this);

        this.render();
    }
    render() {
        // this.$el
        let htmlStr = document.querySelector(this.$el).innerHTML;

        for (let key in this.$data) {
            htmlStr = htmlStr.replaceAll("{
   
   {" + key + "}}", this.$data[key]);
        }
        document.querySelector(this.$el).innerHTML = htmlStr;
    }
}
// 发布订阅模式的代码。
class Observer {
    constructor() {
        // 存放所有的订阅
        this.arr = [];
    }
    // (添加)订阅
    addSubscribe(cb) {
        this.arr.push(cb);
    }
    // 发布
    publish(what) {
        this.arr.forEach(cb => {
            (typeof cb === "function") && cb(what);
        })
    }
}

二、v-if和v-show区别

相同点:

( 都是控制 dom元素的显示和隐藏的)

不同点:

①原理不同:
     ​ v-if是通过dom元素的删除和添加,来完成显示和隐藏,

     ​ v-show是通过修改样式属性display的值,来完成显示和隐藏。

②性能消耗的不同
      v-if:性能损耗主要体现在频繁切换时

     ​ v-show:性能损耗主要体现在首次

③使用场景的不同
       v-if:用于切换不频繁的场景

     ​ v-show:用于切换频繁的场景。

④安全性的不同
     ​ v-if:安全性好(如果dom元素不显示时,在elements里根本看不到)

     ​ v-show:安全性不好。(如果dom元素不显示时,在elements里依然可以看到,那么,懂程序 的人,即可以修改)

三、为什么不建议v-for与v-if连用

①原因:

     v-for的优先级比v-if优先级高,如果满足条件的数据相对(原始数据)较少,那么会造成大量性能浪费

②解决方案:

在computed里,先把满足条件的数据过滤出来。然后,v-for直接循环过滤出来的数据。而computed是有缓存的,所以,在原始数据没有变化时,不会多次过滤数据,这样,就提高了效率

//所以可以采取以下做法,先判断v-if
<div id="app">
    <ul v-if="flag">
        <li v-for="(item,index) in arr">{
   
   {index}}---{
   
   {item}}</li>
    </ul>
</div>
<script>
    var app = new Vue({
        el: '#app',
        data: {
            flag: true,
            arr: ['h', 'e', 'l', 'l', 'o']
        }
    })
</script>

Day02

一、双向的绑定原理

1、双向:M---->V   V---->M

2、利用事件和属性完成的。

3、v-model是个语法糖。本质就是事件和属性的结合。

      1)、针对文本框(单行和多行): value属性和input事件。如果加上修饰符lazy。事件变成了change事件。

      2)、针对radio:使用的checked属性和change事件,同时需要给radio加上value属性

      3)、针对checkbox:使用的checked属性和change事件

             3.1)、如果应用在多选时,需要给checkbox加上value属性

             3.2)、如果应用在单选时,不需要加

      4)、针对select:使用value属性和change事件

v-model用在radio上的本质

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
    </style>
</head>
<body>
    <div id="app">
        性别:
        <input type="radio"  v-bind:checked="sex=='女'"  @change="changeSex" value="女" >女
        <input type="radio"  v-bind:checked="sex=='男'" @change="changeSex" value="男" >男
        <hr/>
        性别:
        <input type="radio"  v-model="sex" value="女" >女
        <input type="radio"  v-model="sex" value="男">男
        <p>已选择的性别:{
   
   {sex}}</p>
    </div>
</body>
</html>
<script src="./js/vue2.js"></script>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            sex:"女"
        },
        methods: {
          changeSex(e){
            this.sex = e.target.value;
          }
        }
    });
</script>

v-model用在checkbox上的本质

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="app">
        爱好:
        <input type="checkbox" :checked="hobbys.includes('篮球')" @change="changeHobby" value="篮球">篮球
        <input type="checkbox" :checked="hobbys.includes('足球')" @change="changeHobby" value="足球">足球
        <input type="checkbox" :checked="hobbys.includes('乒乓球')" @change="changeHobby" value="乒乓球">乒乓球
        <hr />
        <input type="checkbox" v-model="hobbys" value="篮球">篮球
        <input type="checkbox" v-model="hobbys" value="足球">足球
        <input type="checkbox" v-model="hobbys" value="乒乓球">乒乓球
        <p>爱好:{
   
   {hobbys}}</p>
    </div>
</body>
</html>
<script src="./js/vue2.js"></script>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            hobbys: ['足球']
        },
        methods: {
            changeHobby(e) {
                //    if(this.hobbys.includes(e.target.value)){
                //       this.hobbys = this.hobbys.filter(item=>item!=e.target.value);
                //    }else{
                //       this.hobbys.push(e.target.value);
                //    }
                let idx = this.hobbys.indexOf(e.target.value);
                if (idx == -1) {
                    this.hobbys.push(e.target.value);
                } else {
                    this.hobbys.splice(idx, 1);
                }
            }
        }
    });
</script>

v-model在checkbox上使用(单个复选框) 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="app">
        <input type="checkbox" :checked="isRead" @change="changeRead">已阅读协议;
        <hr />
        <input type="checkbox" v-model="isRead">已阅读协议;
        <p>阅读协议:{
   
   {isRead}}</p>
        <hr />
        <input type="checkbox" :checked="isRead2=='yes'" @change="changeRead2" true-value="yes" false-value="no">已阅读协议;
        <input type="checkbox" v-model="isRead2" true-value="yes" false-value="no">已阅读协议;
        <p>阅读协议:{
   
   {isRead2}}</p>
    </div>
</body>
</html>
<script src="./js/vue2.js"></script>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            isRead: false,
            isRead2: "no",
        },
        methods: {
            changeRead() {
                this.isRead = !this.isRead;
            },
            changeRead2(e) {
                // this.isRead2 = (this.isRead2=='yes'?'no':'yes')
                this.isRead2 = (this.isRead2 == e.target.getAttribute("true-value") ? e.target.getAttribute("false-value") : e.target.getAttribute("true-value"))
            }
        }
    });
</script>

Day03

一、computed和watch的区别

①相同点:都可以监听数据

②不同点:

    1)、概念:

     computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,当依赖的属性值发生改变时,才会重新计算 computed 的值,默认是只读的(相当于getter函数),它也可以设置getter和setter函数来完成读和写。

     watch:更多的是观察的作用,每当监听的数据变化时都会执行回调进行后续操作,它只能设置getter。watch默认只监听一层。如果要深度监听,让deep属性为true。

    2)、作用:

     computed:是为了显示而用,降低了模板上代码复杂度。

     watch:属性变化的检测(相当于事件),当属性的值发生变化时,可以调用函数。

    3)、依赖模板调用:

     computed:只能在模板上使用。

     watch:不能在模板上使用。

    4)、是否异步:

     computed:不能有异步,只能同步。

     watch:可以有异步。

二、什么是虚拟dom

所谓的虚拟 dom,也就是我们常说的虚拟节点,它是通过IS的Obiect对象模拟DOM中的节点,然后再通过特定的render (渲染) 方法将其演染成真实的DOM的节点。

三、如何实现深度监听

首先,新建一个html项目,并在项目中引入vue

引入wue后,在项目中定义一个监听对象

监听对象定义好后,使用watch方法对整个对象进行监听

最后,监听事件设置好后,在事件中添加一个deep属性,并设置为true,即可实现深度监听

(先定义监听对象,使用watch方法对整个对象进行监听,在事件中添加一个deep属性,并设置为true,即可实现深度监听)

四、过滤器怎么理解

过滤器是用来专门做数据格式转换的。如:文本的格式化

①定义指令

    1)、全局定义:Vue.filter(“过滤器名”,过滤器函数(原始数据,))

    2)、局部定义:在Vue对象里的filters配置项里写

②使用指令:

在模板上使用,用管道符。管道符前面 弓原始数据,管道符后面是过滤器的调用(就是 函数的调用)

过滤器的应用场景:平常在开发中,过滤器的应用场景有很多,比如单位转换、文本格式化、时间

格式化之类的等

五、this的理解?

①是什么?

this是函数的内置对象。this是代名词。this代表谁,需要看场景(上下文),在js中函数就是this的场景。所以,this一般都是出现在函数内部(其实这个本质是作用域)。

②this的几种情况(静态的描述) 以下情况所说的函数是非箭头函数。

   1)、当this所在函数是事件处理函数时,this表示事件源。

   2)、当this所在函数是构造函数时,this表示new出来的对象。

   3)、当this所在函数是实例(对象)的方法时,this表示调用该方法的对象。

   4)、当this所在函数是全局声明的函数时,

         4.1)、非严格模式下:this表示window。(其实这个点和第三点一样)。因为,全局函数都是window对象的方法

         4.2)、严格模式下:this是undefined。

   5)、this在script标签里,表示window。

③真正的this,需要看调用(深深的知道就行,面试时,可以不用回答这个)。

   1)、call,apply,bind是可以改变this指向的。

   2)、所谓的构造函数,我也可以不用new调用把。

   3)、所谓的全局函数,我也可以把它赋给事件属性。

④箭头函数是没有this的。

既就是:在判断this指向时,不要把箭头函数当函数看待。

一般人我不告诉他:箭头函数在编译的原理里是词法分析域

Day04

一、请问你怎么理解虚拟DOM和diff算法

所谓的虚拟 dom,也就是我们常说的虚拟节点,它是通过JS的Object对象模拟DOM 中的节点,然后再通过特定的render(渲染)方法将其渲染成真实的DOM节点

①什么是虚拟dom和diff算法:

虚拟DOM: 用JSON对象模拟的真实dom,用来提升性能(减少重绘回流)

diff算法:用来比较两个虚拟dom的不同之处。

②步骤(思路,流程)

   2.1)、产生两个虚拟DOM树:newVDom,oldVDom。

   2.2)、oldVDom和真实DOM保持一致

   2.3)、数据变化时,影响的是(操作的是)newVDom

   2.4)、操作newVDom后,通过diff算法对比newVDom和oldVDom的差异,并在oldVDom标注哪些节点要删除,哪些节点要增加,修改

   2.5)、根据oldVDom操作真实的DOM,让真实Dom和oldVDom保持一致

③diff算法的解释:

逐步解析newVdom的节点,找到它在oldVdom中的位置,如果找到了就移动到下一个的DOM元素,如果没找到说明是新增节点,则新建一个节点插入。遍历完成之后如果oldVdom中还 没处理过的节点,则说明这些节点在newVdom中被删除了,删除它们即可。

二、单向数据流

父----->子 的数据传递是可以的。反之不行。

Prop(property的简写) 是单向绑定的:当父组件的属性(数据)变化时,将传导给子组件,但是反过来不会。这是为了防止子组件无意间修改了父组件的状态,来避免应用的数据流变得难以理解。 ​ 另外,每次父组件更新时,子组件的所有 prop 都会更新为最新值。这意味着你不应该在子组件内部改变 prop。如果你这么做了,Vue 会在控制台给出警告。

总结:

组件就是标签,prop是标签的属性。

prop是外部传入的数据,data是组件内部的数据。

三、data是个函数,vue组件的data为什么是个函数

​一个组件的 data 选项必须是一个函数,且要有返回object(就是vue对象的data),只有这样,每个实例(vue组件对象)就可以维护一份被返回对象的独立的拷贝,否则,组件复用时,数据相互影响。即:组件的作用域(应该)是独立的。

​简单回答:如果不是函数,那么,复用的组件的data共享同一块内存空间。

Day06

一、组件间通信:

①父子组件传值

    1)、父--->子传:props,ref

    ref:引用,通过ref可以找到子组件对象。ref跟原生中获得dom(如:getElementById)是一样的道理.需要品一段文字:自定义标签就是标签,js中获取dom就是在获取标签。组件就是dom对象

    this.$refs.sonRef;// 等价于 document.getElementById("sonId");

    通过this.$refs.sonRef,获取了dom对象,也就是相当于获取了子组件对象。

    this.$refs.sonRef 就等价于子组件里的this【这句话一定要理解】

 

    2)、子--->父传:emit

②兄弟组件

    1)、子1--->父--->子2

    2)、事件总线(event-bus)

原理:使用vue对象的$on和$emit完成。

具体做法:假设SonA给SonB传递数据。新建一个空的vue对象。在SonA里和SonB引入该vue对象。

$emit:触发事件(在SonA)

$on:绑定事件(在SonB)

二、ajax中的readyState和status

①readyState是什么意思:

readyState:是表示请求和响应过程中的状态(进行到了哪一步)。

0:未初始化,【XMLHttpRequest对象创建完毕】

1:初始化,【调用open完毕】

2:后端接收到请求,

3:后端正在处理

4:后端响应回来。

②status是什么意思:

status:表示响应结果的描述

200:(成功) 服务器已成功处理了请求这表示服务器提供了请求的网页。

400:(错误请求) 服务器不理解请求的语法

401:(未授权) 请求要求身份验证。

403:(禁止) 服务器拒绝请求

404:(未找到) 服务器找不到请求的网页

408:(请求超时) 服务器等候请求时发生超时

500:(服务器内部错误) 服务器遇到错误,无法完成请求

502:(错误网关) 服务器作为网关或代理,从上游服务器收到无效响应

503:(服务不可用)服务器目前无法使用 (由于超载或停机维护) 。通常,这只是暂时状态

504:(网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求

505:(HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本

三、原型和原型链

①原型:

    1)、每个构造函数(类)都会有一个原型属性(prototype)。

    2)、原型属性的目的:

让所有实例共享属性和方法,共享的是构造函数(类)的原型属性(prototype)上的属性和方法。由此,节约了内存。实例是通过 __proto__属性找到构造函数(类)的prototype属性的。

    3)、原型属性里还有一个constructor属性,指向构造函数(类)本身。

②原型链:

当使用对象访问属性或者方法时,先从对象本身的内存中寻找,如果找不到,就去 __proto__(原型)指向的内存中(类的prototype)寻找,如果找不到,则在类的原型的 __proto__(父类的prototype)寻找,以此类推,一直找到Object,如果没有找到,则显示出错(如: is not defined,或者 is not a function等等)。

这种一直沿着属性 __proto__ 朝上寻找,就是原型链的寻找。也就是原型链的意思。

Day07

一、对MVC,MVP,MVVM的理解

三者都是项目的架构模式(不是类的设计模式),即:一个项目的结构,如果分层,不同层负责不同的职责。

①MVC:

MVC的出现是用在后端(全栈时代)

M:model,模型:

主要完成业务功能,在数据库相关的项目中,数据库的增删改查属于模型(重点)。(nodeJS中的db文件夹),没有页面,是纯粹的逻辑

V:view,视图:

主要负责数据的显示(HTML+CSS,动态网页(jsp,含有html的php文件))页面的展示和用户的交互。

C:controller,控制器:

主要负责每个业务的核心流程,在项目中体现在路由以及中间件上(nodeJS中的routes文件夹)

②MVP

MVP是把MVC中的C改成了P。主要限制了M和V之间不能直接通信(互相调用,传递数据)。M和V之间的通信必须经过P。

P:Presenter,表示器

主要用于连接M层、V层,完成Model层与View层的交互,还可以进行业务逻辑的处理。

③MVVM:

MVVM是把MVP中P改成了VM。主要体现的是MV之间和双向绑定。View的变动可以同步响应在Model,反之亦然。Vue就是一个MVVM的框架。准确来说,使用Vue框架完成项目时,使用的是MVVM模式。

VM:ViewModel

主要完成MV的数据通信,并且是双向绑定。而 View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作 DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。

二、vue2,vue3的(组件对象的)生命周期【第四点不同】

①什么是生命周期

vue对象(组件)的生命周期,就是从创建,挂载,渲染,更新,到销毁的一系列过程。就是生命周期。

②vue2的生命周期有四个阶段和八个钩子函数

第一个阶段:数据挂载阶段。数据挂载阶段是把data配置项的属性挂载到vue对象本身。并做劫持

                      前后分别有一个钩子函数: beforeCreate,created

第二个阶段:模板渲染阶段:把数据渲染(显示)在模板上。

                      前后分别有一个钩子函数: beforeMount,mounted

第三个阶段:模板更新阶段:当数据(在模板上使用的数据)发生改变时,会把新的数据渲染到模板上。

                      前后分别有一个钩子函数:beforeUpdate,updated

vue2:

第四个阶段:组件销毁:前后分别有一个钩子函数:beforeDestroy 和 destroyed

vue3:

第四个阶段:组件销毁:【只有这一点和vue2不一样】

                     前后分别有一个钩子函数:beforeUnmount 和 unmounted

Day08

一、keep-alive

keep-alive 可以缓存组件及其状态 (数据),避免了组件的频警创建和销毁所带来的性能损耗。

它有三个特性:

用于缓存组件,一般结合路由和动态组件一起使用。

提供 include 和 exclude 属性。两者都支持字符中或正则表达式,include 表示只有名称匹配的组件会被缓存,exclude 表示任何名称匹配的组件都不会被缓存,其中 exclude 的优先级比 include 高
这两个 prop 的值都可以是一个以英文过号分隔的字符串、一个正则表达式,或是包含这两种类型的一个数组:它会根据组件的 name 选项进行匹配,所以组件如果想要条件性地破 Keeplive 级存,就必须显式声明一个 name选项。

对应两个钩子函数 activated 和 deactivated,当组件被激活时,触发钩子函数 activated,当组件被移除时,触发钩了函数 deactivated。

二、Vue 的父组件和子组件生命周期钩子函数执行顺序?

Vue 的父子组件钩子函数的执行顶序可以归类为4个 部分:

第一部分:首次加载渲染

父 beforeCreate ->父 created > 父 beforeMount -> 子 beforeCreate -> 子 created >子

beforeMount -> 子mounted -> 父mounted.

第二部分: 父组件修改子组件的props值时

父 beforeUpdate -> 子 beforeUpdate -> 子updated -> 父 updated

第三部分:父组件修政的数据跟子组件没有关系时

不会影响了组件 父 beforeUpdate ->父 updated

第四部分:销毁过程

beforeDestroy ->子beforeDestroy ->子destroyed -> 父 destroyed

Day09

 一、axios的拦截器

①axios拦截器是什么?

    拦截器是在前后端交互(请求和响应)到达对方之前调用的回调函数。所有的请求都会调用该回调函数

②拦截器分为:

    请求拦截器:请求到达后端前调用的回调函数
    响应拦截器:响应到达前端前调用的回调函数

③拦截器解决的问题:

    1)、请求拦截器: 能够处理所有请求(到达后端前)的公共业务,如: 携带token,loading的显示,请求体加验证、设置请求头等等。针对不同请求类型做不同类型的处理等等。
    2)、响应拦截器:能够处理所有响应(到达前端的then 或 catch) 的公共业务,如:数据统一处理,响应的错误状态码,loading的隐藏等等。

Day10

一、$router和$route的区别

$router是vue-router对象,是创建的vue-router对象,该对象具有路由相关api,如: push( ),

replace ( ) go(), back(), forward()

$route是匹配到的路由对象。当地址栏的路径发生变化时,会匹配某个路由配置。然后,vue-router对象就会在组件上去产生一个$route对象,来保存匹配到的路由的相关信息,包括:传递的参数,路由元信息等(如:path,params,query等等)

二、两种路由模式的区别

外观上的区别: 1)、hash有# 2)、history没有#

原理上的区别:

   1)、hash用的是锚点连接。背后使用location.href和window.hashchange事件。锚点连接自带历史记录。

   2)、history背后用的是history.pushState 来记录页面的历史记录。

跟后端有关的区别:

   1)、hash和后端没有关系

   2)、history和后端有关系。当地址栏发生变化后,浏览器默认会发送请求给服务器(服务器上的资源html,css,js,api接口,后端渲染的页面,等等),所以,当前后端不分离时: 需要保证前端路径和后端的api或者后端渲染的页面不要重名。另外,前后端分离,前端服务器需要配置一个针对404页面时,返回index.html.

三、路由传参

vue-router有两种传参方式:params和query。

params

首先,需要在路由配置中使用动态路由匹配{path:“/路径/:参数名”,name:"路由名”}

1)、传(跳转时传,编程式和声明市相同)

//声明式:
1)、字符串写法
<router-link to="/路径/参数的值"></router-link>
//编程式:
this.$router.push("/user /01001");
2、对象写法
<router-link :to="{name:路由名,params:{参数名:参数值}}"></router-link>
//编程
this.$router.push({ name: user', params: { id:  01001' }})

2)、接[路由的组件内部接收]

this,$route.params,参数名

queny

1)、

//声明式
//1)、字符串写法:
<router-link to=路径?参数名1=参数值&参数名2=参数值2”></router-link>
//2) 对象写法:
<router-link :to="{path路径?参数名1=参数值&参数名2=参数价2}}"></router-link>
//编程式
                   同上

2)、

this.$route.query.参数名

Day11

一、路由懒加载(按需加载)

①为什么要用

减轻服务器压力,加快页面呈现速度,对象的实例化在getter方法中,各司其职,降低耦合性.

②什么是

懒加载其实就是延时加载,即当对象需要用到的时候再去加载相关的对象

③解决方案

  • vue异步组件

  • es 的 import()

  • webpack的require.ensure()

二、路由守卫

①什么是路由守卫

控制组件的跳转,对是否能够进入某个路径对应组件做限制。根据业务逻辑来判定是否可以进入某个组件。

②路由守卫有哪些分类

   1)、全局守卫

          1.1)、前置钩子 : beforeEach

          1.2)、后置钩子:afterEach

    2)、路由独享守卫

           2.1)、只有前置: beforeEnter

    3)、组件内部守卫

           3.1)、前置 : beforeRouteEnter

           3.2)、路径更新,组件复用 :beforeRouteUpdate

           3.3)、离开:beforeRouteLeave

③路由钩子函数的参数:

to:要跳转到的路由(路由对象信息)目标

from:从哪里跳转的路由 (路由对象信息)来源

next: 函数体必须要next()才会让路由正常地跳转和切换,next(false)在原地停留,next(“强制修改到另一个路由路径上”

Day12

一、vuex

①vuex是什么

vuex是一个状态(数据)管理工具,它能够完成组件之间的数据共享(组件的通信)

②vuex的作用

    1)、vuex能够保存全局数据(数据仓库),供整个应用使用

    2)、vuex保存的数据是响应式的

    3)、vuex保存的数据可以跟踪状态的变化

③vuex的(核心概念)配置项:

    1)、state : 数据仓库 ,存储所有的 共享数据 ,相当于vue组件里的data

    2)、Getters : 在state的基础上 派生的数据, 相当于vue组件里 computed

    3)、Mutations:修改state的数据时,用mutation,这与跟踪状态 有关系,只能有同步代码

    4)、Action:解决mutation里只能有同步代码的问题,action里可以有异步代码

    5)、modules:模块化

④vuex的数据流转

vue组件 派发(dispatch)actionaction里提交(commit)mutation,mutation里修改(mutate)state的数据,state的数修改后,会响应式渲染到模板上。

⑤模块化怎么使用

    1)、当项目比较大时,所有的全局数据存放在state里,会非常混乱,怎么办?使用module,把数据分门别类的进行处理,即:模块化。 每个模块是一个独立的store。然后由总体的store引入所有的分模块store。

    2)、怎么解决(getters,mutations,actions)的重名

             2.1)、namespaced:true

             2.2)、使用模块中getters,mutations,actions时,前面需要加上模块名:

格式:

模块名/getters或者mutations或者actions的名字

⑥辅助函数:

mapState, mapGetters,mapMutations, mapActions

   1)、作用:

简化代码:在组件里不需要使用$store 了。

   2)、具体使用:

mapState, mapGetters 会映射到组件的computed上

mapMutations, mapActions 会映射到组件的methods里。

Day13

$nextTick的实现原理:

①为什么用Vue.nextTick()

首先,JS是单线程的,那么,它如何处理异步操作。

所有同步任务都在主线程上执行,形成一个执行栈。

主线程之外,会存在一个任务队列,只要异步任务有了结果,就在任务队列中放置一个事件(所以,也叫事件队列),进行排队(处于等待状态)。

当执行栈中的所有同步任务执行完后,就会读取任务队列(事件队列)中的任务(事件)。即:任务队列中的任务就结束了等待状态,进入执行栈。

主线程不断重复第三步。直到任务队列和执行栈里的代码执行完毕。

了解一个事件循环: javascript的事件循环(event loop)_jiang7701037的博客-CSDN博客

其次,vue更新DOM的思路。使用的就是异步更新队列,所以,就使用了事件循环。目的是提高性能,避免无效的重复的DOM更新。即:vue中更新数据后,并不会立即更新DOM,而是把数据引起的DOM更新放入到异步更新队列里。等待下次事件循环(tick),并在两个tick之间进行UI渲染。这样程序员就不能在更改数据后,立即获取更新后的DOM,也不知道什么时候DOM能够更新。基于此,vue提供了nextTick函数。程序员把操作更新后DOM的代码放入到nextTick的回调函数里。由nextTick内部,在更新完DOM后,调用回调函数。 示例代码:

this.msg = "hello"
this.$nextTick(()=>{
     操作更新后DOM的代码。
});

②什么是Vue.nextTick()

Vue.nextTick的代码思路示意

function nextTick(cb){
    //DOM 更新
    cb();
}

那么,vue是如何知道DOM更新了?

MutationObserver:这是HTML5新增的API。用于监视DOM变动的接口,它可以监听一个DOM对象上发生的子节点删除、属性修改、文本内容修改等

另外,考虑到,微任务比宏任务耗时少,浏览器的兼容性。所以,vue中延迟调用优先级如下: Promise > MutationObserver > setImmediate > setTimeout

③应用场景:

答:当需要操作 ”数据更新影响的(新的)dom时“,就使用$nextTick()。而且,必须在数据更新后立即调用$nextTick();

​ 换种说法:当需要操作dom,而且这个dom是由于数据更新(修改)后引起重新渲染的dom。

你可以这么认为,$nextTick(cb); 是updated,是某个数据引起的updated,而不是所有数据引起的updated

SPA的理解

①单页面应用的概念

SPA:single page application,单页面应用。

就是整个项目就只有一个html页面(文件),首次加载时,把所有的html,css,js全部加载下来。通过操作dom的删除和创建(添加)来完成页面的切换。

②单页面应用优缺点

优点:

    1)、单页应用相对服务器压力小。【因为:首次、或者只要HTML,CSS和JS加载完毕后,切换页面是不用再去服务器请求HTML,CSS和JS】

    2)、局部刷新,所以,用户体验好。【通过删除、添加、修改DOM的方式】

   ​ 3)、前后端分离 ​

    4)、页面效果会比较炫酷(比如切换页面内容时的转场动画)

缺点:

    1)、不利于SEO(Search Engine Optimization)。如:百度,360等搜索引擎收录。

    2)、初次加载时耗时多(可以使用路由懒加载解决)

    3)、导航不可用,如果一定要导航需要自行实现前进、后退(vue-router做好了)。页面复杂度提高很多

    4)、容易造成CSS命名冲突。【用scoped或者BEM的方式解决】

猜你喜欢

转载自blog.csdn.net/weixin_72756818/article/details/130206692