到此爲止,咱們的 toggle
組件已經足夠強大以及好用了,所以這篇文章不會再爲它增長新的特性。若是你是從第一篇文章一直讀到這裏的讀者,你必定會發現,整篇文章中,我幾乎沒有對 toggle-on
和 toggle-off
作出任何更改和重構,所以這篇文章着重來重構一下它們。vue
以前一直沒有對它們進行任何更改,一個很重要的緣由是由於它們足夠簡單,組件內部沒有任何 data 狀態,僅靠外部傳入的 prop 屬性 on 來決定內部渲染邏輯。這聽起來彷佛有些耳熟啊,沒錯,它們就是在上一篇文章中所說起的木偶組件(Dump Component)。在 Vue 中,這種類型的組件也能夠叫作函數式組件(Functional Component)。git
仔細觀察 app 組件的模板代碼,會發現存在必定的冗餘性的,好比:github
<toggle-on :on="status.on">{{firstTimes}}</toggle-on> <toggle-off :on="status.on">{{firstTimes}}</toggle-off>
這裏兩行代碼的邏輯幾乎如出一轍,但咱們卻要寫兩次。同時你還會發現一個問題,因爲其內部的渲染邏輯是經過 v-if
來描述的,實際上在 Vue 渲染完成後,會渲染兩個 dom
節點,在切換時的狀態從 devtool 中觀察的效果大概是這樣子的:app
未顯示的節點是一個註釋節點,而顯示的節點是一個 div 節點。dom
這篇文章將着重解決這兩個問題:函數
toggle-on
和 toggle-off
合二爲一,減小代碼冗餘性v-if
實現的渲染邏輯,改成更好的動態渲染邏輯(僅使用一個 dom 節點)首先,先將已經存在的 toggle-on
和 toggle-off
組件轉化爲函數式組件,很簡單,只需保留 template 代碼塊便可,同時在左邊的標籤上聲明 functional
屬性,或者在 script 代碼塊中聲明 functional: true
也是能夠的。惟一要注意的是,因爲函數式組件沒有 data 也沒有 this
,所以全部模板中用到的與 prop 相關的渲染邏輯,都要做出相應更改,好比原先的 on
要改成 props.on
的形式,因爲這裏咱們要移除 v-if
的渲染邏輯,所以直接移除便可,詳細代碼以下:測試
// ToggleOn.vue <template functional> <div class="toggle-on"><slot></slot></div> </template> <style> .toggle-on { color: #86d993; } </style> // ToggleOff.vue <template functional> <div class="toggle-off"><slot></slot></div> </template> <style> .toggle-off { color: red; } </style>
除此以外,還能夠發現,我爲兩個組件增長不一樣的顏色樣式以便於區分當前的開關狀態。this
接下來實現今天的主角,ToggleStatus
組件,因爲咱們的目標是將原先的二個函數式組件合二爲一,所以這個組件自己應當也是一個函數式組件,不過咱們須要使用另一種寫法,以下:spa
<script> import ToggleOn from './ToggleOn' import ToggleOff from './ToggleOff' export default { functional: true, render(createElement, {props, data, children}) { let Comp = ToggleOff if(props.on) Comp = ToggleOn return createElement(Comp, data, children) } } </script>
關於這種寫法中,render
和 createElement
方法的參數就不贅述了,不熟悉的讀者請參考官方文檔。能夠發現,這裏將 toggle-on
和 toggle-off
以模塊的形式導入,以後由 props.on
的值進行斷定,從而決定哪個被做爲 createElement
方法的第一個參數進行渲染。3d
諸如 data
和 children
參數咱們原封不動的傳入 createElement
便可,由於這裏對於 toggle-status
組件的定位是一個代理組件,對於其餘參數以及子元素應當原封不動的傳遞給被代理的組件中。
以後在 app 組件中更改響應的渲染邏輯便可,以下:
// controlled toggle <toggle-status :on="status.on">{{firstTimes}}</toggle-status> // uncontrolled toggle <toggle-status :on="status.on">{{secondTimes}}</toggle-status>
一切如原先同樣,只不過此次咱們能夠少寫一行冗餘的代碼了。同時打開 devtool 能夠發現,兩種狀態的組件會複用同一個 dom 節點,以下:
你能夠經過下面的連接來看看這個組件的實現代碼以及演示:
關於函數式組件,我是在 React 中第一次接觸,其形式和它的名字同樣,就是一個函數。這種組件和普通組件相比的優點主要在於,它是無狀態的,這意味着它的可測試性和可讀性更好,同時一些狀況下,渲染開銷也更小。
咱們在平常工做中,可能會常常遇到動態渲染的需求,通常狀況下,咱們均會經過 v-if
來解決,在比較簡單的狀況下,v-if
確實一種很簡單且高效的方式,可是隨着組件複雜度的上升,極可能會出現麪條式的代碼,可讀性和可測試性都大打折扣,這是不妨換一個角度從渲染機制自己將組件重構爲更小的顆粒,並用一個函數式組件動態的代理它們,可能會獲得更好的效果,舉一個比較常見的例子,好比表單系統中的表單項,通常都具備多種渲染狀態,如編輯狀態、瀏覽狀態、禁用狀態等等,這時利用該模式來抽離不一樣狀態的渲染邏輯就很是不錯。
關注公衆號 全棧101,只談技術,不談人生