关于前端:前端必会vue面试题必备

Vuex有哪几种属性?

有五种,别离是 State、 Getter、Mutation 、Action、 Module

  • state => 根本数据(数据源寄存地)
  • getters => 从根本数据派生进去的数据
  • mutations => 提交更改数据的办法,同步
  • actions => 像一个装璜器,包裹mutations,使之能够异步。
  • modules => 模块化Vuex

Vue.js的template编译

简而言之,就是先转化成AST树,再失去的render函数返回VNode(Vue的虚构DOM节点),具体步骤如下:

首先,通过compile编译器把template编译成AST语法树(abstract syntax tree 即 源代码的形象语法结构的树状表现形式),compile是createCompiler的返回值,createCompiler是用以创立编译器的。另外compile还负责合并option。

而后,AST会通过generate(将AST语法树转化成render funtion字符串的过程)失去render函数,render的返回值是VNode,VNode是Vue的虚构DOM节点,外面有(标签名、子节点、文本等等)

Vue 中 computed 和 watch 有什么区别?

计算属性 computed

 (1)**反对缓存**,只有依赖数据发生变化时,才会从新进行计算函数;
 (2)计算属性内**不反对异步操作**;
 (3)计算属性的函数中**都有一个 get**(默认具备,获取计算属性)**和 set**(手动增加,设置计算属性)办法;
 (4)计算属性是主动监听依赖值的变动,从而动静返回内容。

侦听属性 watch

 (1)**不反对缓存**,只有数据发生变化,就会执行侦听函数;
 (2)侦听属性内**反对异步操作**;
 (3)侦听属性的值**能够是一个对象,接管 handler 回调,deep,immediate 三个属性**;
 (3)监听是一个过程,在监听的值变动时,能够触发一个回调,并**做一些其余事件**。


vue初始化页面闪动问题

应用vue开发时,在vue初始化之前,因为div是不归vue管的,所以咱们写的代码在还没有解析的状况下会容易呈现花屏景象,看到相似于{{message}}的字样,尽管个别状况下这个工夫很短暂,然而还是有必要让解决这个问题的。

首先:在css里加上以下代码:

[v-cloak] {    display: none;}

如果没有彻底解决问题,则在根元素加上style="display: none;" :style="{display: 'block'}"

Vue中的key到底有什么用?

key是为Vue中的vnode标记的惟一id,通过这个key,咱们的diff操作能够更精确、更疾速

diff算法的过程中,先会进行新旧节点的首尾穿插比照,当无奈匹配的时候会用新节点的key与旧节点进行比对,而后超出差别.

diff程能够概括为:oldCh和newCh各有两个头尾的变量StartIdx和EndIdx,它们的2个变量互相比拟,一共有4种比拟形式。如果4种比拟都没匹配,如果设置了key,就会用key进行比拟,在比拟的过程中,变量会往两头靠,一旦StartIdx>EndIdx表明oldCh和newCh至多有一个曾经遍历完了,就会完结比拟,这四种比拟形式就是首、尾、旧尾新头、旧头新尾.

  • 精确: 如果不加key,那么vue会抉择复用节点(Vue的就地更新策略),导致之前节点的状态被保留下来,会产生一系列的bug.
  • 疾速: key的唯一性能够被Map数据结构充分利用,相比于遍历查找的工夫复杂度O(n),Map的工夫复杂度仅仅为O(1).

Vue中如何进行依赖收集?

  • 每个属性都有本人的dep属性,寄存他所依赖的watcher,当属性变动之后会告诉本人对应的watcher去更新
  • 默认会在初始化时调用render函数,此时会触发属性依赖收集 dep.depend
  • 当属性产生批改时会触发watcher更新dep.notify()

依赖收集简版

let obj = { name: 'poetry', age: 20 };

