摘要:觸發事件可以攜帶數據,這些數據被用于傳遞給綁定了事件的其它組件的回調函數上,進而被傳遞給其它組件。父組件可以在回調函數里做任何事情,頗有靈活性。一般情況下,父組件會在回調函數中更新自己的狀態數據。
上一篇博文梳理了vue的數據驅動和響應式相關的特性,這一篇博文就來梳理vue的一個很重要的特性,組件化。
自定義組件之于vue,其意義不亞于函數之于C,java之類的編程語言。
函數是計算機科學中的一大重要的發明。
一方面,它代表著一種自頂向下,逐步求精的分而治之的思維,另外一方面,它能夠封裝復雜實現的細節,提供更高抽象的接口,降低軟件工程的復雜度。
在vue中,自定義組件也起著類似的作用。
我們知道,在組件化的GUI界面上,GUI可以被視為一棵樹,瀏覽器的DOM就是一個最好的例子。
從布局上來看,界面可以看成大盒子套小盒子,小盒子再套更小的盒子。。。
反映到DOM上,DOM某節點的所有子節點,都是該組件的子組件,都是該組件內的元素。
在vue中也是如此,vue組件之間的關系也是類似DOM一樣,是樹狀的。
在定義一個組件時,需要引用的所有組件,都成為了該組件的子組件。
組件作為一個模塊性質的東西,自然就有著它一定的獨立性。而且,與其它模塊的耦合都理所應當的有著明確的接口約定。
在vue中,父子組件通信通過組件屬性和事件來進行的。
其中,通過組件屬性,父組件的數據流向子組件;通過事件,子組件的數據流向父組件。
從抽象的角度看,組件作為一個黑盒子,它有著特定的屬性用以接收外部傳遞給它的數據,它也有著特定的事件,當特定操作發生時調用回調函數,以通知別的組件。
組件的屬性 自定義屬性{{ titleMessage }}
上面的例子中,定義了x-child自定義組件,并且在x-parent組件中引用它。
之前在介紹數據驅動的時候,我們知道,定義vue組件時,可以通過data定義組件內部的狀態,它是組件數據的一部分。
除了data之外,prop(屬性)也是組件數據的來源之一,父組件通過prop將自己的數據傳遞給子組件。
在定義組件時我們可以看到:
通過props定義組件能夠接收的屬性,甚至還能指定屬性的默認值及類型,甚至還能編寫任意的函數驗證屬性的合法性。明確的指定類似接口聲明,增強可讀性,降低debug難度。
屬性和內部狀態類似,都作為組件數據的一部分。區別在于,在vue設計上,屬性是只讀的,可以作為數據驅動視圖,但是無法被改變。(我不太清楚vue有沒有從語法強制要求這點,但是良好實踐的vue組件是這樣的)
在使用自定義組件時可以看到:
組件屬性的靈活性特別強,你不僅能傳遞給它一個固定的數據,還能夠使用vue的數據綁定語法把父組件內的數據通過prop傳遞給子組件。
當然,這也是響應式的。當父組件中該數據變化時,自然的,傳遞給子組件的數據也會變化。那么,子組件中綁定了該數據的視圖部分也當然會被重新渲染以展現在瀏覽器上。
子組件中定義中的屬性是駝峰寫法,這是符合js編碼規范的。然而,在引用子組件的地方, 屬性應該要寫成短橫線分割式的寫法。
這是因為,html是不區分大小寫的,vue對此也很無奈。這是在實際編碼中很任意犯的一個錯誤,需要注意。
vue中,屬性被設計用于父組件傳遞數據給子組件的,如果子組件改變了屬性,那么父組件不會受到任何影響。這在vue中被稱為 單向數據流。
但是,如果屬性用來傳遞數組或對象等復合的數據結構,那么可能會出問題??紤]以下的場景:
父組件把數據中的對象傳遞給了子組件的屬性。
由于可能修改該屬性,子組件把該屬性直接賦值給內部狀態,作為內部狀態修改。
在某些操作觸發后,該內部狀態被修改。
問題在于,由于js是引用類型語言,簡單的賦值僅僅是傳遞引用,那么,以上場景中,父組件中的數據,子組件中的屬性,還有子組件中的狀態, 指向的都是同一份對象 !
這會造成一個問題,如果子組件修改了該對象的屬性,那么父組件的數據也會受到影響,這破壞了單向數據流,會造成很多詭異的bug。
解決方法也很顯然:
方案一是父組件傳遞數組或對象給子組件時,使用深拷貝拷貝一份過去,或者子組件將屬性賦值給內部狀態時,深拷貝一份過去,這樣就能夠互不干擾。
方案二是使用不可變數據結構,每次修改都是產生新的拷貝,因此也能解決問題。
組件的事件 自定義事件以上自定義了x-child組件,并且自定義了組件事件。我們可以看到:
使用vue組件實例的$emit方法,用以觸發一個自定義事件。觸發事件可以攜帶數據,這些數據被用于傳遞給綁定了事件的其它組件的回調函數上,進而被傳遞給其它組件。
不像屬性,自定義事件沒有一個統一聲明的地方,至于為什么我也不清楚。。。得問vue作者去。
該自定義組件內部包含了一個按鈕,按鈕被點擊事件觸發了自定義組件的回調函數,進而觸發了該自定義組件的自定義事件。
從一個角度來看,該自定義組件像是轉發了原生組件的事件而已。但是從另外一個角度來看,該自定義組件封裝了這些細節,對外展現的是一個點下按鈕觸發計數器增加的事件的這樣一個計數器。
事件名稱的定義用的短橫線分割的寫法,原因和屬性類似。
{ { counter }}
以上定義了x-parent組件,并且引用了上面定義的子組件??梢钥闯觯?/p>
子組件事件觸發了父組件的回調函數,并且將數據從回調函數中傳入。父組件可以在回調函數里做任何事情,頗有靈活性。
一般情況下,父組件會在回調函數中更新自己的狀態數據。數據更新后觸發新的視圖渲染,用戶即可在界面上看到了反饋。這樣,通過事件,子組件的數據傳遞到了父組件中。
事件綁定的表達式寫法在監聽事件的地方,上面的寫法是使用了一個回調函數,不過,也可以使用js表達式,比如:
上面代碼的重點在于arguments[0],如果是js表達式寫法,使用arguments引用事件的參數,就好像這段js表達式被放入了一個vue提供的匿名函數,然后使用匿名函數監聽這個事件一樣。
那它有什么用呢?在上面的場景里這樣寫當然是不好的,因為削弱了可讀性。
之前在我同事碰到的一個場景里,是一個涉及到插槽分發作用域的場景,如果寫成回調函數的形式,那么在回調函數中無法訪問插槽作用域的變量。
因此,必須使用js表達式的寫法,將插槽作用域中的變量顯式的帶到回調函數中,代碼類似這種,懶得構造具體的例子了 :
雙向綁定
由于vue設計的父子組件通信是單向數據流,但是由于一些需求的需要,如果能提供雙向數據流,會使使用起來更方便。
便捷性和設計的統一性沖突,怎么辦?當然是用語法糖解決了。
實際上,vue提供的兩種好像是雙向數據流的機制,.sync 和 v-model ,都是語法糖。
.sync修飾符這種寫法只是下面的語法糖:
bar = val">
子組件內,如果修改了foo時,需要觸發update:foo事件。
v-modelv-model常用于類似表單這樣的自定義控件:
它也是如下語法的語法糖:
插槽foo = val" >
仔細思考剛才的自定義組件的定義,不難發現,上面的自定義組件只能對DOM中的一棵子樹做抽象和封裝。
那么,考慮這樣一種情況,我們封裝了一個card組件,card的內容可以使用任意的vue組件填充。
這種場景,就需要在自定義組件時,能夠在組件的DOM樹里 挖個洞 ,這個洞能夠讓該組件的調用者填充。
vue提供的這種類似的機制,被稱為插槽。
我是子組件的標題
這是一些初始內容
這是更多的初始內容
標題
這是一些初始內容
這是更多的初始內容
從上面的示例中可以看到:
在自定義組件時,使用slot標簽給自定義組件留了一個“洞”。
在引用該自定義組件時,自定義組件標簽內部的子元素會填補上這個洞,被渲染出來。
默認的插槽只能有一個??梢允褂?b>slot標簽的name屬性定義插槽名稱以區分不同的插槽,這樣能夠在自定義組件上挖多個”洞”。
數據傳遞vue提供的插槽機制,在給自定義組件挖”洞”的同時,還能使自定義組件給洞里填充的組件傳遞數據。如下:
{{ scope.text }}
從上面可以看出:
在定義slot時,可以通過屬性將數據傳遞給它。在引用自定義組件的地方,將插槽內容放入template標簽內,通過slot-scope指定變量名,即可在template標簽內引用該變量從而使用插槽傳遞過來的數據。
在實際使用中,一個典型的例子是,表格組件提供插槽自定義表格行的樣式和布局,同時通過插槽將該表格行的數據傳遞給插槽內容。
最后本篇博文梳理了vue的自定義組件機制,通過自定義組件,就能夠在vue項目中很好的將項目組件化。
一方面,能夠提取共同的組件進行復用,降低代碼冗余;另外一方面,也能夠提供一種強大的抽象機制,提高vue的表達能力。
注:該文于2018-04-10撰寫于我的github靜態頁博客,現同步到我的segmentfault來。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/95890.html
摘要:前言月份開始出沒社區,現在差不多月了,按照工作的說法,就是差不多過了三個月的試用期,準備轉正了一般來說,差不多到了轉正的時候,會進行總結或者分享會議那么今天我就把看過的一些學習資源主要是博客,博文推薦分享給大家。 1.前言 6月份開始出沒社區,現在差不多9月了,按照工作的說法,就是差不多過了三個月的試用期,準備轉正了!一般來說,差不多到了轉正的時候,會進行總結或者分享會議!那么今天我就...
摘要:由于是需要兼容的后臺系統,該項目并不能使用到等技術,因此我在上的經驗大都是使用原生的編寫的,可以看見一個組件分為兩部分視圖部分,和數據部分。 在公司里幫項目組里開發后臺系統的前端項目也有一段時間了。 vue這種數據驅動,組件化的框架和react很像,從一開始的快速上手基本的開發,到后來開始自定義組件,對element UI的組件二次封裝以滿足項目需求,期間也是踩了不少坑。由于將來很長一...
摘要:通過裝作這些變化,我們實現了從而到達了數據變化觸發函數的過程。于此同時,我們還實現了來擴展這個可響應的結構,讓這個對象擁有了觸發和響應事件的能力。最后,根據我們的實現,這是最終的產出,一個框架,了解一下系列文章地址優化優化總結 看這篇之前,如果沒有看過之前的文章,移步拉到文章末尾查看之前的文章。 provide / inject 在上一步我們實現了,父子組件,和 props 一樣 pr...
摘要:前端每周清單年度總結與盤點在過去的八個月中,我幾乎只做了兩件事,工作與整理前端每周清單。本文末尾我會附上清單線索來源與目前共期清單的地址,感謝每一位閱讀鼓勵過的朋友,希望你們能夠繼續支持未來的每周清單。 showImg(https://segmentfault.com/img/remote/1460000010890043); 前端每周清單年度總結與盤點 在過去的八個月中,我幾乎只做了...
閱讀 2809·2021-10-08 10:04
閱讀 3198·2021-09-10 11:20
閱讀 522·2019-08-30 10:54
閱讀 3305·2019-08-29 17:25
閱讀 2301·2019-08-29 16:24
閱讀 883·2019-08-29 12:26
閱讀 1446·2019-08-23 18:35
閱讀 1929·2019-08-23 17:53