怎吗提升
vue的HTML模板到啦最后会被写进render(渲染函数)中
代码示例
<template>
<img alt="Vue logo" src="./assets/logo.png" />
<HelloWorld msg="Hello Vue 3.0 + Vite" />
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
components: {
HelloWorld
}
}
</script>
如图
蓝色框中是经过效率提升的,将一些不会改变的静态值提出来,
红色框中是渲染函数
静态提升
何为静态何为动态
静态: 在vue的HTML模板中,当不需要数据响应式,都是固定死的属性或文本都是静态的
<template>
<h1> I am title </h1>
<h1 class="title"> I am title </h1>
<img src="../assets/logo.png" alt="">
</template>
动态:显示的文本或属性都是响应式数据的称之为动态
<template>
<h1>{{ msg }}</h1>
<button @click="count++">count is: {{ count }}</button>
</template>
静态节点提升
那些静态节点会被提升
- 元素节点
- 没有绑定动态内容 ```vue // vue2 的静态节点 render(){ createVNode(“h1”, null, “Hello World”) // … }
// vue3 的静态节点 const hoisted = createVNode(“h1”, null, “Hello World”) function render(){ // 直接使用 hoisted 即可 }
<a name="Fp82B"></a>
### 静态属性提升
```vue
<div class="user">
{{user.name}}
</div>
const hoisted = { class: "user" }
function render(){
createVNode("div", hoisted, user.name)
// ...
}
预字符串化
预字符串话需要大量连续的静态节点才会触发,最少也要20个起步,如果不是大量连续的话还是会用vue2的方式
<div class="menu-bar-container">
<div class="logo">
<h1>logo</h1>
</div>
<ul class="nav">
<li><a href="">menu</a></li>
<li><a href="">menu</a></li>
<li><a href="">menu</a></li>
<li><a href="">menu</a></li>
<li><a href="">menu</a></li>
</ul>
<div class="user">
<span>{{ user.name }}</span>
</div>
</div>
当编译器遇到大量连续的静态内容,会直接将其编译为一个普通字符串节点
const _hoisted_2 = _createStaticVNode("<div class=\"logo\"><h1>logo</h1></div><ul class=\"nav\"><li><a href=\"\">menu</a></li><li><a href=\"\">menu</a></li><li><a href=\"\">menu</a></li><li><a href=\"\">menu</a></li><li><a href=\"\">menu</a></li></ul>")
vue2的渲染虚拟节点树的示意图,vue2会将所有的节点重新渲染
vue3虚拟节点树 vue3会将重新渲染动态,静态节点不会再次渲染
缓存事件处理函数
vue3对事件的缓存,vue3会认为触发这次事件而启动的事件函数,下次再触发事件不会换成一个新事件函数。故而将事件函数缓存起来
<button @click="count++">plus</button>
// vue2
render(ctx){
return createVNode("button", {
onClick: function($event){
ctx.count++;
}
})
}
// vue3 当事件有缓存会直接使用缓存好的事件,如果没有缓存事件将会给该缓存事件赋值
render(ctx, _cache){
return createVNode("button", {
onClick: cache[0] || (cache[0] = ($event) => (ctx.count++))
})
}
虚拟dom树的比对
block Tree
vue2在对比新旧树的时候,并不知道哪些节点是静态的,哪些是动态的,因此只能一层一层比较,这就浪费了大部分时间在比对静态节点上
示例代码
<form>
<div>
<label>账号:</label>
<input v-model="user.loginId" />
</div>
<div>
<label>密码:</label>
<input v-model="user.loginPwd" />
</div>
</form>
vue2 的比对方式示意图 vue2会将所有节点节点进行对比
vue3的比对方式示意图
上图中灰色的是静态节点,橙色的是动态,黑色是根节点
vue3 的虚拟dom树对比,根节点下会有一个装有所有动态节点的数组,每个根节点下都是一个块也就是一个区域,这样会跳过静态节点
PathFlag
vue3 会觉得对比某一节点还是会浪费效率,因为不知道该节点改变啦啥,就需要对该节点比对内容,属性,PathFlag会记录该动态节点哪一点是动态的
当我们修改为动态内容
示例代码
<template>
<h1>{{ msg }}</h1>
<img alt="Vue logo" src="./assets/logo.png" />
<HelloWorld msg="Hello Vue 3.0 + Vite" />
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
components: {
HelloWorld
},
data() {
return {
msg: "我是动态内容"
}
}
}
</script>
h1元素是动态内容,当我们查看浏览器中编译好文件:
图中显示的代码
import {toDisplayString as _toDisplayString, createVNode as _createVNode, resolveComponent as _resolveComponent, Fragment as _Fragment, openBlock as _openBlock, createBlock as _createBlock} from "/@modules/vue.js"
const _hoisted_1 = /*#__PURE__*/
_createVNode("img", {
alt: "Vue logo",
src: "/src/assets/logo.png"
}, null, -1 /* HOISTED */
)
export function render(_ctx, _cache, $props, $setup, $data, $options) {
const _component_HelloWorld = _resolveComponent("HelloWorld")
return (_openBlock(),
_createBlock(_Fragment, null, [_createVNode("h1", null, _toDisplayString($data.msg), 1 /* TEXT */
), _hoisted_1, _createVNode(_component_HelloWorld, {
msg: "Hello Vue 3.0 + Vite"
})], 64 /* STABLE_FRAGMENT */
))
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkU6XFzns7vnu5/pu5jorqRcXOahjOmdolxcdml0ZVxc5pWI546H5o+Q5Y2HXFx4aWFvbHZcXHNyY1xcQXBwLnZ1ZSJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztnQ0FFRSxhQUE4QztFQUF6QyxHQUFHLEVBQUMsVUFBVTtFQUFDLEdBQUcsRUFBQyxzQkFBbUI7Ozs7Ozs7SUFEM0MsYUFBa0IsNkJBQVgsU0FBRztJQUNWLFVBQThDO0lBQzlDLGFBQXlDLHlCQUE3QixHQUFHLEVBQUMsc0JBQXNCIiwiZmlsZSI6IkU6L+ezu+e7n+m7mOiupC/moYzpnaIvdml0ZS/mlYjnjofmj5DljYcveGlhb2x2L3NyYy9BcHAudnVlIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIjx0ZW1wbGF0ZT5cbiAgPGgxPnt7IG1zZyB9fTwvaDE+XG4gIDxpbWcgYWx0PVwiVnVlIGxvZ29cIiBzcmM9XCIuL2Fzc2V0cy9sb2dvLnBuZ1wiIC8+XG4gIDxIZWxsb1dvcmxkIG1zZz1cIkhlbGxvIFZ1ZSAzLjAgKyBWaXRlXCIgLz5cbjwvdGVtcGxhdGU+XG5cbjxzY3JpcHQ+XG5pbXBvcnQgSGVsbG9Xb3JsZCBmcm9tICcuL2NvbXBvbmVudHMvSGVsbG9Xb3JsZC52dWUnXG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgbmFtZTogJ0FwcCcsXG4gIGNvbXBvbmVudHM6IHtcbiAgICBIZWxsb1dvcmxkXG4gIH0sXG4gIGRhdGEoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG1zZzogXCLmiJHmmK/liqjmgIHlhoXlrrlcIlxuICAgIH1cbiAgfVxufVxuPC9zY3JpcHQ+XG4iXX0=
如上图你会发现h1元素在渲染函数中打上啦标签 也就是 1 /* TEXT */
这个标签就说明这动态节点的内容是动态的
当我们修改为动态类名
示例代码
<template>
<h1 :class="msg">{{ msg }}</h1>
<img alt="Vue logo" src="./assets/logo.png" />
<HelloWorld msg="Hello Vue 3.0 + Vite" />
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
components: {
HelloWorld
},
data() {
return {
msg: "我是动态内容"
}
}
}
</script>
浏览里编译好的代码为:
图中显示的代码为
import {toDisplayString as _toDisplayString, createVNode as _createVNode, resolveComponent as _resolveComponent, Fragment as _Fragment, openBlock as _openBlock, createBlock as _createBlock} from "/@modules/vue.js"
const _hoisted_1 = /*#__PURE__*/
_createVNode("img", {
alt: "Vue logo",
src: "/src/assets/logo.png"
}, null, -1 /* HOISTED */
)
export function render(_ctx, _cache) {
const _component_HelloWorld = _resolveComponent("HelloWorld")
return (_openBlock(),
_createBlock(_Fragment, null, [_createVNode("h1", {
class: _ctx.msg
}, _toDisplayString(_ctx.msg), 3 /* TEXT, CLASS */
), _hoisted_1, _createVNode(_component_HelloWorld, {
msg: "Hello Vue 3.0 + Vite"
})], 64 /* STABLE_FRAGMENT */
))
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkU6XFzns7vnu5/pu5jorqRcXOahjOmdolxcdml0ZVxc5pWI546H5o+Q5Y2HXFx4aWFvbHZcXHNyY1xcQXBwLnZ1ZSJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztnQ0FFRSxhQUE4QztFQUF6QyxHQUFHLEVBQUMsVUFBVTtFQUFDLEdBQUcsRUFBQyxzQkFBbUI7Ozs7Ozs7SUFEM0MsYUFBK0IsUUFBMUIsS0FBSyxFQUFFLFFBQUcscUJBQUssUUFBRztJQUN2QixVQUE4QztJQUM5QyxhQUF5Qyx5QkFBN0IsR0FBRyxFQUFDLHNCQUFzQiIsImZpbGUiOiJFOi/ns7vnu5/pu5jorqQv5qGM6Z2iL3ZpdGUv5pWI546H5o+Q5Y2HL3hpYW9sdi9zcmMvQXBwLnZ1ZSIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyI8dGVtcGxhdGU+XG4gIDxoMSA6Y2xhc3M9XCJtc2dcIj57eyBtc2cgfX08L2gxPlxuICA8aW1nIGFsdD1cIlZ1ZSBsb2dvXCIgc3JjPVwiLi9hc3NldHMvbG9nby5wbmdcIiAvPlxuICA8SGVsbG9Xb3JsZCBtc2c9XCJIZWxsbyBWdWUgMy4wICsgVml0ZVwiIC8+XG48L3RlbXBsYXRlPlxuXG48c2NyaXB0PlxuaW1wb3J0IEhlbGxvV29ybGQgZnJvbSAnLi9jb21wb25lbnRzL0hlbGxvV29ybGQudnVlJ1xuXG5leHBvcnQgZGVmYXVsdCB7XG4gIG5hbWU6ICdBcHAnLFxuICBjb21wb25lbnRzOiB7XG4gICAgSGVsbG9Xb3JsZFxuICB9LFxuICBkYXRhKCkge1xuICAgIHJldHVybiB7XG4gICAgICBtc2c6IFwi5oiR5piv5Yqo5oCB5YaF5a65XCJcbiAgICB9XG4gIH1cbn1cbjwvc2NyaXB0PlxuIl19
从上图我画蓝框中显示的内容为3 /* TEXT, CLASS */
可以看出class为2 后面的内容就提示出啦该节点的内容与类名是动态的
当是动态属性为
示例代码
<template>
<h1 :title="msg">h1</h1>
<img :alt=" msg" src="./assets/logo.png" />
<HelloWorld msg="Hello Vue 3.0 + Vite" />
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
components: {
HelloWorld
},
data() {
return {
msg: "我是动态内容"
}
}
}
</script>
图中显示的代码为
import {createVNode as _createVNode, resolveComponent as _resolveComponent, Fragment as _Fragment, openBlock as _openBlock, createBlock as _createBlock} from "/@modules/vue.js"
export function render(_ctx, _cache) {
const _component_HelloWorld = _resolveComponent("HelloWorld")
return (_openBlock(),
_createBlock(_Fragment, null, [_createVNode("h1", {
title: _ctx.msg
}, "h1", 8 /* PROPS */
, ["title"]), _createVNode("img", {
alt: _ctx.msg,
src: "/src/assets/logo.png"
}, null, c
, ["alt"]), _createVNode(_component_HelloWorld, {
msg: "Hello Vue 3.0 + Vite"
})], 64 /* STABLE_FRAGMENT */
))
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkU6XFzns7vnu5/pu5jorqRcXOahjOmdolxcdml0ZVxc5pWI546H5o+Q5Y2HXFx4aWFvbHZcXHNyY1xcQXBwLnZ1ZSJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7SUFDRSxhQUF3QixRQUFuQixLQUFLLEVBQUUsUUFBRyxJQUFFLElBQUU7SUFDbkIsYUFBMkM7TUFBckMsR0FBRyxHQUFHLFFBQUc7TUFBRSxHQUFHLEVBQUMsc0JBQW1COztJQUN4QyxhQUF5Qyx5QkFBN0IsR0FBRyxFQUFDLHNCQUFzQiIsImZpbGUiOiJFOi/ns7vnu5/pu5jorqQv5qGM6Z2iL3ZpdGUv5pWI546H5o+Q5Y2HL3hpYW9sdi9zcmMvQXBwLnZ1ZSIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyI8dGVtcGxhdGU+XG4gIDxoMSA6dGl0bGU9XCJtc2dcIj5oMTwvaDE+XG4gIDxpbWcgOmFsdD1cIiBtc2dcIiBzcmM9XCIuL2Fzc2V0cy9sb2dvLnBuZ1wiIC8+XG4gIDxIZWxsb1dvcmxkIG1zZz1cIkhlbGxvIFZ1ZSAzLjAgKyBWaXRlXCIgLz5cbjwvdGVtcGxhdGU+XG5cbjxzY3JpcHQ+XG5pbXBvcnQgSGVsbG9Xb3JsZCBmcm9tICcuL2NvbXBvbmVudHMvSGVsbG9Xb3JsZC52dWUnXG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgbmFtZTogJ0FwcCcsXG4gIGNvbXBvbmVudHM6IHtcbiAgICBIZWxsb1dvcmxkXG4gIH0sXG4gIGRhdGEoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG1zZzogXCLmiJHmmK/liqjmgIHlhoXlrrlcIlxuICAgIH1cbiAgfVxufVxuPC9zY3JpcHQ+XG4iXX0=
你会发现动态属性为 "h1", 8 /* PROPS */