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>