class Dep {
    constructor() {
      this.subs = [] // subs [watcher]
    }
    depend() {
      this.subs.push(Dep.target)
    }
    notify() {
      this.subs.forEach(watcher => watcher.update())
    }
}
Dep.target = null;
observer(obj); // 响应式属性劫持

// 依赖收集  所有属性都会减少一个dep属性,
// 当渲染的时候取值了 ,这个dep属性 就会将渲染的watcher收集起来
// 数据更新 会让watcher从新执行

// 观察者模式

// 渲染组件时 会创立watcher
class Watcher {
    constructor(render) {
      this.get();
    }
    get() {
      Dep.target = this;
      render(); // 执行render
      Dep.target = null;
    }
    update() {
      this.get();
    }
}
const render = () => {
    console.log(obj.name); // obj.name => get办法
}

// 组件是watcher、计算属性是watcher
new Watcher(render);

function observer(value) { // proxy reflect
    if (typeof value === 'object' && typeof value !== null)
    for (let key in value) {
        defineReactive(value, key, value[key]);
    }
}
function defineReactive(obj, key, value) {
    // 创立一个dep
    let dep = new Dep();

    // 递归察看子属性
    observer(value);

    Object.defineProperty(obj, key, {
        get() { // 收集对应的key 在哪个办法(组件)中被应用
            if (Dep.target) { // watcher
                dep.depend(); // 这里会建设 dep 和watcher的关系
            }
            return value;
        },
        set(newValue) {
            if (newValue !== value) {
                observer(newValue);
                value = newValue; // 让key对应的办法(组件从新渲染)从新执行
                dep.notify()
            }
        }
    })
}

// 模仿数据获取,触发getter
obj.name = 'poetries'

// 一个属性一个dep,一个属性能够对应多个watcher(一个属性能够在任何组件中应用、在多个组件中应用)
// 一个dep 对应多个watcher 
// 一个watcher 对应多个dep (一个视图对应多个属性)
// dep 和 watcher是多对多的关系

参考 前端进阶面试题具体解答

diff算法

工夫复杂度: 个树的齐全 diff 算法是一个工夫复杂度为 O(n*3) ,vue进行优化转化成 O(n)

了解:

  • 最小量更新, key 很重要。这个能够是这个节点的惟一标识,通知 diff 算法,在更改前后它们是同一个DOM节点

    • 扩大 v-for 为什么要有 key ,没有 key 会暴力复用,举例子的话轻易说一个比方挪动节点或者减少节点(批改DOM),加 key 只会挪动缩小操作DOM。
  • 只有是同一个虚构节点才会进行精细化比拟,否则就是暴力删除旧的,插入新的。
  • 只进行同层比拟,不会进行跨层比拟。

diff算法的优化策略:四种命中查找,四个指针

  1. 旧前与新前(先比结尾,后插入和删除节点的这种状况)
  2. 旧后与新后(比结尾,前插入或删除的状况)
  3. 旧前与新后(头与尾比,此种产生了,波及挪动节点,那么新前指向的节点,挪动到旧后之后)
  4. 旧后与新前(尾与头比,此种产生了,波及挪动节点,那么新前指向的节点,挪动到旧前之前)

$nextTick 是什么?

Vue 实现响应式并不是在数据产生后立刻更新 DOM,应用 vm.$nextTick 是在下次 DOM 更新循环完结之后立刻执行提早回调。在批改数据之后应用,则能够在回调中获取更新后的 DOM

谈谈你对MVVM的了解

为什么要有这些模式,目标:职责划分、分层(将Model层、View层进行分类)借鉴后端思维,对于前端而已,就是如何将数据同步到页面上

MVC模式 代表:Backbone + underscore + jquery

  • 传统的 MVC 指的是,用户操作会申请服务端路由,路由会调用对应的控制器来解决,控制器会获取数据。将后果返回给前端,页面从新渲染
  • MVVM:传统的前端会将数据手动渲染到页面上, MVVM 模式不须要用户收到操作 dom 元素,将数据绑定到 viewModel 层上,会主动将数据渲染到页面中,视图变动会告诉 viewModel层 更新数据。ViewModel 就是咱们 MVVM 模式中的桥梁

