虚构 DOM 的优劣如何?
长处:
- 保障性能上限: 虚构 DOM 能够通过 diff 找出最小差别, 而后批量进行 patch, 这种操作尽管比不上手动优化, 然而比起粗犷的 DOM 操作性能要好很多, 因而虚构 DOM 能够保障性能上限
- 无需手动操作 DOM: 虚构 DOM 的 diff 和 patch 都是在一次更新中主动进行的, 咱们无需手动操作 DOM, 极大进步开发效率
- 跨平台: 虚构 DOM 实质上是 JavaScript 对象, 而 DOM 与平台强相干, 相比之下虚构 DOM 能够进行更不便地跨平台操作, 例如服务器渲染、挪动端开发等等
毛病:
- 无奈进行极致优化: 在一些性能要求极高的利用中虚构 DOM 无奈进行针对性的极致优化, 比方 VScode 采纳间接手动操作 DOM 的形式进行极其的性能优化
如果让你从零开始写一个 vue 路由,说说你的思路
思路剖析:
首先思考 vue
路由要解决的问题:用户点击跳转链接内容切换,页面不刷新。
- 借助
hash
或者 history api
实现url
跳转页面不刷新 - 同时监听
hashchange
事件或者popstate
事件处理跳转 - 依据
hash
值或者state
值从routes
表中匹配对应component
并渲染
答复范例:
一个 SPA
利用的路由须要解决的问题是 页面跳转内容扭转同时不刷新,同时路由还须要以插件模式存在,所以:
- 首先我会定义一个
createRouter
函数,返回路由器实例,实例外部做几件事 - 保留用户传入的配置项
- 监听
hash
或者popstate
事件 - 回调里依据
path
匹配对应路由 - 将
router
定义成一个Vue
插件,即实现install
办法,外部做两件事 - 实现两个全局组件:
router-link
和router-view
,别离实现页面跳转和内容显示 - 定义两个全局变量:
$route
和$router
,组件内能够拜访以后路由和路由器实例
你有对 Vue 我的项目进行哪些优化?
(1)代码层面的优化
- v-if 和 v-show 辨别应用场景
- computed 和 watch 辨别应用场景
- v-for 遍历必须为 item 增加 key,且防止同时应用 v-if
- 长列表性能优化
- 事件的销毁
- 图片资源懒加载
- 路由懒加载
- 第三方插件的按需引入
- 优化有限列表性能
- 服务端渲染 SSR or 预渲染
(2)Webpack 层面的优化
- Webpack 对图片进行压缩
- 缩小 ES6 转为 ES5 的冗余代码
- 提取公共代码
- 模板预编译
- 提取组件的 CSS
- 优化 SourceMap
- 构建后果输入剖析
- Vue 我的项目的编译优化
(3)根底的 Web 技术的优化
- 开启 gzip 压缩
- 浏览器缓存
- CDN 的应用
- 应用 Chrome Performance 查找性能瓶颈
写过自定义指令吗 原理是什么
指令实质上是装璜器,是 vue 对 HTML 元素的扩大,给 HTML 元素减少自定义性能。vue 编译 DOM 时,会找到指令对象,执行指令的相干办法。
自定义指令有五个生命周期(也叫钩子函数),别离是 bind、inserted、update、componentUpdated、unbind
1. bind:只调用一次,指令第一次绑定到元素时调用。在这里能够进行一次性的初始化设置。2. inserted:被绑定元素插入父节点时调用 (仅保障父节点存在,但不肯定已被插入文档中)。3. update:被绑定于元素所在的模板更新时调用,而无论绑定值是否变动。通过比拟更新前后的绑定值,能够疏忽不必要的模板更新。4. componentUpdated:被绑定元素所在模板实现一次更新周期时调用。5. unbind:只调用一次,指令与元素解绑时调用。
原理
1. 在生成 ast 语法树时,遇到指令会给以后元素增加 directives 属性
2. 通过 genDirectives 生成指令代码
3. 在 patch 前将指令的钩子提取到 cbs 中, 在 patch 过程中调用对应的钩子
4. 当执行指令对应钩子函数时,调用对应指令定义的办法
created 和 mounted 的区别
- created: 在模板渲染成 html 前调用,即通常初始化某些属性值,而后再渲染成视图。
- mounted: 在模板渲染成 html 后调用,通常是初始化页面实现后,再对 html 的 dom 节点进行一些须要的操作。
说说你对 proxy 的了解,Proxy 相比于 defineProperty 的劣势
Object.defineProperty()
的问题次要有三个:
- 不能监听数组的变动:无奈监控到数组下标的变动,导致通过数组下标增加元素,不能实时响应
- 必须遍历对象的每个属性:只能劫持对象的属性,从而须要对每个对象,每个属性进行遍历,如果属性值是对象,还须要深度遍历。
Proxy
能够劫持整个对象,并返回一个新的对象 - 必须深层遍历嵌套的对象
Proxy 的劣势如下:
- 针对对象:针对整个对象,而不是对象的某个属性,所以也就不须要对
keys
进行遍历 - 反对数组:
Proxy
不须要对数组的办法进行重载,省去了泛滥 hack,缩小代码量等于缩小了保护老本,而且规范的就是最好的 Proxy
的第二个参数能够有13
种拦挡方:不限于apply
、ownKeys
、deleteProperty
、has
等等是Object.defineProperty
不具备的Proxy
返回的是一个新对象, 咱们能够只操作新的对象达到目标, 而Object.defineProperty
只能遍历对象属性间接批改Proxy
作为新规范将受到浏览器厂商重点继续的性能优化,也就是传说中的新规范的性能红利
proxy 具体应用点击查看(opens new window)
Object.defineProperty 的劣势如下:
兼容性好,反对
IE9
,而Proxy
的存在浏览器兼容性问题, 而且无奈用polyfill
磨平
defineProperty 的属性值有哪些
Object.defineProperty(obj, prop, descriptor)
// obj 要定义属性的对象
// prop 要定义或批改的属性的名称
// descriptor 要定义或批改的属性描述符
Object.defineProperty(obj,"name",{
value:"poetry", // 初始值
writable:true, // 该属性是否可写入
enumerable:true, // 该属性是否可被遍历失去(for...in,Object.keys 等)configurable:true, // 定该属性是否可被删除,且除 writable 外的其余描述符是否可被批改
get: function() {},
set: function(newVal) {}})
相干代码如下
import {mutableHandlers} from "./baseHandlers"; // 代理相干逻辑
import {isObject} from "./util"; // 工具办法
export function reactive(target) {
// 依据不同参数创立不同响应式对象
return createReactiveObject(target, mutableHandlers);
}
function createReactiveObject(target, baseHandler) {if (!isObject(target)) {return target;}
const observed = new Proxy(target, baseHandler);
return observed;
}
const get = createGetter();
const set = createSetter();
function createGetter() {return function get(target, key, receiver) {
// 对获取的值进行喷射
const res = Reflect.get(target, key, receiver);
console.log("属性获取", key);
if (isObject(res)) {
// 如果获取的值是对象类型,则返回以后对象的代理对象
return reactive(res);
}
return res;
};
}
function createSetter() {return function set(target, key, value, receiver) {const oldValue = target[key];
const hadKey = hasOwn(target, key);
const result = Reflect.set(target, key, value, receiver);
if (!hadKey) {console.log("属性新增", key, value);
} else if (hasChanged(value, oldValue)) {console.log("属性值被批改", key, value);
}
return result;
};
}
export const mutableHandlers = {
get, // 当获取属性时调用此办法
set, // 当批改属性时调用此办法
};
Proxy
只会代理对象的第一层,那么 Vue3
又是怎么解决这个问题的呢?
判断以后
Reflect.get 的
返回值是否为Object
,如果是则再通过reactive
办法做代理,这样就实现了深度观测。
监测数组的时候可能触发屡次 get/set,那么如何避免触发屡次呢?
咱们能够判断
key
是否为以后被代理对象target
本身属性,也能够判断旧值与新值是否相等,只有满足以上两个条件之一时,才有可能执行trigger
参考 前端进阶面试题具体解答
简述 mixin、extends 的笼罩逻辑
(1)mixin 和 extends mixin 和 extends 均是用于合并、拓展组件的,两者均通过 mergeOptions 办法实现合并。
- mixins 接管一个混入对象的数组,其中混入对象能够像失常的实例对象一样蕴含实例选项,这些选项会被合并到最终的选项中。Mixin 钩子依照传入程序顺次调用,并在调用组件本身的钩子之前被调用。
-
extends 次要是为了便于扩大单文件组件,接管一个对象或构造函数。
(2)mergeOptions 的执行过程
- 规范化选项(normalizeProps、normalizelnject、normalizeDirectives)
- 对未合并的选项,进行判断
if (!child._base) {if (child.extends) {parent = mergeOptions(parent, child.extends, vm);
}
if (child.mixins) {for (let i = 0, l = child.mixins.length; i < l; i++) {parent = mergeOptions(parent, child.mixins[i], vm);
}
}
}
- 合并解决。依据一个通用 Vue 实例所蕴含的选项进行分类逐个判断合并,如 props、data、methods、watch、computed、生命周期等,将合并后果存储在新定义的 options 对象里。
- 返回合并后果 options。
MVC 和 MVVM 区别
MVC
MVC 全名是 Model View Controller,是模型 (model)-视图(view)-控制器(controller) 的缩写,一种软件设计榜样
- Model(模型):是应用程序中用于解决应用程序数据逻辑的局部。通常模型对象负责在数据库中存取数据
- View(视图):是应用程序中解决数据显示的局部。通常视图是根据模型数据创立的
- Controller(控制器):是应用程序中解决用户交互的局部。通常控制器负责从视图读取数据,管制用户输出,并向模型发送数据
MVC 的思维:一句话形容就是 Controller 负责将 Model 的数据用 View 显示进去,换句话说就是在 Controller 外面把 Model 的数据赋值给 View。
MVVM
MVVM 新增了 VM 类
- ViewModel 层:做了两件事达到了数据的双向绑定 一是将【模型】转化成【视图】,行将后端传递的数据转化成所看到的页面。实现的形式是:数据绑定。二是将【视图】转化成【模型】,行将所看到的页面转化成后端的数据。实现的形式是:DOM 事件监听。
MVVM 与 MVC 最大的区别就是:它实现了 View 和 Model 的主动同步,也就是当 Model 的属性扭转时,咱们不必再本人手动操作 Dom 元素,来扭转 View 的显示,而是扭转属性后该属性对应 View 层显示会主动扭转(对应 Vue 数据驱动的思维)
整体看来,MVVM 比 MVC 精简很多,不仅简化了业务与界面的依赖,还解决了数据频繁更新的问题,不必再用选择器操作 DOM 元素。因为在 MVVM 中,View 不晓得 Model 的存在,Model 和 ViewModel 也察看不到 View,这种低耦合模式进步代码的可重用性
留神:Vue 并没有齐全遵循 MVVM 的思维 这一点官网本人也有阐明
那么问题来了 为什么官网要说 Vue 没有齐全遵循 MVVM 思维呢?
- 严格的 MVVM 要求 View 不能和 Model 间接通信,而 Vue 提供了 $refs 这个属性,让 Model 能够间接操作 View,违反了这一规定,所以说 Vue 没有齐全遵循 MVVM。
Vue 中 computed 和 watch 有什么区别?
计算属性 computed:
(1)** 反对缓存 **,只有依赖数据发生变化时,才会从新进行计算函数;(2)计算属性内 ** 不反对异步操作 **;(3)计算属性的函数中 ** 都有一个 get**(默认具备,获取计算属性)** 和 set**(手动增加,设置计算属性)办法;(4)计算属性是主动监听依赖值的变动,从而动静返回内容。
侦听属性 watch:
(1)** 不反对缓存 **,只有数据发生变化,就会执行侦听函数;(2)侦听属性内 ** 反对异步操作 **;(3)侦听属性的值 ** 能够是一个对象,接管 handler 回调,deep,immediate 三个属性 **;(3)监听是一个过程,在监听的值变动时,能够触发一个回调,并 ** 做一些其余事件 **。
assets 和 static 的区别
相同点: assets
和 static
两个都是寄存动态资源文件。我的项目中所须要的资源文件图片,字体图标,款式文件等都能够放在这两个文件下,这是相同点
不相同点:assets
中寄存的动态资源文件在我的项目打包时,也就是运行 npm run build
时会将 assets
中搁置的动态资源文件进行打包上传,所谓打包简略点能够了解为压缩体积,代码格式化。而压缩后的动态资源文件最终也都会搁置在 static
文件中跟着 index.html
一起上传至服务器。static
中搁置的动态资源文件就不会要走打包压缩格式化等流程,而是间接进入打包好的目录,间接上传至服务器。因为防止了压缩间接进行上传,在打包时会进步肯定的效率,然而 static
中的资源文件因为没有进行压缩等操作,所以文件的体积也就绝对于 assets
中打包后的文件提交较大点。在服务器中就会占据更大的空间。
倡议: 将我的项目中 template
须要的款式文件 js 文件等都能够搁置在 assets
中,走打包这一流程。缩小体积。而我的项目中引入的第三方的资源文件如iconfoont.css
等文件能够搁置在 static
中,因为这些引入的第三方文件曾经通过解决,不再须要解决,间接上传。
用 VNode 来形容一个 DOM 构造
虚构节点就是用一个对象来形容一个实在的 DOM 元素。首先将 template
(实在 DOM)先转成 ast
, ast
树通过 codegen
生成 render
函数, render
函数里的 _c
办法将它转为虚构 dom
Vue 的性能优化有哪些
(1)编码阶段
- 尽量减少 data 中的数据,data 中的数据都会减少 getter 和 setter,会收集对应的 watcher
- v-if 和 v -for 不能连用
- 如果须要应用 v -for 给每项元素绑定事件时应用事件代理
- SPA 页面采纳 keep-alive 缓存组件
- 在更多的状况下,应用 v -if 代替 v -show
- key 保障惟一
- 应用路由懒加载、异步组件
- 防抖、节流
- 第三方模块按需导入
- 长列表滚动到可视区域动静加载
- 图片懒加载
(2)SEO 优化
- 预渲染
- 服务端渲染 SSR
(3)打包优化
- 压缩代码
- Tree Shaking/Scope Hoisting
- 应用 cdn 加载第三方模块
- 多线程打包 happypack
- splitChunks 抽离公共文件
- sourceMap 优化
(4)用户体验
- 骨架屏
- PWA
- 还能够应用缓存 (客户端缓存、服务端缓存) 优化、服务端开启 gzip 压缩等。
Vue.extend 作用和原理
官网解释:Vue.extend 应用根底 Vue 结构器,创立一个“子类”。参数是一个蕴含组件选项的对象。
其实就是一个子类结构器 是 Vue 组件的外围 api 实现思路就是应用原型继承的办法返回了 Vue 的子类 并且利用 mergeOptions 把传入组件的 options 和父类的 options 进行了合并
相干代码如下
export default function initExtend(Vue) {
let cid = 0; // 组件的惟一标识
// 创立子类继承 Vue 父类 便于属性扩大
Vue.extend = function (extendOptions) {
// 创立子类的构造函数 并且调用初始化办法
const Sub = function VueComponent(options) {this._init(options); // 调用 Vue 初始化办法
};
Sub.cid = cid++;
Sub.prototype = Object.create(this.prototype); // 子类原型指向父类
Sub.prototype.constructor = Sub; //constructor 指向本人
Sub.options = mergeOptions(this.options, extendOptions); // 合并本人的 options 和父类的 options
return Sub;
};
}
常见的事件修饰符及其作用
.stop
:等同于 JavaScript 中的event.stopPropagation()
,避免事件冒泡;.prevent
:等同于 JavaScript 中的event.preventDefault()
,避免执行预设的行为(如果事件可勾销,则勾销该事件,而不进行事件的进一步流传);.capture
:与事件冒泡的方向相同,事件捕捉由外到内;.self
:只会触发本人范畴内的事件,不蕴含子元素;.once
:只会触发一次。
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 节点,外面有(标签名、子节点、文本等等)
vue3 中 watch、watchEffect 区别
watch
是惰性执行,也就是只有监听的值发生变化的时候才会执行,然而watchEffect
不同,每次代码加载watchEffect
都会执行(疏忽watch
第三个参数的配置,如果批改配置项也能够实现立刻执行)watch
须要传递监听的对象,watchEffect
不须要watch
只能监听响应式数据:ref
定义的属性和reactive
定义的对象,如果间接监听reactive
定义对象中的属性是不容许的(会报正告),除非应用函数转换一下。其实就是官网上说的监听一个getter
watchEffect
如果监听reactive
定义的对象是不起作用的,只能监听对象中的属性
看一下 watchEffect
的代码
<template>
<div>
请输出 firstName:<input type="text" v-model="firstName">
</div>
<div>
请输出 lastName:<input type="text" v-model="lastName">
</div>
<div>
请输出 obj.text:<input type="text" v-model="obj.text">
</div>
<div>【obj.text】{{obj.text}}
</div>
</template>
<script>
import {ref, reactive, watch, watchEffect} from 'vue'
export default {
name: "HelloWorld",
props: {msg: String,},
setup(props,content){let firstName = ref('')
let lastName = ref('')
let obj= reactive({text:'hello'})
watchEffect(()=>{console.log('触发了 watchEffect');
console.log(` 组合后的名称为:${firstName.value}${lastName.value}`)
})
return{
obj,
firstName,
lastName
}
}
};
</script>
革新一下代码
watchEffect(()=>{console.log('触发了 watchEffect');
// 这里咱们不应用 firstName.value/lastName.value,相当于是监控整个 ref, 对应第四点下面的论断
console.log(` 组合后的名称为:${firstName}${lastName}`)
})
watchEffect(()=>{console.log('触发了 watchEffect');
console.log(obj);
})
略微革新一下
let obj = reactive({text:'hello'})
watchEffect(()=>{console.log('触发了 watchEffect');
console.log(obj.text);
})
再看一下 watch 的代码,验证一下
let obj= reactive({text:'hello'})
// watch 是惰性执行,默认初始化之后不会执行,只有值有变动才会触发,可通过配置参数实现默认执行
watch(obj, (newValue, oldValue) => {
// 回调函数
console.log('触发监控更新了 new', newValue);
console.log('触发监控更新了 old', oldValue);
},{
// 配置 immediate 参数,立刻执行,以及深层次监听
immediate: true,
deep: true
})
- 监控整个
reactive
对象,从下面的图能够看到deep
理论默认是开启的,就算咱们设置为false
也还是有效。而且旧值获取不到。 - 要获取旧值则须要监控对象的属性,也就是监听一个
getter
,看下图
总结
- 如果定义了
reactive
的数据,想去应用watch
监听数据扭转,则无奈正确获取旧值,并且deep
属性配置有效,主动强制开启了深层次监听。 - 如果应用
ref
初始化一个对象或者数组类型的数据,会被主动转成reactive
的实现形式,生成proxy
代理对象。也会变得无奈正确取旧值。 - 用任何形式生成的数据,如果接管的变量是一个
proxy
代理对象,就都会导致watch
这个对象时,watch
回调里无奈正确获取旧值。 - 所以当大家应用
watch
监听对象时,如果在不须要应用旧值的状况,能够失常监听对象没关系;然而如果当监听扭转函数外面须要用到旧值时,只能监听 对象.xxx` 属性 的形式才行
watch 和 watchEffect 异同总结
体验
watchEffect
立刻运行一个函数,而后被动地追踪它的依赖,当这些依赖扭转时从新执行该函数
const count = ref(0)
watchEffect(() => console.log(count.value))
// -> logs 0
count.value++
// -> logs 1
watch
侦测一个或多个响应式数据源并在数据源变动时调用一个回调函数
const state = reactive({count: 0})
watch(() => state.count,
(count, prevCount) => {/* ... */}
)
答复范例
watchEffect
立刻运行一个函数,而后被动地追踪它的依赖,当这些依赖扭转时从新执行该函数。watch
侦测一个或多个响应式数据源并在数据源变动时调用一个回调函数watchEffect(effect)
是一种非凡watch
,传入的函数既是依赖收集的数据源,也是回调函数。如果咱们不关怀响应式数据变动前后的值,只是想拿这些数据做些事件,那么watchEffect
就是咱们须要的。watch
更底层,能够接管多种数据源,包含用于依赖收集的getter
函数,因而它齐全能够实现watchEffect
的性能,同时因为能够指定getter
函数,依赖能够管制的更准确,还能获取数据变动前后的值,因而如果须要这些时咱们会应用watch
watchEffect
在应用时,传入的函数会立即执行一次。watch
默认状况下并不会执行回调函数,除非咱们手动设置immediate
选项- 从实现上来说,
watchEffect(fn)
相当于watch(fn,fn,{immediate:true})
watchEffect
定义如下
export function watchEffect(
effect: WatchEffect,
options?: WatchOptionsBase
): WatchStopHandle {return doWatch(effect, null, options)
}
watch
定义如下
export function watch<T = any, Immediate extends Readonly<boolean> = false>(
source: T | WatchSource<T>,
cb: any,
options?: WatchOptions<Immediate>
): WatchStopHandle {return doWatch(source as any, cb, options)
}
很显著 watchEffect
就是一种非凡的 watch
实现。
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 data 中某一个属性的值产生扭转后,视图会立刻同步执行从新渲染吗?
不会立刻同步执行从新渲染。Vue 实现响应式并不是数据发生变化之后 DOM 立刻变动,而是按肯定的策略进行 DOM 的更新。Vue 在更新 DOM 时是异步执行的。只有侦听到数据变动,Vue 将开启一个队列,并缓冲在同一事件循环中产生的所有数据变更。
如果同一个 watcher 被屡次触发,只会被推入到队列中一次。这种在缓冲时去除反复数据对于防止不必要的计算和 DOM 操作是十分重要的。而后,在下一个的事件循环 tick 中,Vue 刷新队列并执行理论(已去重的)工作。
vue 和 react 的区别
=> 相同点:
1. 数据驱动页面,提供响应式的试图组件
2. 都有 virtual DOM, 组件化的开发,通过 props 参数进行父子之间组件传递数据,都实现了 webComponents 标准
3. 数据流动单向,都反对服务器的渲染 SSR
4. 都有反对 native 的办法,react 有 React native,vue 有 wexx
=> 不同点:
1. 数据绑定:Vue 实现了双向的数据绑定,react 数据流动是单向的
2. 数据渲染:大规模的数据渲染,react 更快
3. 应用场景:React 配合 Redux 架构适宜大规模多人合作简单我的项目,Vue 适宜小快的我的项目
4. 开发格调:react 举荐做法 jsx + inline style 把 html 和 css 都写在 js 了
vue 是采纳 webpack + vue-loader 单文件组件格局,html, js, css 同一个文件
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 中有助于一致性;