組件是vue的特性,它是Vue最強(qiáng)大的功能之一。在Vue中,組件可以擴(kuò)展HTML元素,封裝可重用的代碼;在較高層面上,組件是自定義元素,Vue的編譯器為它添加特殊功能;在有些情況下,組件也可以是原生HTML元素的形式,以is特性擴(kuò)展。
本教程操作環(huán)境:windows7系統(tǒng)、vue3版,DELL G3電腦。
Vue.js 是一個優(yōu)秀的前端界面開發(fā) JavaScript 庫,它之所以非?;?,是因為有眾多突出的特點,其中主要的特點有以下幾個。
1) 輕量級的框架
Vue.js 能夠自動追蹤依賴的模板表達(dá)式和計算屬性,提供 MVVM 數(shù)據(jù)綁定和一個可組合的組件系統(tǒng),具有簡單、靈活的 API,使讀者更加容易理解,能夠更快上手。
2) 雙向數(shù)據(jù)綁定
聲明式渲染是數(shù)據(jù)雙向綁定的主要體現(xiàn),同樣也是 Vue.js 的核心,它允許采用簡潔的模板語法將數(shù)據(jù)聲明式渲染整合進(jìn) DOM。
3) 指令
Vue.js 與頁面進(jìn)行交互,主要就是通過內(nèi)置指令來完成的,指令的作用是當(dāng)其表達(dá)式的值改變時相應(yīng)地將某些行為應(yīng)用到 DOM 上。
4) 組件化
組件(Component)是 Vue.js 最強(qiáng)大的功能之一。組件可以擴(kuò)展 HTML 元素,封裝可重用的代碼。在較高層面上,組件是自定義元素,Vue.js 的編譯器為它添加特殊功能。在有些情況下,組件也可以是原生 HTML 元素的形式,以 is 特性擴(kuò)展。
在 Vue 中,父子組件通過 props 傳遞通信,從父向子單向傳遞。子組件與父組件通信,通過觸發(fā)事件通知父組件改變數(shù)據(jù)。這樣就形成了一個基本的父子通信模式。
在開發(fā)中組件和 HTML、JavaScript 等有非常緊密的關(guān)系時,可以根據(jù)實際的需要自定義組件,使開發(fā)變得更加便利,可大量減少代碼編寫量。
組件還支持熱重載(hotreload)。當(dāng)我們做了修改時,不會刷新頁面,只是對組件本身進(jìn)行立刻重載,不會影響整個應(yīng)用當(dāng)前的狀態(tài)。CSS 也支持熱重載。
組件的優(yōu)勢:
-
降低整個系統(tǒng)的耦合度,在保持接口不變的情況下,我們可以替換不同的組件快速完成需求,例如輸入框,可以替換為日歷、時間、范圍等組件作具體的實現(xiàn)
-
調(diào)試方便,由于整個系統(tǒng)是通過組件組合起來的,在出現(xiàn)問題的時候,可以用排除法直接移除組件,或者根據(jù)報錯的組件快速定位問題,之所以能夠快速定位,是因為每個組件之間低耦合,職責(zé)單一,所以邏輯會比分析整個系統(tǒng)要簡單
-
提高可維護(hù)性,由于每個組件的職責(zé)單一,并且組件在系統(tǒng)中是被復(fù)用的,所以對代碼進(jìn)行優(yōu)化可獲得系統(tǒng)的整體升級
5) 客戶端路由
Vue-router 是 Vue.js 官方的路由插件,與 Vue.js 深度集成,用于構(gòu)建單頁面應(yīng)用。Vue 單頁面應(yīng)用是基于路由和組件的,路由用于設(shè)定訪問路徑,并將路徑和組件映射起來,傳統(tǒng)的頁面是通過超鏈接實現(xiàn)頁面的切換和跳轉(zhuǎn)的。
6) 狀態(tài)管理
狀態(tài)管理實際就是一個單向的數(shù)據(jù)流,State 驅(qū)動 View 的渲染,而用戶對 View 進(jìn)行操作產(chǎn)生 Action,使 State 產(chǎn)生變化,從而使 View 重新渲染,形成一個單獨的組件。
初識VUE組件應(yīng)用
實例化多個vue對象
用new創(chuàng)建多個vue對象并命名,可以通過變量相互訪問
例子:對象2修改對象1的name變量
<!-- 第一個根元素 --> <div id="vue-app-one">這里是:{{name}}</div> <!-- 第二個根元素 --> <div id="vue-app-two"> <p>這里是:{{name}}</p><br> <button @click="changeName">change-one-name</button> <!-- 點擊后修改vue-app-one的name值--> </div>
// 第一個vue對象 var one = new Vue({ el:"#vue-app-one", data:{ "name":"ccy1" } }) // 第二個vue對象 var two = new Vue({ el:"#vue-app-two", data:{ "name":"ccy2" }, methods:{ // 修改vue-app-one的name為'ccy333' changeName:function(){ one.name = 'ccy333' } } })
效果:點擊后修改”ccy1“為”ccy333“
全局組件
定義與使用
- 定義全局組件,需給組件一個名字,調(diào)用時,將組件名當(dāng)作標(biāo)簽名使用;相當(dāng)于自定義標(biāo)簽,該標(biāo)簽下可以包含很多子html標(biāo)簽;
- 這些子html標(biāo)簽定義在組件的template屬性中,每次調(diào)用該組件,都渲染template里的標(biāo)簽
- template里必須只有一個根元素
- 在組件中,data是函數(shù),將數(shù)據(jù)return回去
- 依然可以用this來調(diào)用data中定義的數(shù)據(jù)
例子:
定義組件:
① 定義一個組件,命名為my-component
② 其中包含數(shù)據(jù):name和方法:changeName
③ 渲染出的html效果有一個p標(biāo)簽,包含一個按鈕,點擊按鈕時,修改name
④ 命名規(guī)范:camelCase (駝峰命名法) 與kebab-case (短橫線分隔命名)
- 當(dāng)寫成標(biāo)簽時,遇到有大寫字母的命名,需要改成小寫并用橫桿鏈接前后兩個部分,如定義組件時命名為myComponent,寫成標(biāo)簽時應(yīng)寫成<my-component>;
- 組件定義時也可以用橫桿法命名;
- 如果定義時用myComponent,標(biāo)簽用<my-component>是OK的,系統(tǒng)自動識別
// 自定義的全局組件my-component // template中只有一個根元素p標(biāo)簽,里面包含一個button按鈕 Vue.component('my-component',{ template:`<p> 我的名字是:{{name}} <button @click='changeName()'>btn</button> </p>`, data(){ return { name:'ccy' } }, methods:{ changeName:function(){ this.name = '安之' } } }) // vue對象1 new Vue({ el:"#vue-app-one", }) // vue對象2 new Vue({ el:"#vue-app-two", })
使用組件:
① 在vue對象對應(yīng)的根元素(el指定標(biāo)簽)下使用
② 由于定義的是全局組件,所以可以在任意的vue對象下使用
③ 組件可復(fù)用,在一個vue對象下可以使用多次,且組件間互相獨立
<div id="vue-app-one"> <my-component></my-component> <my-component></my-component> </div> <div id="vue-app-two"> <my-component></my-component> </div>
效果:
data是一個函數(shù)
在vue對象中,data屬性值是一個對象,比如這樣的:
但是在全局組件中,同一份data可能被多個vue對象使用,每個對象不單獨維護(hù)一份data時,如果某一個vue對象修改了data中的一個變量,其他vue對象獲取data時就會被影響;
如果用上面的例子做案例,若組件中的data是對象(引用),其他地方均不改變,兩個vue對象便共享同一個name變量;當(dāng)我通過其中一個vue對象改變name數(shù)據(jù)時(即點擊任一個btn按鈕),另一個對象獲得的name也發(fā)生了改變(其他按鈕處的’ccy’也都被改成了’安之’)
因此,為保證數(shù)據(jù)的獨立性,即每個實例可以維護(hù)一份被返回對象的獨立的拷貝,data為每個實例都return一份新創(chuàng)建的數(shù)據(jù),不同的vue對象獲取的data均互不影響
在vscode中不允許組件中的data是對象,會報錯:
[Vue warn]: The “data” option should be a function that returns a per-instance value in component definitions.
局部組件
- 局部組件注冊在某個vue對象中,
- 只有注冊過該局部組件的vue對象才能使用這個局部組件
例子:
局部組件定義:
// template僅一個根元素:ul var msgComponent = { // 數(shù)據(jù)是自身提供的 (hobbies) template:`<ul><li v-for='hobby in hobbies' v-bind:key='hobby.id'>{{hobby}}</li></ul>`, data(){ return { hobbies:['看劇','看動漫','吃好吃的'] } } }
注冊局部組件:
// 僅由注冊過該局部組件的vue對象才能使用,此處為div#vue-app-one // 注意命名規(guī)范,components中對象的key將會被作為標(biāo)簽名,多個單詞拼接的命名需使用橫桿法 // 可以寫成msg-component,此處直接簡化了命名為msg, new Vue({ el:"#vue-app-one", components:{ "msg": msgComponent } })
html文件中使用<msg></msg>
:
<div id="vue-app-one"> <p>這里是vue-app-one</p> <mycomponent></mycomponent> <mycomponent></mycomponent> <p>我的愛好:</p> <msg></msg> <!--使用局部組件--> </div>
效果: 紅框圈出的部分就是局部組件渲染出來的
父向子傳值/傳引用:prop
靜態(tài)傳值
創(chuàng)建子組件:
var titleComponent = { props:["title"], template:`<p>{{title}}</p>` // 所需要的數(shù)據(jù)title由父組件提供 }
在父組件的components屬性中注冊子組件:
new Vue({ el:"#vue-app-one", components:{ "msg": msgComponent, "titleComponent":titleComponent }, })
在父組件上使用子組件:
<!-- div#vue-app-one為父組件 --> <div id="vue-app-one"> <p>這里是vue-app-one</p> <mycomponent></mycomponent> <mycomponent></mycomponent> <!--使用子組件title-component,并傳值"我的愛好:"給子組件--> <title-component title="我的愛好:"></title-component> <msg></msg> </div>
效果:紅框標(biāo)記處就是父向子傳值并展示
動態(tài)傳值:v-bind
定義子組件:
var titleComponent = { props:["title"], template:`<p>{{title}}</p>` }
在父組件的components屬性中注冊子組件:
new Vue({ el:"#vue-app-one", components:{ "msg": msgComponent, "titleComponent":titleComponent }, data(){ return { title:"my hobbies are ", } } })
使用子組件,通過綁定父組件data中的變量title來實現(xiàn)動態(tài)傳值:
<!-- div#vue-app-one為父組件 --> <div id="vue-app-one"> <p>這里是vue-app-one</p> <mycomponent></mycomponent> <mycomponent></mycomponent> <!-- 動態(tài)綁定title --> <title-component v-bind:title="title"></title-component> <msg></msg> </div>
效果:紅框處就是動態(tài)綁定獲取數(shù)據(jù)的展示
傳遞數(shù)組等復(fù)雜數(shù)據(jù)時,也可以使用v-bind來動態(tài)傳值,如:
需要向子級傳遞hobbies數(shù)組,在vue實例對象(父)中創(chuàng)建數(shù)據(jù)hobbies:
new Vue({ el:"#vue-app-one", components:{ "msg": msgComponent, "titleComponent":titleComponent }, data:{ title:"my hobbies are ", hobbies:['看劇','看動漫','吃好吃的'], //需要向子組件傳遞的數(shù)據(jù) } })
定義子組件:
var msgComponent = { template:` <p>{{hobby}}</p> `, props:["hobby"], data(){ return { } } }
使用子組件:
<!-- div#vue-app-one為父組件 --> <div id="vue-app-one"> <p>這里是vue-app-one</p> <mycomponent name="ccy"></mycomponent> <mycomponent name="ccy"></mycomponent> <title-component v-bind:title="title"></title-component> <!-- 動態(tài)傳值:hobbies --> <msg v-for="hobby in hobbies" v-bind:hobby="hobby" v-bind:key="hobby.id"></msg> </div>
效果:
跳回“一點想法”處
子向父:事件傳值$emit
子組件不能通過prop向父組件傳遞數(shù)據(jù),需要使用事件向父組件拋出一個值,告知父組件我需要實現(xiàn)一個功能,由父組件處理這個事件
例子:點擊按鈕,改變名稱chinesename
(由于data變量名不支持chinese-name形式,花括號里不支持chineseName形式,所以這里我都用了小寫,此處記錄一下,日后學(xué)到了新知再來填坑)
先在父組件的data中定義chinesename的初始值:
new Vue({ el:"#vue-app-one", data:{ chinesename:"anzhi" // chinesename初始值 } })
創(chuàng)建子組件,并注冊事件change-name(就像click事件一樣,需要讓系統(tǒng)能夠辨認(rèn)這是一個事件并監(jiān)聽,當(dāng)事件被觸發(fā)時,執(zhí)行某項約定好的操作):
Vue.component('blog-post', { props: ['chinesename'], template: ` <div class="blog-post"> <h4>{{ chinesename }}</h4> <button v-on:click='$emit("change-name","ruosu")'> 修改名字 </button> </div> ` // blog-post組件包含一個h4,顯示chinesename,和一個按鈕 // 點擊這個按鈕,觸發(fā)change-name事件,將"ruosu"作為參數(shù)傳遞給指定的處理函數(shù)onChangeName })
在父組件中使用子組件,定義change-name的處理函數(shù)為onChangeName:
<div id="vue-app-one"> <p>這里是vue-app-one</p> <!-- v-bind:通過prop給子組件傳遞chinesename的初始值 --> <!-- v-on:子組件通過$emit給父組件傳遞新的chinesename的值 --> <div id="blog-posts-events-demo"> <blog-post v-bind:chinesename='chinesename' v-on:change-name = "onChangeName" ></blog-post> </div> </div>
在父組件處定義事件處理函數(shù)onChangeName:
new Vue({ el:"#vue-app-one", data:{ chinesename:"anzhi" }, methods:{ onChangeName:function(value){ // 將chinesename換成傳遞過來的數(shù)據(jù) this.chinesename=value } } })
效果:
一點想法
關(guān)于父子組件的區(qū)分,在此寫一點總結(jié),還是日后學(xué)了新知識再來填坑
官網(wǎng)中沒有很明確指明兩者的定義和區(qū)別,在網(wǎng)上搜了一圈,覺得比較多人認(rèn)可并且好理解的是:
- el指定的根元素為父組件(使用之處為父組件)
- vue實例對象也可看做組件
在前面這些父子傳值的例子中,我們可以看到,對于局部組件,我們會在某個html根元素中注冊并使用,所以此時el指定的根元素在html文件中是這個局部組件的父組件,局部組件在html使用時便是這個父組件的一份子,承擔(dān)數(shù)據(jù)傳輸?shù)呢?zé)任
跳轉(zhuǎn)到父向子動態(tài)傳值案例
再用繞口令說一波,即:title-component組件定義處與使用處,兩者身份是不一樣的,在定義處,它是局部組件,也是子組件,需注冊才能使用;在使用處,它是根元素的包含一部分,根元素為父組件,而“它”,承擔(dān)著父組件與子組件數(shù)據(jù)溝通的重任
這個總結(jié)在全局組件情況下也適用,使用該全局組件的根元素是父組件,如上面的子向父傳值的案例,p#vue-app-one是父組件,<blog-post></blog-post>作為父子組件溝通的橋梁,全局組件blog-post為子組件
圖示:
如果是子組件又嵌套了子組件,被嵌套的組件是子子組件,以此類推
【相關(guān)視頻教程推薦:vue視頻教程、web前端入門】