MVVM模式 映射关系的简化,暗藏了controller

MVVMModel-View-ViewModel缩写,也就是把MVC中的Controller演变成ViewModelModel层代表数据模型,View代表UI组件,ViewModelViewModel层的桥梁,数据会绑定到viewModel层并主动将数据渲染到页面中,视图变动的时候会告诉viewModel层更新数据。

  • Model: 代表数据模型,也能够在Model中定义数据批改和操作的业务逻辑。咱们能够把Model称为数据层,因为它仅仅关注数据自身,不关怀任何行为
  • View: 用户操作界面。当ViewModelModel进行更新的时候,会通过数据绑定更新到View
  • ViewModel: 业务逻辑层,View须要什么数据,ViewModel要提供这个数据;View有某些操作,ViewModel就要响应这些操作,所以能够说它是Model for View.

总结MVVM模式简化了界面与业务的依赖,解决了数据频繁更新。MVVM 在应用当中,利用双向绑定技术,使得 Model 变动时,ViewModel 会自动更新,而 ViewModel 变动时,View 也会主动变动。

咱们以下通过一个 Vue 实例来阐明 MVVM 的具体实现

<!-- View 层 -->

<div id="app">
    <p>{{message}}</p>
    <button v-on:click="showMessage()">Click me</button>
</div>
// ViewModel 层

var app = new Vue({
    el: '#app',
    data: {  // 用于形容视图状态   
        message: 'Hello Vue!', 
    },
    methods: {  // 用于形容视图行为  
        showMessage(){
            let vm = this;
            alert(vm.message);
        }
    },
    created(){
        let vm = this;
        // Ajax 获取 Model 层的数据
        ajax({
            url: '/your/server/data/api',
            success(res){
                vm.message = res;
            }
        });
    }
})
// Model 层

{
    "url": "/your/server/data/api",
    "res": {
        "success": true,
        "name": "test",
        "domain": "www.baidu.com"
    }
}

如何了解Vue中模板编译原理

Vue 的编译过程就是将 template 转化为 render 函数的过程

  • 解析生成AST树template模板转化成AST语法树,应用大量的正则表达式对模板进行解析,遇到标签、文本的时候都会执行对应的钩子进行相干解决
  • 标记优化 对动态语法做动态标记 markup(动态节点如div下有p标签内容不会变动) diff来做优化 动态节点跳过diff操作

    • Vue的数据是响应式的,但其实模板中并不是所有的数据都是响应式的。有一些数据首次渲染后就不会再变动,对应的DOM也不会变动。那么优化过程就是深度遍历AST树,依照相干条件对树节点进行标记。这些被标记的节点(动态节点)咱们就能够跳过对它们的比对,对运行时的模板起到很大的优化作用
    • 期待后续节点更新,如果是动态的,不会在比拟children
  • 代码生成 编译的最初一步是将优化后的AST树转换为可执行的代码

答复范例

思路

  • 引入vue编译器概念
  • 阐明编译器的必要性
  • 论述编译器工作流程

答复范例

  1. Vue中有个独特的编译器模块,称为compiler,它的次要作用是将用户编写的template编译为js中可执行的render函数。
  2. 之所以须要这个编译过程是为了便于前端能高效的编写视图模板。相比而言,咱们还是更违心用HTML来编写视图,直观且高效。手写render函数不仅效率底下,而且失去了编译期的优化能力。
  3. Vue中编译器会先对template进行解析,这一步称为parse,完结之后会失去一个JS对象,咱们称为 形象语法树AST ,而后是对AST进行深加工的转换过程,这一步成为transform,最初将后面失去的AST生成为JS代码,也就是render函数

可能的诘问

  1. Vue中编译器何时执行?

