render function
Vue 编译流程
- 将
template模板/template选项/render函数
转化为 AST - vue 将 AST 转化为 VNode
- 对比 VNode 看是否需要更新, 如果需要更新就去更新
render 函数和 template 的不同
template 是直接使用模板, 在模板中可以通过 this 来访问组件实例的数据, 然后 Vue 的会将这个模板编译为 AST 语法树 这个 AST 语法树是 用来描述 dom 结构的
, 而 render 函数不同, 他是直接 让你自己写 AST
, 然后通过一些函数, 将 AST 树转化成 VNode
用 render 函数替代 template 模板
html
<div class="login-form-card">
<div class="card-title">
<slot name="title">标题</slot>
</div>
<form :action="actionUrl" class="card-content">
<div class="form-item">
<input
type="text"
v-model="loginForm.email"
name="email"
placeholder="请输入邮箱"
/>
</div>
<div class="form-item">
<input
type="password"
v-model="loginForm.password"
name="password"
placeholder="请输入密码"
/>
</div>
<div class="form-item">
<button class="submit-btn" type="button" @click="onSubmit">
{{btnText}}
</button>
</div>
</form>
</div>
Vue2 实现
Vue2 render 函数语法
js
// Vue2: h函数是 render 函数的形参, 可以自己任意命名
render (h) {
// h函数语法:
// h(标签名, 数据对象, 子节点)
// 1. 如果子节点是 元素节点: 就必须用数组 [子节点] 语法, 如果子节点是文本节点, 可以直接写
// 2. 数据对象: https://cn.vuejs.org/v2/guide/render-function.html#%E6%B7%B1%E5%85%A5%E6%95%B0%E6%8D%AE%E5%AF%B9%E8%B1%A1
}
实现
js
export default {
name: "login-form-card",
data: () => ({
actionUrl: "http://localhost:8888/api/login",
btnText: "登录",
loginForm: {
email: "",
password: "",
},
}),
emits: ["submit"],
methods: {
onSubmit() {
console.info(this.loginForm);
this.$emit("submit", this.loginForm);
},
},
render(h) {
return h(
"div",
{ class: "login-form-card" },
[
h(
"div",
{ class: "card-title" },
this.$slots.title, // 插槽
),
h(
"form",
{
attrs: { action: this.actionUrl },
class: "card-content"
},
[
h(
"div",
{ class: "form-item" },
[
h(
"input",
{
attrs: {
type: "text",
name: "email",
placeholder: "请输入邮箱",
// v-model: 本质就是 value + oninput
value: this.loginForm.email,
},
on: {
input: (e) => this.loginForm.email = e.target.value
}
}
)
]
),
h(
"div",
{ class: "form-item" },
[
h(
"input", {
attrs: {
type: "password",
name: "password",
placeholder: "请输入密码",
value: this.loginForm.password,
},
on: {
input: (e) => this.loginForm.password = e.target.value
}
}
)
]
),
h(
"div",
{ class: "form-item" },
[
h(
"button",
{
class: "submit-btn",
attrs: { type: "button" },
on: {
click: this.onSubmit,
}
},
this.btnText
)
]
),
]
),
]
);
},
};
Vue3 实现
Vue3 render 语法
js
// Vue3: h函数是从vue中导出的
import { h } from "vue";
render() {
// h函数语法:
// 1. 所有元素节点都必须用 h 函数来创建
// 2. 标签名必须是一个字符串, 如果没有属性集合可以用 null 代替
// 3. 如果有多个子节点, 必须用数组, 如果只有一个可以直接写, 没有就不用写
// h(标签名, 属性集合, 子节点)
}
js
import { h } from "vue";
export default {
name: "LoginFormCard",
data: () => ({
actionUrl: "http://localhost:8888/api/login",
btnText: "登录",
loginForm: {
email: "",
password: "",
},
}),
emits: ['submit'], // emit 必须申明
methods: {
onSubmit() {
console.log(this.loginForm);
this.$emit('submit', this.loginForm);
},
},
render() {
return h(
"div",
{ class: "form-card" },
[
h("div", { class: "card-title" }, this.$slots.title()), // 插槽
h(
"form",
{ action: this.actionUrl, class: "card-content" },
[
h(
"div",
{ class: "form-item" },
h(
"input",
{
type: "text",
name: "email",
placeholder: "请输入邮箱",
value: this.loginForm.email,
onInput: ($event) => (this.loginForm.email = $event.target.value),
}
)
),
h(
"div",
{ class: "form-item" },
h(
"input",
{
type: "password",
name: "password",
placeholder: "请输入密码",
// 处理: v-model
value: this.loginForm.password,
onInput: (e) => (this.loginForm.password = e.target.value),
}
)
),
h(
"div",
{ class: "form-item" },
h(
"button",
{
type: "button",
class: "submit-btn",
// 处理事件
onClick: () => this.onSubmit(),
},
this.btnText
)
),
]
),
]
);
},
};
JSX
什么是 JSX
- JSX 既不是 HTML 也不是字符串
- JSX 是一种特殊的标签语法, 且无法直接被浏览器识别, 需要用编译器编译成 js
- 描述 UI 呈现与交互的直观的形式的语法
为什么使用 JSX
因为 render 函数的参数结构很复杂, 非常容易写错, 并不直观, 所以也可以使用 jsx 语法
那为什么不直接使用 template 语法?
没说一定要用 render 或者 jsx, 只是提供了一种选项, 让你在一些特殊的场景可以更好的使用 vue
JSX 语法
建议直接 看 React 的笔记, 因为 JSX 语法但是差不多的, 细微的区别直接看文档就好了