参考来源:time.geekbang.org/column/intr…
作者:杨文坚
1. render
, template
, el
顺序
render
优先级最高 > 其次template
> 最后el
2.代码参考
_ctx
代表组件的上下文对象,它封装了组件实例的所有可访问属性,包括但不限于props、data、methods、computed properties等。在Vue 3的Composition API中,尽管我们倾向于使用setup
函数内部声明的响应式变量(如ref
和reactive
创建的),但在某些情况下,直接访问_ctx
仍然有用,尤其是在与Vue的生命周期钩子、自定义指令或其他需要访问组件实例属性的场景中。
2.
_cache
主要用于优化渲染性能。Vue在渲染函数模式下,会尝试利用纯函数的特性进行优化。当渲染函数被多次调用时,Vue会检查是否可以复用之前的计算结果,从而避免不必要的计算和DOM操作。_cache
数组就扮演了这个角色,Vue会自动管理它,开发者也可以直接利用它来手动缓存数据。
const Counter = {
setup() {
const num = ref(0);
const complexCalculation = (n) => {
// 假设这是一个复杂的计算过程
for(let i = 0; i < 100000; i++) {
// ...计算逻辑
}
return `计算结果: ${n * n}`;
};
return (_ctx, _cache) => {
if (!_cache[0]) {
// 首次计算并将结果存储在_cache中
_cache[0] = complexCalculation(num.value);
} else if (num.value !== _cache[1]) {
// 当依赖变化时,重新计算并更新_cache
_cache[0] = complexCalculation(num.value);
_cache[1] = num.value; // 记录最新依赖值
}
return h('div', { class: 'v-counter' }, [
h('div', { class: 'v-text' }, _cache[0]),
h('button', { class: 'v-btn', onClick: () => num.value++ }, '点击加1')
]);
};
},
};
- _ctx提供了对组件实例属性和方法的访问途径,尽管在Composition API中直接使用setup内的变量更为常见。
- _cache则是Vue内部用于优化渲染性能的工具,开发者可以直接利用它来存储中间计算结果,避免不必要的重复计算。
<html>
<head>
<style>
.v-counter {
width: 400px;
margin: 20px auto;
padding: 10px;
color: #666666;
box-shadow: 0px 0px 9px #00000066;
text-align: center;
}
.v-counter .v-text {
font-size: 28px;
font-weight: bolder;
}
.v-counter .v-btn {
font-size: 20px;
padding: 0 10px;
height: 32px;
cursor: pointer;
}
</style>
<script src="https://unpkg.com/vue@3.2.37/dist/vue.global.js" ></script>
<!-- <script src="./node_modules/vue/dist/vue.global.js" ></script> -->
</head>
<body>
<div id="app">
<div>此处是el的数据{{ num }}</div>
<button>el按钮+1</button>
</div>
</body>
<script>
(function() {
const { h,toDisplayString,createApp, ref, createVNode,createElementVNode } = window.Vue;
const Counter = {
template: `
<div class="v-counter">
<div class="v-text">{{ num }}</div>
<button class="v-btn" @click="click">点击加1</button>
</div>
`,
setup() {
const num = ref(0)
const click = () => {
num.value += 1;
}
return {
num,
click
}
}
}
const CreateElementVNodeCounter = {
setup() {
const num = ref(0)
const click = () => {
num.value += 1;
}
return (_ctx, _cache) => {
return (
createElementVNode('div', { class: 'v-counter' }, [
createElementVNode('div', { class: 'v-text' }, toDisplayString(num.value)),
createElementVNode("button", { class: 'v-btn', onClick: click }, "CreateElementVNode点击加1")
])
)
}
}
}
const HCounter = {
setup() {
const num = ref(0)
const click = () => {
num.value += 1;
}
return (_ctx, _cache) => {
return h('div', { class: 'v-counter' }, [
h('div', { class: 'v-text' }, toDisplayString(num.value)),
h('button', {
class: 'v-btn',
onClick: click
}, "h函数点击加1")
])
}
}
}
const RenderCounter = {
template: `
<div class="v-counter">
<div class="v-text">{{ num }}</div>
<button class="v-btn" @click="click">render点击加1</button>
</div>
`,
setup() {
const num = ref(0)
const click = () => {
num.value += 1;
}
return {
num,
click
}
}
}
// 组件挂载渲染
const app = createApp({
template: `<div>
<v-counter />
<CreateElementVNodeCounter />
<h-counter />
<v-render-counter />
</div>`,
// render() {
// return createVNode(RenderCounter)
// }
});
app.component('v-counter', Counter)
app.component('v-render-counter', RenderCounter)
app.component('h-counter', HCounter)
app.component('CreateElementVNodeCounter', CreateElementVNodeCounter)
app.mount('#app')
})()
</script>
</html>