new Vue()之后。 Vue 会调用 _init 函数进行初始化,也就是这里的 init 过程,它会初始化生命周期、事件、 propsmethodsdatacomputedwatch等。其中最重要的是通过 Object.defineProperty 设置 settergetter 函数,用来实现「响应式」以及「依赖收集」

  • 初始化之后调用 $mount 会挂载组件,如果是运行时编译,即不存在 render function 然而存在 template 的状况,须要进行「编译」步骤
  • compile编译能够分成 parseoptimizegenerate 三个阶段,最终须要失去 render function
  • React有没有编译器?

react 应用babelJSX语法解析

<div id="app"></div>
<script>
    let vm = new Vue({
        el: '#app',
        template: `<div>
            // <span>hello world</span> 是动态节点
            <span>hello world</span>    
            // <p>{{name}}</p> 是动静节点
            <p>{{name}}</p>
        </div>`,
        data() {
          return { name: 'test' }
        }
    });
</script>

源码剖析

export function compileToFunctions(template) {
  // 咱们须要把html字符串变成render函数
  // 1.把html代码转成ast语法树  ast用来形容代码自身造成树结构 不仅能够形容html 也能形容css以及js语法
  // 很多库都使用到了ast 比方 webpack babel eslint等等
  let ast = parse(template);
  // 2.优化动态节点:对ast树进行标记,标记动态节点
    if (options.optimize !== false) {
      optimize(ast, options);
    }

  // 3.通过ast 从新生成代码
  // 咱们最初生成的代码须要和render函数一样
  // 相似_c('div',{id:"app"},_c('div',undefined,_v("hello"+_s(name)),_c('span',undefined,_v("world"))))
  // _c代表创立元素 _v代表创立文本 _s代表文Json.stringify--把对象解析成文本
  let code = generate(ast);
  //   应用with语法扭转作用域为this  之后调用render函数能够应用call扭转this 不便code外面的变量取值
  let renderFn = new Function(`with(this){return ${code}}`);
  return renderFn;
}

Vue的长处

  • 轻量级框架:只关注视图层,是一个构建数据的视图汇合,大小只有几十 kb
  • 简略易学:国人开发,中文文档,不存在语言障碍 ,易于了解和学习;
  • 双向数据绑定:保留了 angular 的特点,在数据操作方面更为简略;
  • 组件化:保留了 react 的长处,实现了 html 的封装和重用,在构建单页面利用方面有着独特的劣势;
  • 视图,数据,构造拆散:使数据的更改更为简略,不须要进行逻辑代码的批改,只须要操作数据就能实现相干操作;
  • 虚构DOM:dom 操作是十分消耗性能的,不再应用原生的 dom 操作节点,极大解放 dom 操作,但具体操作的还是 dom 不过是换了另一种形式;
  • 运行速度更快:相比拟于 react 而言,同样是操作虚构 dom,就性能而言, vue 存在很大的劣势。

diff算法

<details open=””><summary>答案</summary>
<p>
</p><p>工夫复杂度: 个树的齐全 diff 算法是一个工夫复杂度为 O(n*3) ,vue进行优化转化成 O(n) 。</p>
<p>了解:</p>
<ul>
<li>
<p>最小量更新, key 很重要。这个能够是这个节点的惟一标识,通知 diff 算法,在更改前后它们是同一个DOM节点</p>
<ul>
<li>扩大 v-for 为什么要有 key ,没有 key 会暴力复用,举例子的话轻易说一个比方挪动节点或者减少节点(批改DOM),加 key 只会挪动缩小操作DOM。</li>
</ul>
</li>
<li>
<p>只有是同一个虚构节点才会进行精细化比拟,否则就是暴力删除旧的,插入新的。</p>
</li>
<li>
<p>只进行同层比拟,不会进行跨层比拟。</p>
</li>
</ul>
<p>diff算法的优化策略:四种命中查找,四个指针</p>
<ol>
<li>
<p>旧前与新前(先比结尾,后插入和删除节点的这种状况)</p>
</li>
<li>
<p>旧后与新后(比结尾,前插入或删除的状况)</p>
</li>
<li>
<p>旧前与新后(头与尾比,此种产生了,波及挪动节点,那么新前指向的节点,挪动到旧后之后)</p>
</li>
<li>
<p>旧后与新前(尾与头比,此种产生了,波及挪动节点,那么新前指向的节点,挪动到旧前之前)</p>
</li>
</ol>
<p></p>
</details>

