做者:Milos Protic
譯者:前端小智
來源:medium
阿里雲最近在作活動,低至2折,真心以爲很划算了,能夠點擊本條內容或者連接進行參與:
https://promotion.aliyun.com/...css
騰訊雲最近在作活動,百款雲產品低至 1 折,能夠點擊本條內容或者連接進行參與html
狀態管理一般在較小的項目並不須要,可是當涉及到更大的範圍時,如企業級的應用大部分須要它了。簡單的說,狀態是一個包含應用程序使用的最新值的對象。可是,若是我們從結構的、更抽象的角度來看待它,就會清楚地看到,狀態是複雜應該中重要一塊,它使可以構建乾淨的體系結構,並將關注點強有力地分離開來。前端
一般,缺少經驗的開發人員沒法預測對狀態管理的需求,以及如何實現狀態管理,所以很難了解狀態管理的重要性。若是基於狀態的組件堆積起來,它們之間的數據管理和共享將成爲一場噩夢。從長遠來看,擁有的基於狀態的組件越多,出現的問題就越多。vue
若是沒有使用外部包進行狀態管理,那麼最好儘量少地使用基於狀態的組件,而展現組件則使用圍繞它們構建的狀態。node
Vue 中的無狀態組件其實就是函數組件。但函數組件又是啥呢? 要回答這個問題,我們首先必須理解什麼是函數式編程。git
與將程序分解爲對象的面向對象方法不一樣,函數式編程鼓勵將程序分解爲小函數,這些小函數用於造成更高級的程序。咱們建立的函數不依賴於或能夠改變任何外部狀態,這致使另外一個觀察結果,對於給定的輸入,它們老是返回相同的輸出。github
所以,函數組件是沒有狀態的組件,而且能夠更改它。函數組件輸出老是基於給定的輸入。在 Vue 方面,這類組件會根據給定的props
給出不一樣的輸出。編程
Vue 提供了一種定義函數組件的簡單方法。我們只須要給個 functional
關鍵字就能夠。在 2.5.0 及以上版本中,若是使用了單文件組件,那麼基於模板的函數式組件能夠這樣聲明::segmentfault
<template functional> <div> 函數/無狀態組件 </div> </template>
或者數組
export default { functional: true, props: { // ... }, render(createElement, context) { return createElement( 'div', '函數/無狀態組件' ) } }
注意:在 2.3.0 以前的版本中,若是一個函數式組件想要接收prop
,則props
選項是必須的。在 2.3.0 或以上的版本中,你能夠省略props
選項,全部組件上的特性都會被自動隱式解析爲prop
。當使用函數式組件時,該引用將會是
HTMLElement
,由於他們是無狀態的也是無實例的。
須要注意的是,傳遞給函數組件的唯一數據是props
。這些組件是徹底無狀態的(沒有響應數據),它們忽略傳遞給它們的任何狀態,而且不觸發任何生命週期方法(created
、mounted
等等)。
並且,我們也不能經過使用 this
關鍵字來訪問實例,由於這些組件也是不實例化的。相反,組件須要的全部東西都是經過context
提供的。在render
函數中,它做爲createElement
方法的第二個參數傳遞。
組件須要的一切都是經過 context
參數傳遞,它是一個包括以下字段的對象:
props
:提供全部 prop 的對象children
: VNode 子節點的數組slots
: 一個函數,返回了包含全部插槽的對象scopedSlots
: (2.6.0+) 一個暴露傳入的做用域插槽的對象。也以函數形式暴露普通插槽。data
:傳遞給組件的整個數據對象,做爲 createElement 的第二個參數傳入組件parent
:對父組件的引用listeners
: (2.3.0+) 一個包含了全部父組件爲當前組件註冊的事件監聽器的對象。這是 data.on 的一個別名。injections
: (2.3.0+) 若是使用了 inject 選項,則該對象包含了應當被注入的屬性。到目前爲止,我們已經瞭解到函數組件是無狀態的,在它們的核心中,它們只是可執行的函數,接受一些輸入並根據其提供輸出。
就它們的用法而言,由於函數式組件只是函數,因此渲染開銷也低不少,這也意味着它們是很是高效的,不須要花太多時間渲染。同時,考慮高階組件,它們不須要任何狀態,它們所要作的就是用額外的邏輯或樣式包裝給定的子組件。
接下來,通例事例展現同樣啥時使用函數組件,函數組件很是適合此類任務。
在這個示例中,我們建立一個panel
組件,它充當一個包裝器,並提供所需的樣式。子組件將在panel
主體中渲染:
export default { name: 'panel', functional: true, props: { title: String }, render(createElement, context) { const slots = context.slots(); const header = createElement('header', { attrs: { class: 'panel-header'} }, context.props.title); const body = createElement('main', { attrs: { class: 'panel-body'} }, slots.default); return createElement('section', { attrs: { class: 'panel' } }, [header, body]); } }
如上所述,此組件的惟一目的是提供相似於面板(卡片)的樣式,它有header
和main
元素,分別保存面板標題和HTML
內容。整個過程是經過使用render
函數中的createElement
參數在中完成。createElement
是 Vue 核心中實現的虛擬 Dom 系統的一部分。
虛擬 DOM
Vue 經過創建一個虛擬 DOM 來追蹤本身要如何改變真實 DOM。請仔細看這行代碼:
return createElement('h1', this.blogTitle)
createElement
到底會返回什麼呢?其實不是一個實際的 DOM
元素。它更準確的名字多是 createNodeDescription
,由於它所包含的信息會告訴 Vue 頁面上須要渲染什麼樣的節點,包括及其子節點的描述信息。咱們把這樣的節點描述爲「虛擬節點 (virtual node)」,也常簡寫它爲「VNode」。「虛擬 DOM」是咱們對由 Vue 組件樹創建起來的整個 VNode
樹的稱呼。
createElement 參數
接下來你須要熟悉的是如何在 createElement 函數中使用模板中的那些功能。這裏是 createElement 接受的參數:
// @returns {VNode} createElement( // {String | Object | Function} // 一個 HTML 標籤名、組件選項對象,或者 // resolve 了上述任何一種的一個 async 函數。必填項。 'div', // {Object} // 一個與模板中屬性對應的數據對象。可選。 { // (詳情見下一節) }, // {String | Array} // 子級虛擬節點 (VNodes),由 `createElement()` 構建而成, // 也可使用字符串來生成「文本虛擬節點」。可選。 [ '先寫一些文字', createElement('h1', '一則頭條'), createElement(MyComponent, { props: { someProp: 'foobar' } }) ] )
面板 CSS 樣式以下:
.panel { margin-bottom: .5rem } .panel, .panel-header { border: 1px solid #d3d3d3; border-radius: 4px; } .panel-header, .panel-body, .panel { padding: .5rem; } .panel-header { background-color:#efefef; color: #eeeee }
這是一個簡單直接的 CSS,提供了一些padding
和color
。
如今,爲了讓例子更加生動爲此,我們再建立兩個附加組件,一個顯示汽車列表,另外一個只是一個簡單lorem-ipsum
的文本組件,要求它們具備相同的面板樣式和外觀。
列表組件:
export default { name: 'cars', props: { data: Array } }
template:
<template> <ul> <li v-for="car in data" :key="car">{{car}}</li> </ul> </template>
文本組件:
export default { name: 'lorem-ipsum' }
template:
<template> <p> 終身學習者,終身學習者,終身學習者,終身學習者,終身學習者 </p> </template>
如今,有了可用的子組件,我們所須要作的就是用panel
組件將它們封裝到應用程序中,以下所示:
<div class="vue-app"> <panel :title="'Car Manufacturers'"> <cars :data="['Mazda', 'Ford', 'Mercedes']"></cars> </panel> <panel :title="'Lorem Ipsum'"> <lorem-ipsum></lorem-ipsum> </panel> </div>
請注意,使用這些組件是由於示例比較簡單。在實際應用中,它能夠是任何類型的組件。
hmtl
<div class="vue-app"> <panel :title="'Car Manufacturers'"> <cars :data="['Mazda', 'Ford', 'Mercedes']"></cars> </panel> <panel :title="'Lorem Ipsum'"> <lorem-ipsum></lorem-ipsum> </panel> </div> <script type="text/x-template" id="cars"> <template> <ul> <li v-for="car in data" :key="car">{{car}}</li> </ul> </template> </script> <script type="text/x-template" id="lorem-ipsum"> <template> <p>前端小智, 終身學習者,終身學習者,終身學習者,終身學習者,終身學習者</p> </template> </script>
css
body { padding: .5rem } * { padding: 0; margin:0; box-sizing: border-box; } .panel { margin-bottom: .5rem } .panel, .panel-header { border: 1px solid #d3d3d3; border-radius: 4px; } .panel-header, .panel-body, .panel { padding: .5rem; } .panel-header { background-color:#efefef; color: #eeeee } ul { list-style: none; } ul > li { padding: .5rem .2rem }
js
// the wrapper panel const panel = { functional: true, name: "panel", props: { title: String }, render(createElement, context) { const slots = context.slots(); const header = createElement('header', { attrs: { class: 'panel-header'} }, context.props.title); const body = createElement('main', { attrs: { class: 'panel-body'} }, slots.default); return createElement('section', { attrs: { class: 'panel' } }, [header, body]); } } // sample components const cars = { name: 'cars', template: '#cars', props: { data: Array } } const loremIpsum = { name: 'lorem-ipsum', template: '#lorem-ipsum' } new Vue({ el: '.vue-app', components: { panel, cars, 'lorem-ipsum': loremIpsum } });
運行效果:
代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug。
原文:https://itnext.io/whats-the-d...
乾貨系列文章彙總以下,以爲不錯點個Star,歡迎 加羣 互相學習。
https://github.com/qq449245884/xiaozhi
由於篇幅的限制,今天的分享只到這裏。若是你們想了解更多的內容的話,能夠去掃一掃每篇文章最下面的二維碼,而後關注我們的微信公衆號,瞭解更多的資訊和有價值的內容。
每次整理文章,通常都到2點才睡覺,一週4次左右,挺苦的,還望支持,給點鼓勵