vue3渲染函數(h函數)的變化

2022-10-27 06:01:06

vue3 渲染函數(h函數)的更改

h函數的更改總結
1==>h 現在全域性匯入,而不是作為引數傳遞給渲染函數
2==>渲染函數引數更改為在有狀態元件和函陣列件之間更加一致
3==>vnode 現在有一個扁平的 prop 結構

h函數的三個引數詳細說明

第一個引數是必須的。【跟原來的是一樣的。沒有發生變化】
型別:{String | Object | Function} 
一個 HTML 標籤名、一個元件、一個非同步元件、或一個函數式元件。
是要渲染的html標籤。
第一個引數div  是表示建立一個div的元素 

第二個引數是可選的。 
【第二個引數的格式發生了變化, 現在是一個扁平的 prop 結構】
型別:{Object} 主要是當前html中的各種屬性。
在開發時。建議傳,實在沒有傳的時候,傳入 null

第三個引數可選的。(第三個引數建議使用函數返回,否者會有警告)
型別:{String | Array | Object} children
虛擬子節點(vnodes),當前html標籤的元素。

ps:第三個引數建議使用函數返回。否者在控制有警告
Non-function value encountered for default slot. Prefer function slots for better performance. 

VNode Props 格式化 vue2.x 語法

{
  class: ['button', 'is-outlined'],
  style: { color: '#34495E' },
  attrs: { id: 'submit' },
  domProps: { innerHTML: '' },
  on: { click: submitForm },
  key: 'submit-button'
}

VNode Props 格式化 vue3.x 語法

{
  class: ['button', 'is-outlined'],
  style: { color: '#34495E' },
  //屬性不需要放在 attrs domProps on這些欄位下了。
  id: 'submit',
  innerHTML: '',
  onClick: submitForm,
  key: 'submit-button'
}

vue2中render 函數將自動接收 h 函數 (它是 createElement 的常規別名) 作為引數

render(h){
    return h('div',{
      //第二個引數
      class:{
        'is-red': true
      }
    },
    //第三個引數  
    [h('p','這是一個render')]
);

vue3 h函數-繫結事件

//renderTest.vue
<script lang="ts">
import { h, reactive } from 'vue'
export default {
  setup(props, { slots, attrs, emit }) {
    const state = reactive({
      count: 0
    })

    function increment() {
      state.count++
    }
    // 返回render函數
    return () =>
      h(
        'button',
        {
          onClick: increment //這裡繫結事件
        },
        state.count
      )
  }
}
</script>

vue3 render函數簡單的迴圈 map

<script lang="ts">
import { h, reactive } from 'vue'
export default {
    setup() {
      const state = reactive({
        listArr: [
          { name: '三悅有了新工作', like: '工作答辯-你為什來這個-為了錢',id:'00' },
          { name: '三悅有了新工作', like: '沒有最好的選擇,那不太壞的選擇也可以吧', id: '01' },
          { name: '三悅有了新工作', like: '沒有最好的選擇,那不太壞的選擇也可以吧', id: '02' },
          { name: '三悅有了新工作', like: '沒有那麼好,就是比什麼都不做多做了一點點而已',id: '03' },
          { name: '三悅有了新工作', like: '能好好說話是因為愛,不能好好說話,是因為太熟悉了就忘了邊界', id: '04' }
        ]
      })
      // 返回render函數
      return () =>
        h(
          'ul',
          null,
          [
            state.listArr.map(item => { //通過map進行迴圈
              return h('li', { key: item.id }, ['劇名:',item.name,'我喜歡的句子:', item.like])
            })
          ]
        )
    }
}
</script>

vue3 預設插槽-slots.default?.()

//renderTest.vue 檔案
<script lang="ts">
import { h } from 'vue'
export default {
  setup(props, { slots }) {
    return () =>
      h(
        'div',
        null,
        [  
          h('h1', null, '我元件的預設內容'), 
          h('h2', null, [slots.default?.()]), 
        ]
      )
  }
}
</script>
//頁面使用 renderTest.vue這個元件
<template>
    <div class="father-div">
        <renderTest>
            <p>預設插槽</p>
        </renderTest>
    </div>
</template>
<script setup lang="ts">
import renderTest from './renderTest.vue'
</script>

具名插槽

//renderTest.vue 檔案
<script lang="ts">
import { h } from 'vue'
export default {
  setup(props, { slots }) {
    return () =>
      h(
        'div',
        null,
        [  
          //第三個引數建議使用函數返回.
          h('h1', null, '我元件的預設內容'), 
          h('h2', null, [slots.details?.()]), 
        ]
      )
  }
}
</script>
//頁面使用 renderTest.vue這個元件
<template>
    <div class="father-div">
        <renderTest>
           <template #details>
             <p>我是具名插槽中的內容</p>
           </template>
        </renderTest>
    </div>
</template>
<script setup lang="ts">
import renderTest from './renderTest.vue'
</script>

props 父傳子
//renderTest.vue
<script lang="ts">
import { h } from 'vue'
export default {
  props: {
    title: {
      type: String
    }
  },
  setup(props, { slots }) {
    return () =>
      h(
        'div',
        null,
        //接受父元件 props傳遞過來的資料,第三個引數建議使用函數返回
        props.title
      )
  }
}
</script>
//頁面使用 renderTest.vue這個元件
<template>
  <div class="father-div">
    <renderTest title="父元件給的資料"></renderTest>
  </div>
</template>
<script setup lang="ts">
import renderTest from './renderTest.vue'
</script>

emit 子傳父

//renderTest.vue 檔案
<script lang="ts">
import { h } from 'vue'
//把按鈕作為標籤需要匯入
import { ElButton } from 'element-plus'
export default {
  props: {
    title: {
      type: String
    }
  },
  setup(props, { emit }) {
    return () =>
      h(
        'div',
        null,
        [ 
          //把按鈕作為標籤需要匯入
          h(ElButton, {
            type:"primary",
            // 注意這裡需要使用箭頭函數,
            onClick: () => emit('myClick', '123')
          }, 
            //第三個引數建議使用函數返回。否者在控制有警告
            // Non-function value encountered for default slot. Prefer function slots for better performance. 
            ()=>'點選我'
          )
  
        ]
      )
  }
}
</script>
//頁面使用 renderTest.vue這個元件
<template>
  <div class="father-div">
    <renderTest @myClick="myClick"></renderTest>
  </div>
</template>
<script setup lang="ts">
import renderTest from './renderTest.vue'
const myClick = (mess:string) => { 
    console.log('子元件給的資料', mess)
}
</script>

需要注意的點

1.如果使用ElButton作為標籤。需要引入import { ElButton } from 'element-plus'。
否則在頁面中無法正常解析。

2. 第三個引數建議使用函數返回。否者在控制有警告
Non-function value encountered for default slot. Prefer function slots for better performance. 

詳細地址 :https://cn.vuejs.org/guide/extras/render-function.html#v-if