— 问完下面这些如果都能很分明的话,根本O了 —

以下的这些简略的概念,你必定也是没有问题的啦😉

Vue 的生命周期办法有哪些 个别在哪一步发申请

beforeCreate 在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用。在以后阶段 data、methods、computed 以及 watch 上的数据和办法都不能被拜访

created 实例曾经创立实现之后被调用。在这一步,实例已实现以下的配置:数据观测(data observer),属性和办法的运算, watch/event 事件回调。这里没有$el,如果非要想与 Dom 进行交互,能够通过 vm.$nextTick 来拜访 Dom

beforeMount 在挂载开始之前被调用:相干的 render 函数首次被调用。

mounted 在挂载实现后产生,在以后阶段,实在的 Dom 挂载结束,数据实现双向绑定,能够拜访到 Dom 节点

beforeUpdate 数据更新时调用,产生在虚构 DOM 从新渲染和打补丁(patch)之前。能够在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程

updated 产生在更新实现之后,以后阶段组件 Dom 已实现更新。要留神的是防止在此期间更改数据,因为这可能会导致有限循环的更新,该钩子在服务器端渲染期间不被调用。

beforeDestroy 实例销毁之前调用。在这一步,实例依然齐全可用。咱们能够在这时进行善后收尾工作,比方革除计时器。

destroyed Vue 实例销毁后调用。调用后,Vue 实例批示的所有货色都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。 该钩子在服务器端渲染期间不被调用。

activated keep-alive 专属,组件被激活时调用

deactivated keep-alive 专属,组件被销毁时调用

异步申请在哪一步发动?

能够在钩子函数 created、beforeMount、mounted 中进行异步申请,因为在这三个钩子函数中,data 曾经创立,能够将服务端端返回的数据进行赋值。

如果异步申请不须要依赖 Dom 举荐在 created 钩子函数中调用异步申请,因为在 created 钩子函数中调用异步申请有以下长处:

  • 能更快获取到服务端数据,缩小页面 loading 工夫;
  • ssr 不反对 beforeMount 、mounted 钩子函数,所以放在 created 中有助于一致性;

Vue 组件间通信有哪几种形式?

​ Vue 组件间通信是面试常考的知识点之一,这题有点相似于凋谢题,你答复出越多办法当然越加分,表明你对 Vue 把握的越纯熟。Vue 组件间通信只有指以下 3 类通信:父子组件通信、隔代组件通信、兄弟组件通信,上面咱们别离介绍每种通信形式且会阐明此种办法可实用于哪类组件间通信。

(1)props / $emit 实用 父子组件通信

这种办法是 Vue 组件的根底,置信大部分同学耳闻能详,所以此处就不举例开展介绍。

(2)ref$parent / $children 实用 父子组件通信

  • ref:如果在一般的 DOM 元素上应用,援用指向的就是 DOM 元素;如果用在子组件上,援用就指向组件实例
  • $parent / $children:拜访父 / 子实例

(3)EventBus ($emit / $on) 实用于 父子、隔代、兄弟组件通信

这种办法通过一个空的 Vue 实例作为地方事件总线(事件核心),用它来触发事件和监听事件,从而实现任何组件间的通信,包含父子、隔代、兄弟组件。

