Vue.js-函數化組件

學習筆記:函數化組件

函數化組件

Vue提供了一個functional的布爾值選項,設置爲true可以使組件無狀態和無實例,也就是沒有datathis上下文。這樣用render函數返回虛擬節點可以更容易渲染,因爲函數化組件只是一個函數,渲染開銷要小很多。

使用函數化組件時,Render函數提供了第二個參數context來提供臨時上下文。組件需要的datapropslotschildrenparent都是通過這個上下文來傳遞。比如this.level要改寫爲context.props.levelthis.$slots.default改變爲context.children

用函數化組件展示一個根據數據智能選擇不同組件的場景:

<p data-height="365" data-theme-id="0" data-slug-hash="mKRKGm" data-default-tab="html,result" data-user="whjin" data-embed-version="2" data-pen-title="Vue-函數化組件-根據數據選擇組件" class="codepen">See the Pen Vue-函數化組件-根據數據選擇組件 by whjin (@whjin) on CodePen.</p>
<script async src="https://static.codepen.io/ass...;></script>

函數化組件主要適用於以下兩個場景:

  1. 程序化地在多個組件中選擇一個。
  2. 在將childrenpropsdata傳遞給子組件之前操作它們。

JSX

爲了讓Render函數更好地書寫和閱讀,Vue提供了插件babel-plugin-transform-vue-jsx來支持JSX語法。

使用createElement時,常用配置:

<p data-height="365" data-theme-id="0" data-slug-hash="Vdpwpz" data-default-tab="js" data-user="whjin" data-embed-version="2" data-pen-title="Vue-createElement" class="codepen">See the Pen Vue-createElement by whjin (@whjin) on CodePen.</p>
<script async src="https://static.codepen.io/ass...;></script>

JSX寫法:

<p data-height="300" data-theme-id="0" data-slug-hash="eKvYvm" data-default-tab="js" data-user="whjin" data-embed-version="2" data-pen-title="Vue-JSX" class="codepen">See the Pen Vue-JSX by whjin (@whjin) on CodePen.</p>
<script async src="https://static.codepen.io/ass...;></script>

實戰:使用Render函數開發可排序的表格組件

表格組件的所有的內容(表頭和行數據)由兩個prop構成:columnsdata。兩者都是數組,columns用來描述每列的信息,並渲染在表頭<head>內,可以指定某一列是否需要排序;data時每一行的數據,由columns決定每一行裏各列的順序。

爲了讓排序後的columnsdata不影響原始數據,給v-table組件的data選項添加兩個對應的數據,組件所有的操作將在這兩個數據上完成,不對原始數據做任何處理。

columns的每一項是一個對象,其中titlekey字段是必填的,用來標識這列的表頭標題,key的對應data中列內容的字段名。sortable是選填字段,如果值爲true,說明該列需要排序。

v-talbe組件的prop:columnsdata的數據已經從父級傳遞過來,v-table不直接使用它們,而是使用data選項的currentColumnscurrentData。所以在v-table初始化時,需要把columnsdata賦值給currentColumnscurrentData。在v-tablemethods選項裏定義兩個方法用來複制,並在mounted鉤子內調用。

map()是JavaScript數組的一個方法,根據傳入的函數重新構造一個新數組。

排序分升序(asc)和降序(desc)兩種,而且同時只能對一列數據進行排序,與其他列互斥,爲了標識當前列的排序狀態,在map列添加數據時,默認給每列都添加一個_sortType的字段,並且賦值爲normal,表示默認排序(也就是不排序)。

在排序後,currentData每項的順序可能都會發生變化,所以給currentColumnscurrentData的每個數據都添加_index字段,代表當前數據在原始數據中的索引。

render(h) {
    var ths = [],
        trs = [];
    return h('table', [
        h('thead', [
            h('tr', ths)
        ]),
        h('tbody', trs)
    ])
}

這裏的h就是createElement,只是換了個名稱。

表格主題trs是一個二維數組,數據由currentColumnscurrentData組成。

先遍歷所有的行,然後再每一行內再遍歷各列,最終組合出主題內容節點trs

如果col.sortable沒有定義,或值爲false,就直接把col.title渲染出來,否則除了渲染title,還加了兩個<a>元素來實現升序和降序的操作。

排序使用了JavaScript數組的sort()方法,這裏之所以返回1-1,而不直接返回a[key]<b[key],也就是truefalse,是因爲在部分瀏覽器對sort()的處理不同,而1-1可以做到兼容。

排序前,先將所有列的排序狀態都重置爲normal,然後設置當前列的排序狀態(ascdesc),對用到render的<a>元素的class名稱on,後面通過CSS來高亮顯示當前列的排序狀態。

當渲染完表格後,父級修改了data數據,比如增加或刪除,v-tablecurrentData也應該更新,如果某列已經存在排序狀態,更新後應該直接處理一次排序。

通過遍歷currentColumns來找出是否按某一列進行過排序,如果有,就按照當前排序狀態對更新後的數據做一次排序操作。

<p data-height="365" data-theme-id="0" data-slug-hash="XYMmJr" data-default-tab="html,result" data-user="whjin" data-embed-version="2" data-pen-title="Vue-可排序表格組件" class="codepen">See the Pen Vue-可排序表格組件 by whjin (@whjin) on CodePen.</p>
<script async src="https://static.codepen.io/ass...;></script>

實戰:留言列表

發佈一條留言,需要的數據有暱稱和留言內容,發佈操作應該在根實例app內完成。留言列表的數據也是從app獲取。

數組list存儲了所有的留言內容,通過函數handleSendlist添加一項留言數據,添加成後把texrarea文本框置空。

Render函數內的節點使用v-model:動態綁定value,並且監聽input事件,把輸入的內容通過$emit('input')派發給父組件。

列表數據list爲空時,渲染一個“列表爲空”的信息提示節點;不爲空時,每個list-item贏包含暱稱、留言內容和回覆按鈕3個子節點。

this.list.forEach相當於template裏的v-for指令,遍歷出每條留言。句柄handleReply直接向父組件派發一個事件reply,父組件(app)接收後,將當前list-item的暱稱提取,並設置到v-textarea內。

<p data-height="365" data-theme-id="0" data-slug-hash="ZRKGrR" data-default-tab="html,result" data-user="whjin" data-embed-version="2" data-pen-title="Vue-留言列表" class="codepen">See the Pen Vue-留言列表 by whjin (@whjin) on CodePen.</p>
<script async src="https://static.codepen.io/ass...;></script>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章