Vue3.0的几大亮点
- 性能比vue2.x 快1.2~2倍
- 按需编译,体积比vue2.x更小
- composition Api (组和api类似React Hooks)
- 本身就是ts从写的更好的支持ts
- custom Renderer api 暴露了自定义渲染的api
- Teleport(Protal),Suspense 更先进的组件
Vue.3.0是如何变快的
1.优化了diff算法
- Vue2.x中的虚拟dom是进行全量的对比
- Vue3.x新增了动态标记位(PatchFlag),在与上次虚拟节点进行比较的时候,只对比带有patchflag的节点,并且可以通过flag的信息得知当前节点要对比的具体内容
Vue2.x中首先 div会和div比较h1和h1比较,p和p比较,这就是全量比较,其中只有p标签改变了值,比较的时候是每个节点对比,其中h1的值是写死的根本不会变,按道理就不应该去比较,所以vue3.0做了优化
Vue3.0的比较只比较和追踪带有标记位的
vue-next-template-explorer.netlify.app/
代码示例:
<div>
<h1>这是一个测试</h1>
<h1>这是一个测试</h1>
<h1>这是一个测试</h1>
<p>{{msg}}</p>
</div>
复制代码
import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createElementBlock("div", null, [
_createElementVNode("h1", null, "这是一个测试"),
_createElementVNode("h1", null, "这是一个测试"),
_createElementVNode("h1", null, "这是一个测试"),
_createElementVNode("p", null, _toDisplayString(_ctx.msg), 1 /* TEXT */)
]))
}
// Check the console for the AST
复制代码
在创建虚拟Dom节点的时候,只有p标签插入了一个静态标记位1
下列为标记值所代表的含义:
export const enum PatchFlags {
TEXT = 1, *//动态文字内容*
CLASS = 1 << 1, *// 2 动态 class*
STYLE = 1 << 2, *//4 动态样式*
PROPS = 1 << 3, *//8 动态属性 props (不包含类名和样式)*
FULL_PROPS = 1 << 4, *//16 有动态的key属性,当key改变时需要进行完整的diff比较*
HYDRATE_EVENTS = 1 << 5, *//32 带有监听事件的节点*
STABLE_FRAGMENT = 1 << 6, *//64 一个不会改变子节点顺序的 fragment*
KEYED_FRAGMENT = 1 << 7, *// 128 带有key的节点的fragment或者部分子节点带有key*
UNKEYED_FRAGMENT = 1 << 8, *//256 子节点没有key的fragment*
NEED_PATCH = 1 << 9, *//512 一个节点只会进行非props比较,比如`ref`*
*// 动态的插槽*
DYNAMIC_SLOTS = 1 << 10,
*// SPECIAL FLAGS -------------------------------------------------------------*
*// 以下是特殊的flag,不会在优化中被用到,是内置的特殊flag*
*// 表示他是静态节点,他的内容永远不会改变,对于hydrate的过程中,不会需要再对其子节点进行diff*
HOISTED = -1,
*// 用来表示一个节点的diff应该结束*
BAIL = -2,
}
复制代码
2. hoistStatic (静态提升)
这个是没有添加静态提升的代码,无论是更新还是不需要更新的每次都要从新生成节点 列如:3个p标签 开启静态提升之前:
点击右侧的options选中
开启静态提升以后:
import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
const _hoisted_1 = /*#__PURE__*/_createElementVNode("h1", null, "这是一个测试", -1 /* HOISTED */)
const _hoisted_2 = /*#__PURE__*/_createElementVNode("h1", null, "这是一个测试", -1 /* HOISTED */)
const _hoisted_3 = /*#__PURE__*/_createElementVNode("h1", null, "这是一个测试", -1 /* HOISTED */)
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createElementBlock("div", null, [
_hoisted_1,
_hoisted_2,
_hoisted_3,
_createElementVNode("p", null, _toDisplayString(_ctx.msg), 1 /* TEXT */)
]))
}
// Check the console for the AST
复制代码
选中静态提升的时候,h1的虚拟节点被从render方法中提升到全局变量中,这样就只创建一次,每次render的时候直接复用
3.事件侦听缓存
随便搞个栗子,开启事件侦听缓存之前:
<div>
<button @click='clickEvent'></button>
</div>
复制代码
import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
const _hoisted_1 = ["onClick"]
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createElementBlock("div", null, [
_createElementVNode("button", { onClick: _ctx.clickEvent }, null, 8 /* PROPS */, _hoisted_1)
]))
}
// Check the console for the AST
复制代码
可以看到这个标记位的值是8,被当成了动态属性,这样就会被对比,这里每次都是同一个方法没必要去进行对比
开启事件侦听缓存之后:
标记位没有了,没有被追踪就没有产生对比了
Vue3.0的diff算法中只有有静态标记位的才会对比才会追踪。
Vue中ref和reactive的对比:
reactive
- reactive 是vue3.0提供的响应式数据的方法
- reactive 是通过es6中的proxy来实现的,接收的参数必须是对象(json/arr)传入其他的值不会被监听
- 如果给reactive传递其他对象,默认情况下修改对象,视图不会更新,想要更新可以通过从新赋值的方式.如传入的是时间对象,值其实更新了,视图并灭有改变,想要改变就从新赋值
这样视图是没有更新的
**从新赋值以后视图更新
setup(){
const state=reactive({time:new Date()})
const change=()=>{
//时间从新赋值
let newTime=new Date(state.time.getTime());
newTime.setDate(state.time.getDate()+1);
state.time=newTime;
console.log(state.time)
}
return {
...toRefs(state),
change
}
}
复制代码
Ref
- 1.Ref底层的本质还是 reactive 系统会自动根据我们给ref传入的值将它转化为
- Ref(xx)------->reactive({value:xxx})
- 2. 在模板中获取ref 的值不用通过value,在js中需要,那为什么reactive就不用.value去修改值呢,它是怎么判断的呢
- 3.之所会有ref是因为reactive只监听对象或者数组,想监听某个变量比较繁琐,所以就有了ref可以单独监听某个变量
好了编不下去了,累------未完待续