(4)$attrs/$listeners 实用于 隔代组件通信

  • $attrs:蕴含了父作用域中不被 prop 所辨认 (且获取) 的个性绑定 ( class 和 style 除外 )。当一个组件没有申明任何 prop 时,这里会蕴含所有父作用域的绑定 ( class 和 style 除外 ),并且能够通过 v-bind="$attrs" 传入外部组件。通常配合 inheritAttrs 选项一起应用。
  • $listeners:蕴含了父作用域中的 (不含 .native 润饰器的) v-on 事件监听器。它能够通过 v-on="$listeners" 传入外部组件

(5)provide / inject 实用于 隔代组件通信

先人组件中通过 provider 来提供变量,而后在子孙组件中通过 inject 来注入变量。 provide / inject API 次要解决了跨级组件间的通信问题,不过它的应用场景,次要是子组件获取下级组件的状态,跨级组件间建设了一种被动提供与依赖注入的关系。

(6)Vuex 实用于 父子、隔代、兄弟组件通信

Vuex 是一个专为 Vue.js 利用程序开发的状态管理模式。每一个 Vuex 利用的外围就是 store(仓库)。“store” 基本上就是一个容器,它蕴含着你的利用中大部分的状态 ( state )。

  • Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地失去高效更新。
  • 扭转 store 中的状态的惟一路径就是显式地提交 (commit) mutation。这样使得咱们能够不便地跟踪每一个状态的变动。

理解nextTick吗?

异步办法,异步渲染最初一步,与JS事件循环分割严密。次要应用了宏工作微工作(setTimeoutpromise那些),定义了一个异步办法,屡次调用nextTick会将办法存入队列,通过异步办法清空以后队列。

Vue 模板编译原理

Vue 的编译过程就是将 template 转化为 render 函数的过程 分为以下三步

第一步是将 模板字符串 转换成 element ASTs(解析器)
第二步是对 AST 进行动态节点标记,次要用来做虚构DOM的渲染优化(优化器)
第三步是 应用 element ASTs 生成 render 函数代码字符串(代码生成器)

相干代码如下

export function compileToFunctions(template) {
  // 咱们须要把html字符串变成render函数
  // 1.把html代码转成ast语法树  ast用来形容代码自身造成树结构 不仅能够形容html 也能形容css以及js语法
  // 很多库都使用到了ast 比方 webpack babel eslint等等
  let ast = parse(template);
  // 2.优化动态节点
  // 这个有趣味的能够去看源码  不影响外围性能就不实现了
  //   if (options.optimize !== false) {
  //     optimize(ast, options);
  //   }

  // 3.通过ast 从新生成代码
  // 咱们最初生成的代码须要和render函数一样
  // 相似_c('div',{id:"app"},_c('div',undefined,_v("hello"+_s(name)),_c('span',undefined,_v("world"))))
  // _c代表创立元素 _v代表创立文本 _s代表文Json.stringify--把对象解析成文本
  let code = generate(ast);
  //   应用with语法扭转作用域为this  之后调用render函数能够应用call扭转this 不便code外面的变量取值
  let renderFn = new Function(`with(this){return ${code}}`);
  return renderFn;
}

Vue 组件间通信有哪几种形式?

Vue 组件间通信是面试常考的知识点之一,这题有点相似于凋谢题,你答复出越多办法当然越加分,表明你对 Vue 把握的越纯熟。Vue 组件间通信只有指以下 3 类通信:父子组件通信、隔代组件通信、兄弟组件通信,上面咱们别离介绍每种通信形式且会阐明此种办法可实用于哪类组件间通信。

(1)props / $emit 实用 父子组件通信 这种办法是 Vue 组件的根底,置信大部分同学耳闻能详,所以此处就不举例开展介绍。

(2)ref 与 $parent / $children 实用 父子组件通信

  • ref:如果在一般的 DOM 元素上应用,援用指向的就是 DOM 元素;如果用在子组件上,援用就指向组件实例
  • $parent / $children:拜访父 / 子实例

(3)EventBus ($emit / $on) 实用于 父子、隔代、兄弟组件通信 这种办法通过一个空的 Vue 实例作为地方事件总线(事件核心),用它来触发事件和监听事件,从而实现任何组件间的通信,包含父子、隔代、兄弟组件。

