學習筆記:函數化組件
函數化組件
Vue提供了一個functional
的布爾值選項,設置爲true
可以使組件無狀態和無實例,也就是沒有data
和this
上下文。這樣用render
函數返回虛擬節點可以更容易渲染,因爲函數化組件只是一個函數,渲染開銷要小很多。
使用函數化組件時,Render函數提供了第二個參數context
來提供臨時上下文。組件需要的data
、prop
、slots
、children
、parent
都是通過這個上下文來傳遞。比如this.level
要改寫爲context.props.level
,this.$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>
函數化組件主要適用於以下兩個場景:
- 程序化地在多個組件中選擇一個。
- 在將
children
、props
、data
傳遞給子組件之前操作它們。
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
構成:columns
和data
。兩者都是數組,columns
用來描述每列的信息,並渲染在表頭<head>
內,可以指定某一列是否需要排序;data
時每一行的數據,由columns
決定每一行裏各列的順序。
爲了讓排序後的columns
和data
不影響原始數據,給v-table
組件的data
選項添加兩個對應的數據,組件所有的操作將在這兩個數據上完成,不對原始數據做任何處理。
columns
的每一項是一個對象,其中title
和key
字段是必填的,用來標識這列的表頭標題,key
的對應data
中列內容的字段名。sortable
是選填字段,如果值爲true
,說明該列需要排序。
v-talbe
組件的prop:columns
和data
的數據已經從父級傳遞過來,v-table
不直接使用它們,而是使用data
選項的currentColumns
和currentData
。所以在v-table
初始化時,需要把columns
和data
賦值給currentColumns
和currentData
。在v-table
的methods
選項裏定義兩個方法用來複制,並在mounted
鉤子內調用。
map()
是JavaScript數組的一個方法,根據傳入的函數重新構造一個新數組。
排序分升序(asc
)和降序(desc
)兩種,而且同時只能對一列數據進行排序,與其他列互斥,爲了標識當前列的排序狀態,在map
列添加數據時,默認給每列都添加一個_sortType
的字段,並且賦值爲normal
,表示默認排序(也就是不排序)。
在排序後,currentData
每項的順序可能都會發生變化,所以給currentColumns
和currentData
的每個數據都添加_index
字段,代表當前數據在原始數據中的索引。
render(h) {
var ths = [],
trs = [];
return h('table', [
h('thead', [
h('tr', ths)
]),
h('tbody', trs)
])
}
這裏的h
就是createElement
,只是換了個名稱。
表格主題trs
是一個二維數組,數據由currentColumns
和currentData
組成。
先遍歷所有的行,然後再每一行內再遍歷各列,最終組合出主題內容節點trs
。
如果col.sortable
沒有定義,或值爲false
,就直接把col.title
渲染出來,否則除了渲染title
,還加了兩個<a>
元素來實現升序和降序的操作。
排序使用了JavaScript數組的sort()
方法,這裏之所以返回1
或-1
,而不直接返回a[key]<b[key]
,也就是true
或false
,是因爲在部分瀏覽器對sort()
的處理不同,而1
和-1
可以做到兼容。
排序前,先將所有列的排序狀態都重置爲normal
,然後設置當前列的排序狀態(asc
或desc
),對用到render的<a>
元素的class
名稱on
,後面通過CSS來高亮顯示當前列的排序狀態。
當渲染完表格後,父級修改了data
數據,比如增加或刪除,v-table
的currentData
也應該更新,如果某列已經存在排序狀態,更新後應該直接處理一次排序。
通過遍歷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
存儲了所有的留言內容,通過函數handleSend
給list
添加一項留言數據,添加成後把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>