Vue基础
v-if 和 v-show
v-if 控制dom节点是否存在、更高的切换消耗、惰性的(初始条件为假什么也不做)、有局部编译和卸载的过程
v-show 控制css:display、更高的初始消耗
切换频繁用v-show,条件改变很少时用v-if
v-for key作用
必须用key,且不能是index和random,diff算法中通过tag和key来判断是否是相同节点,用key可以使diff算法减少渲染次数提升渲染性能。
组件通讯
- 父子组件:props 和 this.$emit
- 非父子组件:自定义事件 event.emit触发, event.on绑定/event.$off销毁
- vuex
组件生命周期
-
挂载阶段
- beforeCreate:$el和data未初始化
- created:$el未初始化 data初始化
- beforeMount:$el和data初始化,未挂载
- mounted:已挂载
-
更新阶段
- beforeUpdate
- updated
-
销毁阶段
-
beforeDestroy
-
destroyed
父子组件生命周期顺序
- 挂载阶段:父created - 子created - 子mounted - 父mounted
- 更新阶段:父beforeUpdate - 子beforeUpdate - 子updated - 父updated
组件如何抽离公共逻辑——mixin
mixin缺点:
- 变量来源不明确,不利于阅读
- 多 mixin 可能会引起命名冲突
- mixin 和组件可能会出现多对多的关系 造成混乱
动态注册全局组件
核心:通过 require.context() 方法获取文件夹下所有vue文件路径
Vue组件更新后如何获取最新DOM
vue是异步渲染,data 修改后不会立刻修改dom,而是会整合多次修改结果,更新一次dom。
路由原理
- hash路由:window.onhashchange事件
- history路由:history.pushState事件、window.onpopstate事件(前进/后退)
history路由需要服务端支持(无论url是什么,都返回index.html这个主文件)
data为什么是函数?
定义vue组件是一个Class类,如果data不是函数,实例化出来的每一个vue实例的data都是一样的,相互影响。data是函数,实例化的时候函数会形成一个闭包,不同实例之间的data数据不会相互影响。
ajax请求放在哪个生命周期?
mounted. 等页面渲染挂载完成,再请求数据,渲染数据。由于js是单线程的,ajax异步获取数据,放在mounted之前没有用(即便你先拿到数据,页面没渲染完成,数据也是在异步队列中),只会让逻辑更加混乱。
注意:如果父组件请求接口拿到的数据,需要传给子组件,这个请求需要放到created。因为父子组件的生命周期执行顺序是:父created-子craeted-子mounted-父mounted。
vue常见性能优化方式
- 合理使用 v-show 和 v-if
- 合理使用 computed
- v-for 加 key,避免和 v-if 同时使用
- 自定义事件、DOM事件及时销毁(内存泄漏)
- 合理使用异步组件(大的第三方组件)
- 合理使用 keep-alive
- data层级不要太深(响应式监听一次会监听到最底层)
用 vnode 描述一个 DOM 结构
<div class="container">
<p>vdom</p>
</div>
{
tag: 'div',
props: {
className: 'container'
},
children: [
{
tag: 'p',
children: 'vdom'
}
]
}
何时需要使用 beforeDestroy
-
解绑自定义事件 event.$off
-
清除定时器
-
解绑自定义的 DOM 事件,如 window.onscroll 等
Vue原理
Vue工作机制
MVVM
MVVM模型:model-view-viewmodel
核心是viewmodel,充当两个方向的桥梁。
- model->view 数据绑定(Directives)
- view->model Dom事件监听(Dom Listeners)
响应式原理
Vue2
利用 Object.defineProperty,对 data 里的每一个属性的 get 和 set 都重新定义(数据劫持),从而可以监听属性的变化。在 get 的时候通过依赖收集器收集依赖(Watcher),在 set 的时候通知相应的依赖去更新。
缺点:
- 深度监听,需要递归到底,一次性计算量大
- 无法监听新增属性、删除属性(Vue.set Vue.delete解决)
- 无法原生监听数组变化,需特殊处理
Vue3
利用 Proxy 做数据劫持。
优点:
- data属性访问到哪一层就响应式监听到哪一层
- 可以监听对象、数组的变化
缺点:兼容性差,无法 polyfill
Object.defineProperty不能监听数组变化,为什么Vue2可以?
Vue改写了data里的数组属性的原型链,使其等于Vue自定义的数组类的原型,在访问数组属性的方法时,实际上调用的是Vue自定义的数组方法,并且在这里会执行一次视图更新方法,从而监听数组变化。
v-model双向绑定原理
模型到视图:input框的value属性设置为data里的某个属性
视图到模型:利用input框的@input事件,在输入框发生变化时,触发input事件,把data里绑定给input框的属性的值设置为当前输入框的event.target.value。由于data是响应式的,所以依赖data属性的地方都会自动更新。
模板编译
概述
通过模板编译实现依赖收集,让视图和模型产生联系,在模型发生变化时,根据依赖关系更新视图。
将template模板内容编译成 Js 代码,先编译成 render 函数,再编译成 vnode。
组件渲染/更新过程
- 解析模板,生成 render 函数,执行 render 函数,触发 data 里的 getter,并进行依赖收集。(模板里用到了哪个变量,用一个wather观察起来)
- 修改 data 里的某个属性值,触发其 setter 方法,通知相应的 watcher 更新,重新调用 render 函数
初次渲染过程
- 解析模板为 render 函数
- 触发响应式,监听 data 属性的 getter、setter
- 执行 render 函数,生产 vnode ,打补丁调用 patch(ele, vnode),生成 dom
更新过程
- 修改 data ,触发 setter (此前在 getter 中已监听)
- 通知 watcher 更新,重新调用 render 函数,生成 newVnode
- 打补丁,调用 patch(vnode, newVnode),生成最终的 dom
异步渲染
- $nextTick 在 dom 渲染之后触发回调
- 汇总 data 的修改,一次性更新视图
- 减少 DOM 操作次数,提高性能