(4)$attrs/$listeners 实用于 隔代组件通信

  • $attrs:蕴含了父作用域中不被 prop 所辨认 (且获取) 的个性绑定 ( class 和 style 除外 )。当一个组件没有申明任何 prop 时,这里会蕴含所有父作用域的绑定 ( class 和 style 除外 ),并且能够通过 v-bind="$attrs" 传入外部组件。通常配合 inheritAttrs 选项一起应用。
  • $listeners:蕴含了父作用域中的 (不含 .native 润饰器的) v-on事件监听器。它能够通过 v-on="$listeners" 传入外部组件

(5)provide / inject 实用于 隔代组件通信 先人组件中通过 provider 来提供变量,而后在子孙组件中通过 inject 来注入变量。 provide / inject API 次要解决了跨级组件间的通信问题,不过它的应用场景,次要是子组件获取下级组件的状态,跨级组件间建设了一种被动提供与依赖注入的关系。 (6)Vuex 实用于 父子、隔代、兄弟组件通信 Vuex 是一个专为 Vue.js 利用程序开发的状态管理模式。每一个 Vuex 利用的外围就是 store(仓库)。“store” 基本上就是一个容器,它蕴含着你的利用中大部分的状态 ( state )。

  • Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地失去高效更新。
  • 扭转 store 中的状态的惟一路径就是显式地提交 (commit) mutation。这样使得咱们能够不便地跟踪每一个状态的变动。

Vue性能优化

编码优化

  • 事件代理
  • keep-alive
  • 拆分组件
  • key 保障唯一性
  • 路由懒加载、异步组件
  • 防抖节流

Vue加载性能优化

  • 第三方模块按需导入( babel-plugin-component
  • 图片懒加载

用户体验

  • app-skeleton 骨架屏
  • shellap p壳
  • pwa

SEO优化

  • 预渲染

Vue为什么没有相似于React中shouldComponentUpdate的生命周期?

考点: Vue的变动侦测原理

前置常识: 依赖收集、虚构DOM、响应式零碎

根本原因是Vue与React的变动侦测形式有所不同

React是pull的形式侦测变动,当React晓得发生变化后,会应用Virtual Dom Diff进行差别检测,然而很多组件实际上是必定不会发生变化的,这个时候须要用shouldComponentUpdate进行手动操作来缩小diff,从而进步程序整体的性能.

Vue是pull+push的形式侦测变动的,在一开始就晓得那个组件产生了变动,因而在push的阶段并不需要手动管制diff,而组件外部采纳的diff形式实际上是能够引入相似于shouldComponentUpdate相干生命周期的,然而通常正当大小的组件不会有适量的diff,手动优化的价值无限,因而目前Vue并没有思考引入shouldComponentUpdate这种手动优化的生命周期.

父组件能够监听到子组件的生命周期吗

比方有父组件 Parent 和子组件 Child,如果父组件监听到子组件挂载 mounted 就做一些逻辑解决,能够通过以下写法实现:

// Parent.vue
<Child @mounted="doSomething"/>

// Child.vue
mounted() {
this.$emit("mounted");
}

以上须要手动通过 $emit 触发父组件的事件,更简略的形式能够在父组件援用子组件时通过 @hook 来监听即可,如下所示:

//  Parent.vue
<Child @hook:mounted="doSomething" ></Child>

doSomething() {
   console.log('父组件监听到 mounted 钩子函数 ...');
},

//  Child.vue
mounted(){
   console.log('子组件触发 mounted 钩子函数 ...');
},    

// 以上输入程序为:
// 子组件触发 mounted 钩子函数 ...
// 父组件监听到 mounted 钩子函数 ...     

当然 @hook 办法不仅仅是能够监听 mounted,其它的生命周期事件,例如:createdupdated 等都能够监听

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理