一、基础
1、使用 this.$forceUpdate(); 强制更新数据, computed里面的数据不会变化。
2、vue是单项数据流,不要在子组件里面更改父组件的数据,应该通过父组件的属性里面绑定一个函数,在子组件里面调用该函数,把数据传回父组件,然后在父组件里更改数据;
3、vue2.6版本的slot插槽使用和2.5的已经不一样了。但是还是兼容之前的使用方式。
// 2.6版本的<template v-slot:item="props"><p>item slot-scope {{ props }}</p></template>// 2.5版本的<p slot="item" slot-scope="props">item slot-scope {{ props }}</p>
4、vue2.4版本新增了inheritAttrs属性,当父组件传过来的数据,子组件没有在html中使用时,该变量会默认挂载到子组件的元素上,设置inheritAttrs为false时,就不会挂载了。应用场景?
5、子组件发射事件时,可以传递一个函数,在父组件接受到值后再回调。
// 子组件this.$emit("change", e.target.value, val => {console.log(val);});父组件handleEventChange(val, callback) {this.name = val;callback("hello");}
6、函数式组件:
functional:true
特征: 无状态、无实例、没有this上下文、无生命周期
7、指令的执行顺序:
创建时:beforeCreate
data
created
beforeMount
render
bind // 组件render后,开始执行指令的bind
mounted
inserted // 组件mounted后,开始执行指令的inserted
更新时:update // 执行指令的update方法
componentUpdated // 执行指令的componentUpdated 方法
beforeUpdate
render
updated
销毁时:beforeDestroy
destroyed
unbind // 执行指令的unbind方法
8、Vue.observable,创建一个响应对象。以前只有当实例被创建时 data 中存在的属性才是响应式的
9、vue响应式原理和依赖收集
function isObject (obj) {return typeof obj === 'object'&& !Array.isArray(obj)&& obj !== null&& obj !== undefined}function observe (obj) {if (!isObject(obj)) {throw new TypeError()}Object.keys(obj).forEach(key => {let internalValue = obj[key]let dep = new Dep()Object.defineProperty(obj, key, {get () {dep.depend()return internalValue},set (newValue) {const isChanged = internalValue !== newValueif (isChanged) {internalValue = newValuedep.notify()}}})})}window.Dep = class Dep {constructor () {this.subscribers = new Set()}depend () {if (activeUpdate) {// register the current active update as a subscriberthis.subscribers.add(activeUpdate)}}notify () {// run all subscriber functionsthis.subscribers.forEach(subscriber => subscriber())}}let activeUpdatefunction autorun (update) {function wrappedUpdate () {activeUpdate = wrappedUpdateupdate()activeUpdate = null}wrappedUpdate()}const state = {count: 0}observe(state)autorun(() => {console.log(state.count)})// should immediately log "count is: 0"state.count++
二、原理
new Vue 发生了什么
执行了初始化方法_init();
合并参数;
// 各种初始化vm._self = vminitLifecycle(vm) // $parent/$rootinitEvents(vm) // 自定义事件监听initRender(vm) // $slots/$createElementcallHook(vm, 'beforeCreate')// 获取祖辈注入的数据initInjections(vm) // resolve injections before data/propsinitState(vm) // 数据状态初始化:data/props/methods/computed/watch// 给后代提供数据initProvide(vm) // resolve provide after data/propscallHook(vm, 'created')// 选项如果有el,自动执行$mountif (vm.$options.el) {vm.$mount(vm.$options.el)}
说一下数据响应式
在new Vue 中执行 initState(vm)的时候,遍历data并做响应式处理,
通过Object.defineProperty添加属性拦截,每一个属性会创建一个Dep,
在get的时候通过闭包的方式把依赖添加到之前创建的dep里面,从而对依赖进行收集,
在set的时候通知会通知各个watcher去更新视图;
keep-alive原理
根据组件id和tag 设置缓存的key值, value值用组件的vnode, 用 activeted deactived 钩子 , 如果组件已经缓存到队列里面了,会先删除缓存里面那个缓存的值,然后再把新的值更新到队列最后面, 有最大的缓存值
$nextTick 原理
vue里面set了一个数据后,不会马上更新视图,而是放到一个watcher里面,nextTick里面的方法也会放到watcher里面,用于created的时候操作dom元素,里面的实现主要有三个promise.then mutationObsive, setTimeout
Vue中的diff原理
Vue的diff算法是平级比较,不考虑跨级别比较的情况。内部采用深度递归的方式+双指针的方式进行比较;
1、先比较是否是相同的节点
2、相同节点比较属性,并复用老节点
3、比较儿子节点,考虑老节点和儿子节点的情况
4、优化比较:头头、尾尾、头尾、尾头
5、比对查找进行复用
三种类型的Watcher对象
Watcher分为三种,按创建的先后顺序为:计算属性的Watcher、用户Watcher(监听器)、渲染Watcher,执行的顺序也是一样的。
三、vue周边
vuex
state: 提供一个响应式数据
getter: 借助vue的计算属性computed来实现缓存
mutation: 更改state方法
action: 触发mutation
module: vue.set动态添加state到响应式数据中

如上图所示:vue-devtool会监测mutation里面的数据改变并做记录,因此只能在mutation里面更改state的数据。
boforeCreate中混入$store的获取方式
问:为什么需要action?
用于异步操作,异步代码放在一个地方,便于复用
vue-router
- hash模式 丑,无法使用锚点定位
history 需要后端配合,ie9不兼容(可使用强制刷新处理)
原理:

vue.util.defineReactive为响应式数据
SPA 缺点
1、不利于seo
2、首屏渲染时间长
nuxt 优点
1、静态站点
2、动态渲染
3、简化配置
ssr 核心原理
无头浏览器渲染
