共计 12429 个字符,预计需要花费 32 分钟才能阅读完成。
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 算法的优化策略:四种命中查找,四个指针
- 旧前与新前(先比结尾,后插入和删除节点的这种状况)
- 旧后与新后(比结尾,前插入或删除的状况)
- 旧前与新后(头与尾比,此种产生了,波及挪动节点,那么新前指向的节点,挪动到旧后之后)
- 旧后与新前(尾与头比,此种产生了,波及挪动节点,那么新前指向的节点,挪动到旧前之前)
$nextTick 是什么?
Vue 实现响应式并不是在数据产生后立刻更新 DOM,应用 vm.$nextTick
是在下次 DOM 更新循环完结之后立刻执行提早回调。在批改数据之后应用,则 能够在回调中获取更新后的 DOM。
谈谈你对 MVVM 的了解
为什么要有这些模式,目标:职责划分、分层(将 Model
层、View
层进行分类)借鉴后端思维,对于前端而已,就是如何将数据同步到页面上
MVC 模式 代表:Backbone
+ underscore
+ jquery
- 传统的
MVC
指的是, 用户操作会申请服务端路由,路由会调用对应的控制器来解决,控制器会获取数据。将后果返回给前端, 页面从新渲染 MVVM
:传统的前端会将数据手动渲染到页面上,MVVM
模式不须要用户收到操作dom
元素, 将数据绑定到viewModel
层上,会主动将数据渲染到页面中,视图变动会告诉viewModel
层 更新数据。ViewModel
就是咱们MVVM
模式中的桥梁
MVVM 模式 映射关系的简化,暗藏了controller
MVVM
是Model-View-ViewModel
缩写,也就是把MVC
中的Controller
演变成ViewModel
。Model
层代表数据模型,View
代表 UI 组件,ViewModel
是View
和Model
层的桥梁,数据会绑定到viewModel
层并主动将数据渲染到页面中,视图变动的时候会告诉viewModel
层更新数据。
Model
: 代表数据模型,也能够在Model
中定义数据批改和操作的业务逻辑。咱们能够把Model
称为数据层,因为它仅仅关注数据自身,不关怀任何行为View
: 用户操作界面。当ViewModel
对Model
进行更新的时候,会通过数据绑定更新到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
编译器概念 - 阐明编译器的必要性
- 论述编译器工作流程
答复范例
Vue
中有个独特的编译器模块,称为compiler
,它的次要作用是将用户编写的template
编译为js
中可执行的render
函数。- 之所以须要这个编译过程是为了便于前端能高效的编写视图模板。相比而言,咱们还是更违心用
HTML
来编写视图,直观且高效。手写render
函数不仅效率底下,而且失去了编译期的优化能力。 - 在
Vue
中编译器会先对template
进行解析,这一步称为parse
,完结之后会失去一个JS
对象,咱们称为 形象语法树 AST,而后是对AST
进行深加工的转换过程,这一步成为transform
,最初将后面失去的AST
生成为JS
代码,也就是render
函数
可能的诘问
Vue
中编译器何时执行?
在
new Vue()
之后。Vue
会调用_init
函数进行初始化,也就是这里的 init
过程,它会初始化生命周期、事件、props
、methods
、data
、computed
与watch
等。其中最重要的是通过Object.defineProperty
设置setter
与getter
函数,用来实现「响应式」以及「依赖收集」
- 初始化之后调用
$mount
会挂载组件,如果是运行时编译,即不存在render function
然而存在template
的状况,须要进行「编译」步骤 compile
编译能够分成parse
、optimize
与generate
三个阶段,最终须要失去render function
React
有没有编译器?
react
应用 babel
将JSX
语法解析
<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 事件循环分割严密。次要应用了宏工作微工作(setTimeout
、promise
那些),定义了一个异步办法,屡次调用 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
,其它的生命周期事件,例如:created
,updated
等都能够监听