一般情況都是使用 template 來做渲染,但有時候就是需要 javascript ,所以這時候就需要渲染函式。
創建 vnode
Vue 提供了 h()
函式來創建 vnode
h 是 hyperscript 的簡稱,意思是能生成 HTML 的 javascript,這個名字來源於實作虛擬 DOM 的默認規則,更正確的名稱應該是 createVNode()
,但一個常用的函式名字越簡短越有利。
h()
的使用方式:
舉個例子:
vnode 內部其實包含很多屬性,但強烈建議不要使用這裡沒列出的屬性,以避免變更屬性導致內部程式碼無法運行的情況
在使用 Composition API 時,setup()
hook 的回傳值是用來給予 template 資料,不過在使用渲染函式的時候可以直接回傳渲染函式就好。
渲染函式宣告在 setup()
中,自然就能夠存取任何宣告在同個區塊的 props 或是響應式狀態。
除了回傳渲染函式,你也可以回傳字串或陣列
確保setup()
都是回傳函式,而不是直接回傳值,因為setup()
只會被呼叫一次,而你回傳的函式可以被叫很多次
如果渲染函式的元件不需要任何的 instance state,方便起見你也可以直接把他們宣告成一般的函式
其實這樣就是合法的 Vue 元件了
如果你真的很想這樣做,你可以用工廠函式來達成
JSX 是 javascript 類似 XML 的一個拓展
在 jsx 中可以利用大括弧來動態嵌入變數值
create-vue
和 Vue CLI 都有支援 jsx,如果你想手動配置 jsx,請參考 @vue/babel-plugin-jsx
雖然最早 jsx 是由 React 引入,但實際上 jsx 沒有定義運行上的語意,而且也能被編譯成不同類型的輸出,如果你之前使用過 jsx,請注意 Vue 的 JSX 轉換方式與 React 不同,因此你不能在 Vue 中使用 React 的 jsx 轉換法,以下是一些明顯的區別:
className
和 htmlFor
Vue 也支援 TSX,使用的時候要在 tsconfig.json
中設置 "jsx": "preserve"
與轉換類似,Vue 與 jsx 也需要不同的類型定義,目前 Vue 會在全域範圍自動註冊 Vue 的 JSX 類型。
全域註冊的 jsx 與其他同樣需要 jsx 的 library 一起使用時可能會引起衝突(特別是 React)。從 3.3 開始,Vue 利用 jsxImportSource選項指定 jsx 命名空間,並計畫會在 3.4 移除全域註冊。
對於 tsx 用戶建議在升級到3.3之後把 tsconfig.json 中的 jsxImportSource
設置為 vue
,或是針對單個文件加入 /* @jsxImportSource vue */
,這可以讓你使用區域註冊,並在3.4無痛升級。
如果你還有程式碼會依賴全域的 jsx,你可以通過 explicitly referencing ,把路徑改成 vue/jsx
來保留 3.4 之前的全域註冊。
template:
h():
jsx:
template:
h():
jsx:
h():
jsx:
.passive
、.capture
和 .once
,可以用駝峰式命名將他們接在事件名後面
h():
jsx:
其他的事件或是按鍵修飾符,可以用 withModifiers
函式
h():
jsx:
在為元件創建 vnode 時,第一個傳給 h() 的參數就是元件的定義,這代表你使用渲染函式就不用再註冊元件了
h():
jsx:
不論是什麼類型的文件,只要你導入的是有效的 Vue 元件,h
就能正常運作。
動態函式也可以直接使用:
h():
jsx:
如果你的元件是用名稱來註冊,不能直接導入(例如經由某個第三方套件幫你全域註冊),你可以用 resolveComponent()
來解決
在渲染函式中,插槽可以通過setup()
的上下內容來訪問,每個 slots
對象中的插槽都是一個返回 vnode
陣列的渲染函式
jsx:
向元件傳遞子元素和項元素傳遞子元素的方式其實不盡相同,我們需要傳遞的是 slot 函式或是一個包含 slot 函式的物件而非陣列,普通的渲染函式可以回傳的 slot 函式都能回傳,並且都會在子元件被拜訪時被轉換成 vnode 陣列。
h():
jsx:
用函式的方式傳遞可以使得他們以 lazy invoke 的方式被子元件使用,這能夠確保 slot 的依賴關係是存在於子元件而非父元件,使得更新更準確與有效。
<KeepAlive>
、<Transition>
、<TransitionGroup>
、<Teleport>
和 <Suspense>
等要 import 才能用
h():
v-model
的指令擴展為 modelValue
還有 onUpdate:modelValue
,在模板編譯的過程中我們要自己提供這些 props
可以使用 withDirectives
將自定義指令用於 vnode
如果是名稱註冊一樣可以使用 resolveDirective
來解決
在 Composition API 中,模板引用通過 ref()
本身作為一個屬性傳遞給 vnode 來創建
函式式元件是元件的替代形式,它们不具有自己的狀態。它们的行為類似於纯函式:接收 props,輸出虚擬節點 (vnode)。它们在渲染时不會創建組件實例(即没有 this),也不會使用一般的元件生命周期勾子。
要創建函式式元件,我们使用普通的函式,而不是 options object。這個函式實際上就是元件的渲染函式。
基本上就和 setup() hook 相同:
常見的元件配置在這裡都不能使用,不過可以使用 props 和 emits
如果這個 props 沒被定義就會像 attrs 一樣包含所有的 attritube,除非有指定 props 選項,不然他們不會被處理成駝峰式命名。
對於有明確 props 的 函式式元件,屬性傳透的原理和一般的元件一樣,但是對於沒有明確指定 props 的 函式式元件只會有 class
、style
、onXXX
默認會從中繼承,在這兩種情況下都可以將 inheritAttrs
設成 false 來禁用屬性繼承。
函式式元件可以根據他們是否有命名來標註類型,在 SFC 中 Volar 還支持型別檢查
匿名函式式組件: