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