摘要:往往定義組件的構(gòu)造器后,不需要手動的進行初始化,而是在其他組件的模板中當(dāng)成標(biāo)簽來使用,這時候需要調(diào)用注冊成組件。這樣設(shè)計的目的是防止從子組件意外改變父級組件的狀態(tài),從而導(dǎo)致應(yīng)用的數(shù)據(jù)流向難以理解。
上節(jié)說到組件https://segmentfault.com/a/1190000009236700,這一節(jié)繼續(xù)來學(xué)習(xí)組件:
原文博客地址,歡迎學(xué)習(xí)交流:點擊預(yù)覽
從github上獲取本文代碼:示例代碼
封裝的組件要具備復(fù)用性和通用性。
先來說復(fù)用,復(fù)用主要是復(fù)用 HTML 結(jié)構(gòu),外加這塊結(jié)構(gòu)中的交互 js,和針對這一塊設(shè)置的 css。 這三者是構(gòu)成一個組件最基本的要素,這三者相互隔離有相互作用,將三者聚合起來,在需要使用的地方,類似一個變量(標(biāo)簽對)一樣,會引用這一塊的所有功能,可以多次使用。
在 vue 中提供了單文件組件,一個文件就是一個組件,這樣把組件模塊化的方式,讓開發(fā)者更方便的利用組件堆積頁面。將三者聚合在一個文件中,孤立的存在,減少了改動組件而影響外界的風(fēng)險,極大的提高了代碼可維護性。
再說通用性,在討論通用性這點上,要向兩個方面思考:
外界使用組件,對組件所需要的數(shù)據(jù)進行定制,由外界傳遞進來(內(nèi)部可以設(shè)置默認值)
組件內(nèi)部的交互要通知給外界,并在外界的控制下產(chǎn)生影響,做不同事情。
組件達到復(fù)用后,可以在多個地方使用,而使用的位置不同,需要展示的數(shù)據(jù)也不同,此時封裝的組件要具有通用性,組件內(nèi)部則由外界使用組件時來決定將要顯示的數(shù)據(jù),需要將數(shù)據(jù)傳遞給組件。
組件的內(nèi)部除了需要數(shù)據(jù)外,不可避免的還有交互,當(dāng)完成一個交互后,需要對外界產(chǎn)生影響,這不能在組件內(nèi)部做具體的事情,因為使用的位置不同,所產(chǎn)生的效果也不一樣,而完成這一系列事情則交給外界來決定,需要組件內(nèi)部通信給外界,告訴外界,內(nèi)部完成了一次交互。
注冊使用組件從封裝一個自定義的下拉框 custom-select 組件開始。
要達到封裝性好,并且可以寫多種功能的代碼塊,那么組件本身就是一個函數(shù)或者類,需要使用 Vue.extend( options ) 來創(chuàng)建構(gòu)造器,這個構(gòu)造器可以由開發(fā)者自己手動初始化掛載,也可以注冊成組件在其他組件的模板中使用。
在 body 中放置掛載點:
定義組件的構(gòu)造器,并手動初始化,手動掛載:
let customeSelect = Vue.extend({ template: `` }) // 手動初始化,掛載到頁面的掛載點上 new customeSelect().$mount("#app");這是一個定義的下拉框
請選擇:北京
- 北京
- 上海
- 杭州
選擇手動初始化的方式,調(diào)用內(nèi)置方法 $mount 方法進行掛載,隨后組件的模板進行編譯,替換掉掛載點,渲染在頁面中。
往往定義組件的構(gòu)造器后,不需要手動的進行初始化,而是在其他組件的模板中當(dāng)成標(biāo)簽來使用,這時候需要調(diào)用 Vue.component( id, [definition] ) 注冊成組件。
// 注冊組件,傳入一個擴展過的構(gòu)造器 Vue.component("my-component", Vue.extend({ /* ... */ })) // 注冊組件,傳入一個選項對象 (自動調(diào)用 Vue.extend) Vue.component("my-component", { /* ... */ }) // 獲取注冊的組件 (始終返回構(gòu)造器) var MyComponent = Vue.component("my-component")
根據(jù)注冊組件的語法,其實是可以省略調(diào)用 Vue.extend 這一步,只需要傳入 選項對象即可,內(nèi)部會自定調(diào)用 Vue.extend ,所以定義組件變成了這樣的簡寫方式:
Vue.component("custome-select",{ template: `` })這是一個定義的下拉框
請選擇:北京
- 北京
- 上海
- 杭州
將來 custome-select 就當(dāng)成了標(biāo)簽使用在其他組件的模板中 < custome-select>< /custome-select>,Vue在編譯模板時,就回去找這種自定義標(biāo)簽是否是一個組件,如果已經(jīng)注冊的話,就會把注冊的構(gòu)造器進行初始化,編譯組件模板,最終將編譯后的模板替換掉自定義標(biāo)簽的位置。如果沒有注冊直接使用,則會拋出錯誤。
關(guān)于組件名稱的命名:
采用烤串(kebab-case)命名,custome-select
采用駝峰命名( PascalCase), customeSelect
名稱不能是HTML規(guī)定的標(biāo)簽名,比如div、span、header、footer等等。。。
注意:注冊時隨便使用兩種命名方式的任何一種,在模板中一律采用烤串命名才有效。
定義掛載點,并使用組件:
啟動應(yīng)用:
new Vue({ el: "#app" })
最終渲染后的結(jié)構(gòu)為:
給組件定制數(shù)據(jù)傳遞props這是一個定義的下拉框
請選擇:北京
- 北京
- 上海
- 杭州
目前 HTML 達到了復(fù)用的目的,但使用多次依然顯示的是寫死的數(shù)據(jù)。作為顯示數(shù)據(jù)的 HTML 結(jié)構(gòu),在不同地方使用,所要展示的數(shù)據(jù)由外界來決定,這就需要給組件傳遞數(shù)據(jù)。
而傳遞參數(shù)實際上就是給組件的構(gòu)造器傳遞參數(shù),本質(zhì)上就是給函數(shù)傳參。函數(shù)的參數(shù)分為實參和形參兩個部分:
實參是實際傳遞給函數(shù)的參數(shù)
形參是用來接收數(shù)據(jù)所聲明的變量
現(xiàn)在組件寫在模板中以標(biāo)簽對的形式呈現(xiàn),需要傳遞實際的參數(shù),唯一的地方就是寫在行間作為自定義屬性,而傳遞的參數(shù)會有很多個,最好表明具體的含義,需要和組件約定好屬性名,傳遞參數(shù):
在組件中需要顯示的用 props 接收傳遞的數(shù)據(jù),這樣的好處就是一旦看到組件,就會很清晰快速的了解到組件所需要的數(shù)據(jù)。
注意: 在行間寫上自定義屬性,要解析為數(shù)組,在屬性名前加上 v-bind,解析為 javascript 表達式,否則只能當(dāng)成是字符串。
具體如下:
Vue.component("custome-select",{ // 關(guān)于props具體參考: // https://cn.vuejs.org/v2/guide/components-props.html#Prop-%E7%B1%BB%E5%9E%8B // https://cn.vuejs.org/v2/guide/components-props.html#Prop-%E9%AA%8C%E8%AF%81 props:{ title: { type: String, default: "這是一個定義的下拉框" }, list:{ type: Array, default(){return []} }, selectIndex:{ type: Number, default:0 } }, template: `` }){{title}}
請選擇:{{list[selectIndex]}}
- {{item}}
在組件中約定了三個需要接收的參數(shù),分別寫出了接受的類型和默認值,props參數(shù)文檔如下:
屬性 | 說明 | 類型 | 默認值 |
---|---|---|---|
title | 定制組件的標(biāo)題 | String | "這是一個定義的下拉框"" |
list | 定制組件的下拉列表 | Array | [] |
selectIndex | 選擇要展示的一項 | String | 0 |
有了文檔,很清晰的知道每一個屬性代表的意思,傳入響應(yīng)的參數(shù)后,就會達到預(yù)期的效果。
組件自身狀態(tài)data以上渲染后直接把下拉框顯示了出來,下拉框應(yīng)該是在點擊 p 標(biāo)簽時候才能顯示,再次點擊就隱藏掉,要實現(xiàn)這樣的一個顯示隱藏切換功能。
在 Vue 中不提倡直接操作 DOM,需要設(shè)置一個狀態(tài)來確定 DOM 的狀態(tài),當(dāng)需要改變 DOM 時,只需要改變設(shè)置好的狀態(tài)即可,把我們的關(guān)注點放在狀態(tài)的維護上,而無需手動操作 DOM 改變。
這個狀態(tài)不受外界的影響,屬于是組件自身的狀態(tài)變化,定義在組件內(nèi)部,并且改變時只能由組件自身更改。
具體如下:
Vue.component("custome-select",{ ... 省略了props設(shè)置 data(){ return { show: false // 一開始狀態(tài)為false,也就是不顯示下拉列表 } }, template: ``, methods:{ toggleShow(){ this.show = !this.show; } } }){{title}}
請選擇:{{list[selectIndex]}}
- {{item}}
以上做了三件事情:
在 data 中設(shè)置一個狀態(tài)為 show,初始值為 false,來表示下拉列表為隱藏狀態(tài)
在模板上使用指令 v-show="show" 控制 DOM 的顯示隱藏
給 p 綁定事件,切換 show 的值,一旦改變,自動更新 DOM 到對應(yīng)狀態(tài)上,也就是 true 顯示,false 隱藏
Vuejs 這個框架要做的就是狀態(tài)和UI保持同步。
單向數(shù)據(jù)流單向數(shù)據(jù)流顧名思義就是單方向的數(shù)據(jù)流向,也就是數(shù)據(jù)只能從一邊流向另一邊,反過來則不行,如黃河之水從天上來,卻不能再流回到天上去。具體到組件中,就是:父子 prop 之間形成了一個單向下行綁定:父級 prop 的更新會向下流動到子組件中,子組件改變不能改變父組件。這樣設(shè)計的目的是防止從子組件意外改變父級組件的狀態(tài),從而導(dǎo)致應(yīng)用的數(shù)據(jù)流向難以理解。
與之對應(yīng)的就是雙向數(shù)據(jù)流,父組件子組件都可以任意修改,互相產(chǎn)生影響,這樣的話使用這套數(shù)據(jù)的其他組件也會跟著變化,變得非常的詭異。
在復(fù)雜的應(yīng)用中,控制數(shù)據(jù)有規(guī)則的改變和傳遞非常重要,如果不是單向數(shù)據(jù)流的限制,任何組件都能修改數(shù)據(jù),就跟定義全局的數(shù)據(jù)在任何程序都能修改一樣,最終經(jīng)過多個函數(shù)的調(diào)用修改后,出現(xiàn)了問題,不能準(zhǔn)確的定位到具體的函數(shù)中,排查問題會變的非常的困難。
每次父級組件發(fā)生更新時,子組件中所有的 prop 都將會刷新為最新的值。由父組件傳遞給子組件的數(shù)據(jù),子組件內(nèi)部不能改變 prop。如果你這樣做了,Vue 會在瀏覽器的控制臺中發(fā)出警告。
來個例子說明一下。上面的例子中,需要在下拉框中選擇具體的的一項,顯示在 p標(biāo)簽中,要顯示的數(shù)據(jù)是通過外界傳遞的 selectIndex 來決定從 list 中選取哪一項。那我們可以這樣來做,在點擊下拉框的某一項時,改變 selectIndex 為點擊的一項的下標(biāo)即可,具體如下:
HTML 代碼:
JavaScript代碼:
Vue.component("custome-select",{ props:{ // 省略了title和list.... selectIndex:{ type: Number, default:0 } }, data(){ return { show: false // 一開始狀態(tài)為false,也就是不顯示下拉列表 } }, template: ``, methods:{ toggleShow(){ this.show = !this.show; }, changeIndex(index){ // 改變?yōu)檫x中的下標(biāo),此時會報錯 this.selectIndex = index; } } }) new Vue({ el: "#app" }){{title}}
請選擇:{{list[selectIndex]}}
- {{item}}
以上代碼做的事情:
接收外界傳入的 selecteIndex,在模板中選擇對應(yīng)的值{{list[selectIndex]}}
給下拉框的每一項綁定事件,并傳遞各自的下標(biāo)
傳遞下標(biāo)給到 changeIndex 函數(shù),改變selectIndex的值
控制臺報錯:[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop"s value. Prop being mutated: "selectIndex"大致的意思是:不能直接修改組件的props值,當(dāng)父組件重新渲染時候會重寫這個。在組件中使用data或者computed屬性來代替修改prop的值。
以上的報錯已經(jīng)警告了,不能直接修改props的值,但是組件內(nèi)部是可以修改組件內(nèi)部數(shù)據(jù) data ,所以修改如下:
// 其他代碼省略 Vue.component("custome-select",{ data(){ return { currentIndex: this.selectIndex // 把selectIndex作為currentIndex的初始值 } }, template: ``, methods:{ changeIndex(index){ // 改變自己內(nèi)部狀態(tài)currentIndex this.currentIndex = index; } } }){{title}}
請選擇:{{list[currentIndex]}}
- {{item}}
以上代碼分析:
在 data 中定義組件內(nèi)部狀態(tài)currentIndex,將props中的selectIndex的值,作為currentIndex的初始值
修改模板中取值的selectIndex為currentIndex
點擊改變currentIndex,此時修改的是組件內(nèi)部狀態(tài),不是props的值,修改成功
從以上的例子中可以看出來,data 中定義的就是組件內(nèi)部狀態(tài),只在組件內(nèi)部更改,而傳遞的 props 不能在組件內(nèi)修改,可以通過賦值給data,修改data的值來更新組件自身的狀態(tài)。
父組件監(jiān)聽,子組件發(fā)布上面說的是父組件向子組件定制數(shù)據(jù)傳遞 props,在子組件內(nèi)部會產(chǎn)生一些交互。
子組件內(nèi)部交互一旦發(fā)生后,父組件是需要根據(jù)子組件的交互會產(chǎn)生一些影響,比如改變顏色,顯示文字等。父組件這些變換又不能寫在子組件的交互中,因為子組件是通用的組件。一旦寫了某個父組件的業(yè)務(wù)代碼,只能和這個父組件綁定在一起,不能使用在別的地方了了,此時組件不能達到通用的目的。
舉個例子:
以下使用了兩次 custome-select 組件,當(dāng)點擊第一個組件的下拉框某一項時候,就需要改變 class 為 test1 的div 樣式為 red 色。當(dāng)點擊第二個組件的下拉框某一項時候,就需要改變 class 為 test2 的div 樣式為 blue 色。
第一個需求 第二個需求
使用了兩次組件,組件內(nèi)部點擊下拉框時不能寫具體的處理第一個需求還是第二個需求。而是交到外部的父組件來決定,這時候父組件就需要知道子組件內(nèi)部是否點擊了下拉框。而點擊下拉框這個動作是由用戶觸發(fā)的,不知何時會觸發(fā)一次,那怎么辦呢?
跟原生的元素處理思路一樣,假定以后用戶點擊了這個元素后,需要改變頁面中樣式,那么就需要監(jiān)控這個元素的點擊事件,只要用戶點擊了,觸發(fā)事件處理函數(shù),在函數(shù)中寫具體改變樣式這個動作。
HTML代碼:
JavaScript代碼:
以上代碼是 DOM0 級時代的寫法,直接在行間寫監(jiān)聽事件,這樣寫更直觀。目的就是當(dāng)有用戶點擊了按鈕一下,瀏覽器內(nèi)部就會發(fā)布一個 click 事件,而正好我們在元素上監(jiān)聽了 click 事件,就會把對應(yīng)的事件處理函數(shù)觸發(fā),從而達到開發(fā)者的目的,對頁面做出一些變化。
組件標(biāo)簽使用在模板中,此時外界需要知道組件內(nèi)部發(fā)生了的交互,那么思路一致,也需要在行間監(jiān)聽事件,不過此事件名字不限于是 w3c 規(guī)定的事件名,可以自定義事件名,結(jié)合 Vue 中綁定事件的方式,代碼如下:
第一個需求 第二個需求
把事件處理函數(shù)寫在選項對象中:
new Vue({ el: "#app", data: { color1: "", color2: "" }, methods: { // 第一個需求 changeTest1Handle(){ this.color1 = "red"; }, // 第二個需求 changeTest2Handle(){ this.color2 = "blue"; } } })
以上代碼準(zhǔn)備完畢,去點擊下拉選項,并沒有觸發(fā)父組件的函數(shù),并沒有完成需求,為什么呢?
在原生元素上在行間監(jiān)控事件,用戶點擊元素后,瀏覽器會發(fā)布 click 事件。而現(xiàn)在換做是使用自定義事件來監(jiān)控子組件內(nèi)部產(chǎn)生的交互,這就需要在子組件內(nèi)部自己發(fā)布這個自定義的事件,否則監(jiān)控的自定義事件是無效的。
那什么時候發(fā)布事件呢?就是在用戶點擊了下拉框的選項時候發(fā)布這個自定義事件即可。
你可以這樣來理解,監(jiān)聽原生事件 click ,只需要監(jiān)聽,開發(fā)者無需手動的在瀏覽器內(nèi)部寫發(fā)布事件,click 事件名是瀏覽器給開發(fā)者約定的名字。而現(xiàn)在我們需要自己設(shè)計子組件發(fā)布事件,父組件監(jiān)聽這樣的機制。所以需要開發(fā)者自己約定事件的名字和手動的在組件中發(fā)布事件。在 Vue 中這樣的訂閱/發(fā)布模式已經(jīng)寫好,開發(fā)者只需要調(diào)用即可。
在子組件中發(fā)布事件:
// 其他代碼省略 methods:{ changeIndex(index){ this.currentIndex = index; // 在點擊選項時候產(chǎn)生交互,手動發(fā)布事件,通知父組件 this.$emit("click-option"); } }
當(dāng)點擊選項時候,父組件中會完成不同的需求,改變不同元素的顏色。
以上代碼父子組件之間完全的解耦,父組件中不使用這個組件,依然可以工作,子組件不使用在這個組件中,可以使用在任意其他的組件中。如果父組件關(guān)系子組件內(nèi)部選中下拉框一項這個交互,只需要監(jiān)聽 click-option這個自定義事件,不關(guān)心則不監(jiān)聽。
總結(jié)以上可以看出一個組件數(shù)據(jù)的來源有兩個:
組件自身的數(shù)據(jù),寫在 data 中
父組件傳遞的數(shù)據(jù),寫在props中
父子組件之間通信:
父 ---> 子,使用 props
子 ---> 父,訂閱發(fā)布模式
以上屬于個人理解,如有偏差歡迎指正學(xué)習(xí),謝謝。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/98081.html
摘要:有興趣的同學(xué)可以查看之前發(fā)布的文章學(xué)習(xí)系列一學(xué)習(xí)實踐筆記附學(xué)習(xí)系列二學(xué)習(xí)實踐筆記附學(xué)習(xí)系列三和網(wǎng)絡(luò)傳輸相關(guān)知識的學(xué)習(xí)實踐學(xué)習(xí)系列四打包工具的使用學(xué)習(xí)系列五從來聊聊學(xué)習(xí)系列項目地址項目暫時有點亂,之后會進行整理優(yōu)化。 上次學(xué)習(xí)了vue-router的使用,讓我能夠在各個頁面間切換,將頁面搭建了起來。這次則要學(xué)習(xí)vue的狀態(tài)管理模式——vuex。它類似于redux來應(yīng)用的全局狀態(tài)。 注:本...
摘要:前言是一個提供數(shù)據(jù)雙向綁定的庫,其核心思想無非就是數(shù)據(jù)驅(qū)動組件系統(tǒng)數(shù)據(jù)驅(qū)動的核心是一個響應(yīng)的數(shù)據(jù)綁定系統(tǒng),它讓數(shù)據(jù)與保持同步非常簡單。和所以只兼容及以上版本,可稱為基于依賴收集的觀測機制。核心是,即,保證數(shù)據(jù)和視圖的一致性。 前言 Vue.js是一個提供MVVM數(shù)據(jù)雙向綁定的庫,其核心思想無非就是: 數(shù)據(jù)驅(qū)動 組件系統(tǒng) 數(shù)據(jù)驅(qū)動 Vue.js 的核心是一個響應(yīng)的數(shù)據(jù)綁定系統(tǒng),它讓數(shù)...
摘要:前言是一個提供數(shù)據(jù)雙向綁定的庫,其核心思想無非就是數(shù)據(jù)驅(qū)動組件系統(tǒng)數(shù)據(jù)驅(qū)動的核心是一個響應(yīng)的數(shù)據(jù)綁定系統(tǒng),它讓數(shù)據(jù)與保持同步非常簡單。和所以只兼容及以上版本,可稱為基于依賴收集的觀測機制。核心是,即,保證數(shù)據(jù)和視圖的一致性。 前言 Vue.js是一個提供MVVM數(shù)據(jù)雙向綁定的庫,其核心思想無非就是: 數(shù)據(jù)驅(qū)動 組件系統(tǒng) 數(shù)據(jù)驅(qū)動 Vue.js 的核心是一個響應(yīng)的數(shù)據(jù)綁定系統(tǒng),它讓數(shù)...
摘要:采用了新舊的對比,獲取差異的,最后一次性的更新到真實上。對基本屬性進行監(jiān)聽對對象進行監(jiān)聽對對象某一個屬性監(jiān)聽監(jiān)聽自定義指令全局指令,第一個參數(shù)是指令名,第二個參數(shù)是一個對象,對象內(nèi)部有個的函數(shù),函數(shù)里有這個參數(shù),表示綁定了這個指令的元素。 11.vue 虛擬DOM的理解 Web界面由DOM樹(樹的意思是數(shù)據(jù)結(jié)構(gòu))來構(gòu)建,當(dāng)其中一部分發(fā)生變化時,其實就是對應(yīng)某個DOM節(jié)點發(fā)生了變化,??...
閱讀 2089·2021-09-07 10:14
閱讀 1507·2019-08-30 15:53
閱讀 2293·2019-08-30 12:43
閱讀 2892·2019-08-29 16:37
閱讀 777·2019-08-26 13:29
閱讀 2031·2019-08-26 13:28
閱讀 463·2019-08-23 18:33
閱讀 3563·2019-08-23 16:09