why?
在绝大多数情况下,Vue 推荐使用模板语法来创建应用。然而在某些使用场景下,我们真的需要用到 JavaScript 完全的编程能力。这时渲染函数就派上用场了。
例如:下方要在多个模型上方设置对话框,如果使用Vue模板语法相对较困难(要确保对话框位置相对正确,要产生多个实例),用渲染函数相对更加简单[JS循环]
Vue模板语法、渲染函数两种方式,选择恰当的一个就行!
渲染管线
从高层面的视角看,Vue 组件挂载时会发生如下几件事:
-
编译:Vue 模板被编译为渲染函数:即用来返回虚拟 DOM 树的函数。这一步骤可以通过构建步骤提前完成,也可以通过使用运行时编译器即时完成。
-
挂载:运行时渲染器调用渲染函数,遍历返回的虚拟 DOM 树,并基于它创建实际的 DOM 节点。这一步会作为响应式副作用执行,因此它会追踪其中所用到的所有响应式依赖。
-
更新:当一个依赖发生变化后,副作用会重新运行,这时候会创建一个更新后的虚拟 DOM 树。运行时渲染器遍历这棵新树,将它与旧树进行比较,然后将必要的更新应用到真实 DOM 上去。
渲染函数
Vue3
import { h } from 'vue'
const vnode = h(
'div', // type
{ id: 'foo', class: 'bar' }, // props
[
/* children */
]
)
h()
是 hyperscript 的简称——意思是“能生成 HTML (超文本标记语言) 的 JavaScript”。这个名字来源于许多虚拟 DOM 实现默认形成的约定。一个更准确的名称应该是 createVnode()
,但当你需要多次使用渲染函数时,一个简短的名字会更省力。
h()
函数的使用方式非常的灵活:
// 除了类型必填以外,其他的参数都是可选的
h('div')
h('div', { id: 'foo' })
// attribute 和 property 都能在 prop 中书写
// Vue 会自动将它们分配到正确的位置
h('div', { class: 'bar', innerHTML: 'hello' })
// 像 `.prop` 和 `.attr` 这样的的属性修饰符
// 可以分别通过 `.` 和 `^` 前缀来添加
h('div', { '.name': 'some-name', '^width': '100' })
// 类与样式可以像在模板中一样
// 用数组或对象的形式书写
h('div', { class: [foo, { bar }], style: { color: 'red' } })
// 事件监听器应以 onXxx 的形式书写
h('div', { onClick: () => {} })
// children 可以是一个字符串
h('div', { id: 'foo' }, 'hello')
// 没有 props 时可以省略不写
h('div', 'hello')
h('div', [h('span', 'hello')])
// children 数组可以同时包含 vnodes 与字符串
h('div', ['hello', h('span', 'hello')])
Vue模板语法多数可以直接用渲染函数(更底层)直接实现
Vue2
在 Vue 2 中,渲染函数(Render Functions)同样提供了一种比模板(Templates)更底层、更灵活的方式来描述组件的输出。不过,与 Vue 3 稍有不同的是,Vue 2 的渲染函数直接接收一个名为 createElement
的函数作为参数,虽然 Vue 2 的社区中也经常使用 h
作为 createElement
的别名(这需要通过额外的配置或插件来实现,比如 Babel 插件),但 Vue 2 的官方文档和默认配置中并没有直接提供 h
作为 createElement
的别名。
在 Vue 2 的组件中,你可以通过定义一个 render
函数来使用渲染函数,该函数接收一个 createElement
参数,并返回一个虚拟节点(VNode)。这个虚拟节点描述了组件的 DOM 结构。
下面是一个 Vue 2 组件中使用渲染函数的例子:
// 假设没有使用 h 作为 createElement 的别名
export default {
data() {
return {
message: 'Hello, Vue 2!'
};
},
render(createElement) {
// 使用 createElement 创建 VNode
return createElement('div', this.message);
}
}
createApp()函数
createApp
函数是Vue 3中用于创建一个新的Vue应用实例的API。它是Vue 3的入口点,允许你定义根组件,并挂载这个Vue应用到DOM中的某个元素上
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
//挂载
app.mount('#app')
在Vue2中使用new Vue()构建Vue实例
const createDialog = (opts) => {
if (parentNode) {
document.body.removeChild(parentNode);
parentNode = null;
}
const instance=new Vue({
render: (h) => {
// let properties={...opts}
// console.log(properties)
return h(dialog,{
...opts}
)
}
})
parentNode = document.createElement('div');
// 挂载
instance.$mount(parentNode)
document.body.appendChild(parentNode);
// vue3中新建一个vm实例
// const app = createApp({
// // render() {
// // // 这个是属性传递入口
// return h(dialog, {
// ...opts,
// });
// },
// });
// parentNode = document.createElement('div');
// const instance = app.mount(parentNode);
// document.body.appendChild(parentNode);
return {
vmInstance: instance,
};
};