跳到主要内容

认识

2024年03月13日
柏拉文
越努力,越幸运

一、认识


二、细节


2.1 解析

<h1 v-if="isShow">你好,世界</h1>

解析成如下的 AST

{
type: "1",
ns: 0,
tag: h1,
tagType:0,
props: [
{
type: 7,
name: 'if',
exp: {
type: 4,
content: "isShow",
isStatic: false,
constType: 0
}
}
]
}

2.2 转换

转换生成的 JavaScript AST 如下:

{
type: 9,
branches: [
{
type: 10,
condition: {
type: 4,
content: "isShow",
isStatic: false,
loc: {}
},
children: [
{
type: 1,
tag: h1,
tagType: 0,
children: [
{
type: 2,
content: "你好,世界"
}
],
codegenNode: {
type: 13,
tag: "h1",
children: [
{
type: 2,
content: "你好,世界"
}
]
}
}
]
}
]
}

2.3 生成

生成的渲染函数如下所示:

(function anonymous(
) {
const _Vue = Vue

return function render(_ctx, _cache) {
with (_ctx) {
const { createElementVNode: _createElementVNode, createCommentVNode: _createCommentVNode } = _Vue

return _createElementVNode("div", [], [isShow ?_createElementVNode("h1", null, ["你好,世界"]) : _createCommentVNode("v-if", true)])
}
}
})

因此, v-if 节点的处理结果是一个三元表达式

问题一、 isShow 变量是哪里来的呢?

const _ctx = {
isShow: true
}

function render(_ctx){
with(_ctx){
console.log("isShow",isShow)
}
}

问题二、render 在哪里调用的呢?

export function renderComponentRoot(instance) {
const { type, vnode, render, data = {} } = instance;
let result;
try {
if (vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
result = normalizeVNode(render.call(data, data));
}
} catch (error) {
console.log(error);
}
return result;
}

由上可知, render 函数的 this 指向为 data , render(_ctx) 中的 _ctx 也为 data

2.4 渲染

三、问题


3.1 Vue.js 3.0 v-if 与 v-for 的优先级?

Vue.js 3.0 中, 在同一元素上使用 v-ifv-for 时, v-ifv-for 的优先级更高(源码中 v-if 指令优先被处理), 这意味着 v-if 的条件将无法访问到 v-for 作用域内定义的变量别名。正确的做法是通过 computed 筛选需要渲染的元素 或者通过将 v-forv-if 分开使用即可。