vue推荐在绝大多数情况下使用模板来创建html,但是在一些特殊的场景,需要JavaScript的完全编程的能力,这个时候就可以使用渲染函数,比模板更接近编译器
vue在生成真实的DOM之前,会将所有的节点转换成VNode,而VNode组合在一起形成一颗树结构,就是虚拟DOM(VDOM)
template中的html最终也会使用渲染函数生成对应的VNode
可以使用JavaScript编写createVNode函数,生成对应的VNode
h()函数是一个用于创建vnode的一个函数
h()函数怎么使用?
h()函数接收三个参数
第一个参数:是标签的名称、组件、异步组件或者函数式组件
第二个参数:标签的属性,
第三参数:标签中的内容
注意:如果没有props,那么通常可以将children作为第二参数传入
如果产生歧义,可以将numm作为第二个参数传入,将children作为第三个参数传入
如果使用render函数的话,就不需要写template标签了
<script> import {h} from "vue" export default { render() { return h('h2',{ class:'text' },'hello word') }, }; </script>
使用·h函数实现一个计数器
<script> import {h} from "vue" export default { data(){ return { counter:0 } }, render() { return h('div',{ class:'app' },[ h('h2',null,`当前计数:${this.counter}`), h('button',{ onClick:()=>this.counter++ },'+1'), h('button',{ onClick:()=>this.counter-- },'-1') ]) }, }; </script>
也可以使用setup替代data使用
<script> import {h,ref} from "vue" export default { setup(){ const counter=ref(0) return {counter} }, render() { return h('div',{ class:'app' },[ h('h2',null,`当前计数:${this.counter}`), h('button',{ onClick:()=>this.counter++ },'+1'), h('button',{ onClick:()=>this.counter-- },'-1') ]) }, }; </script>
也可以在setup中写render函数
<script> import {h,ref} from "vue" export default { setup(){ const counter=ref(0) return ()=>{ return h('div',{ class:'app' },[ h('h2',null,`当前计数:${counter.value}`), h('button',{ onClick:()=>counter.value++ },'+1'), h('button',{ onClick:()=>counter.value-- },'-1') ]) } }, }; </script>
接收的参数第一个是组件的情况
hellowrd.vue
<script> import {h} from 'vue' export default { render(){ return h("h2",null,'hello word') } } </script>
app.vue
<script> import { h } from "vue"; import helloword from "./1/helloword.vue"; export default { render() { return h(helloword, null, ""); }, }; </script>
也可以传入插槽
app.vue
<script> import { h } from "vue"; import helloword from "./1/helloword.vue"; export default { render() { return h(helloword, null, { default:props=>h('span',null,'传到helloword的内容') }); }, }; </script>
helloword.vue
<script> import {h} from 'vue' export default { render(){ return h("div",null,[ h('h2',null,'helloword'), this.$slots.default ? this.$slots.default() : h('span',null,'插槽默认值'), ]) } } </script>
再看jsx
如果要在项目中使用jsx,就需要添加对jsx的支持
jsx通过babel来进行转换,在vue中配置对应的插件即可
安装插件
npm install @vue/babel-plugin-jsx
在bable.config.js配置插件
module.exports = { presets: [ '@vue/cli-plugin-babel/preset' ], plugins:[ '@vue/babel-plugin-jsx' ] }
<script> export default { data(){ return { counter:0 } }, render(){ const increment=()=>this.counter++ const decrement=()=>this.counter-- return ( <div> <h2>当前计数:{this.counter}</h2> <button onClick={increment}>+</button> <button onClick={decrement}>-</button> </div> ) } } </script>
也可以使用组件的时候传入一个插槽
<script> import helloword from "./helloword.vue" export default { data(){ return { counter:0 } }, render(){ const increment=()=>this.counter++ const decrement=()=>this.counter-- return ( <div> <h2>当前计数:{this.counter}</h2> <button onClick={increment}>+</button> <button onClick={decrement}>-</button> <helloword> {{default:props=><button>按钮</button>}} </helloword> </div> ) } } </script>
helloword.vue
<script> export default { render(){ return ( <div> <h2>hello word</h2> {this.$slots.default ? this.$slots.default():<span>hello</span>} </div> ) } } </script>