Vue 組件官網(wǎng):https://cn.vuejs.org/v2/guide/components.html
組件化的思想
- 模塊化是一種思想,一種構(gòu)建方式达箍,把一種很復(fù)雜的事物拆分成一個(gè)一個(gè)的小模塊硬纤,然后通過某種特定的方式把這些小模塊組織到一起相互協(xié)作完成這個(gè)復(fù)雜的應(yīng)用功能筝家。
- 在 Vue 中,組件就是用來封裝視圖(HTML)的莹菱。組件思想就是把一個(gè)很大的復(fù)雜的 Web 頁(yè)面視圖拆分成一塊一塊的組件視圖,然后利用某種特定的方式把他們組織到一起完成完整的 Web 應(yīng)用構(gòu)建蜜徽。
- HTML 結(jié)構(gòu)
- CSS 樣式
- JavaScript 行為
- 為什么要把視圖組件化,優(yōu)勢(shì)盆色?
- 開發(fā)效率
- 可維護(hù)性
- 可重用性
- 便于分工
通過 Element 體會(huì)組件的威力
Element 是基于 Vue 開發(fā)的一個(gè)知名的第三方組件庫(kù)缕允,它能幫助我們更加快速的構(gòu)建應(yīng)用教届。
Element 官網(wǎng)
使用:
- 安裝:`npm i element-ui -S``
- 引入 element-ui 組件庫(kù)的 CSS 樣式
- 導(dǎo)入 Vue
- 引入 element-ui 組件庫(kù)的 JavaScript 腳本
- 調(diào)用 element-ui 組件
組件是什么
組件在代碼中的直觀體現(xiàn)就是封裝了一個(gè)自定義的 HTML 標(biāo)簽
使用組件
組件的定義方式分為兩種案训,全局定義和局部定義:
- 全局組件定義在全局,在任意組件中都能直接使用
- 局部組件定義在局部城舞,只能在當(dāng)前組件使用
- 建議把通用組件定義在全局脱柱,把不通用組件定義在局部
全局注冊(cè)
注冊(cè):
基本形式:Vue.component('組件名字', 組件模板對(duì)象)
方式 一:
Vue.component('my-component',
Vue.extend({
template: '<div>A custom component!</div>'
})
)
new Vue({
el: '#app'
})
方式二:
Vue.component('my-component', {
template: '<div>A custom component!</div>'
})
new Vue({
el: '#app'
})
方式三:
<template id="tmpl">
<div>A custom component!</div>
</template>
<script>
Vue.component('my-component', {
template: '#tmpl'
})
new Vue({
el: '#app'
})
</script>
方式四:
<script type="text/x-template" id="tmpl">
<div>A custom component!</div>
</script>
<script>
Vue.component('my-component', {
template: '#tmpl'
})
var vm = new Vue({
el: '#app'
})
</script>
在模板中使用組件:
<div id="app">
<my-component></my-component>
</div>
渲染結(jié)果:
<div id="app">
<div>A custom component!</div>
</div>
局部注冊(cè)
不必把每個(gè)組件都注冊(cè)到全局。可以通過某個(gè) Vue 實(shí)例/組件的實(shí)例選項(xiàng) components
注冊(cè)板壮,僅作用在其作用域中可用的組件:
注冊(cè):
new Vue({
el: '#app'
components: {
// <my-component> 將只能在父組件模板中可用
// 鍵名就是組件名稱,值是一個(gè)對(duì)象笨使,對(duì)象中配置組件的選項(xiàng)
'my-component': {
template: '<div>A custom component!</div>'
}
}
})
使用:
<div id="app">
<my-component></my-component>
</div>
- 組件一般分為兩種
- 通用的組件
- 不通用的業(yè)務(wù)組件
所以設(shè)計(jì)具體業(yè)務(wù)盡量定義成局部。不要污染全局
組件的模板
組件的模板 template 只能有有一個(gè)根元素靶草,否則警告報(bào)錯(cuò):
Component template should contain exactly one root element.
組件定義 template 可以是字面量字符串或是一個(gè)定義了字面量字符串的變量,缺點(diǎn)是沒有高亮派继,內(nèi)置在 JavaScript 中,寫起來麻煩绅络。
X-Templates:template 可以寫在 script 標(biāo)簽中,解決了高亮的問題寻行,但是當(dāng)組件數(shù)量多的時(shí)候拌蜘,也麻煩。
-
以上方式都不好举娩,我們最終的解決方案是使用 Vue 的
.vue
單文件組件來寫铜涉。但是要想使用這種方式必須結(jié)合 webpack 構(gòu)建工具。
組件的復(fù)用
- 組件是可復(fù)用的 Vue 實(shí)例召边,可以有自己的 data片挂、methods滋将、computed父丰、watch 等等選項(xiàng)
- 組件是獨(dú)立的作用域,不能訪問父組件的數(shù)據(jù)
- 組件的 data 必須是函數(shù)坟漱,函數(shù)中返回一個(gè)對(duì)象作為組件的 data。因此每個(gè)實(shí)例可以維護(hù)一份被返回對(duì)象的獨(dú)立的拷貝觅捆。
data: function () {
return {
count: 0
}
}
組件的組織
-
采用組件化構(gòu)建方式,一個(gè)應(yīng)用被一個(gè)根組件管理起來,根組件中嵌套了子組件域携,子組件還可以嵌套自己的子子組件。
組件樹
放到匿名自執(zhí)行函數(shù)中,將某些代碼包裹起來可以實(shí)現(xiàn)塊級(jí)作用域的效果豆巨,減少全局變量的數(shù)量熊户,減少命名沖突蝗罗,在匿名自執(zhí)行函數(shù)執(zhí)行結(jié)束后變量就會(huì)被內(nèi)存釋放掉沼琉,從而也會(huì)節(jié)省了內(nèi)存傻昙。
圖解 Vue 組件化構(gòu)建方式
從程序角度實(shí)現(xiàn)組件化應(yīng)用構(gòu)建的架構(gòu)方式如下圖,這種方式的缺點(diǎn)是:
- 組件的模板沒有高亮
- 沒有模塊化之前,首頁(yè)一堆 script 標(biāo)簽进泼,比較麻煩
使用 vue 實(shí)例的 render 方法渲染組件
官網(wǎng) render 選項(xiàng):https://cn.vuejs.org/v2/api/#render
我們可以用 render 選項(xiàng)進(jìn)行組件渲染逼纸。該渲染函數(shù)接收一個(gè) createElement 方法作為第一個(gè)參數(shù)用來創(chuàng)建 VNode,與前面介紹的的組件渲染不同的是,使用 render 渲染會(huì)把 app 的 div 給覆蓋糜俗。所以也就只能進(jìn)行一次模板替代扩淀。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
</div>
<script>
var login = {
template: '<h1>這是登錄組件</h1>'
}
var vm=new Vue({
el:'#app',
render: function (createElement, context) {
return createElement(login)
}
});
</script>
</body>
</html>
組件通信
在 Vue 中旺韭,父子組件的關(guān)系可以總結(jié)為 prop 向下傳遞,事件向上傳遞。父組件通過 prop 給子組件下發(fā)數(shù)據(jù),子組件通過事件給父組件發(fā)送消息唐全。
父子組件通信:Props Down
- 在父組件中通過子組件標(biāo)簽聲明屬性的方式傳遞數(shù)據(jù)剪勿。注意:只有
v-bind
才可以傳遞動(dòng)態(tài)數(shù)據(jù)厕吉。
<child message="hello!"></child>
- 在子組件中聲明 props 接收父組件傳遞的數(shù)據(jù),組件接收到 props 就可以像訪問 data 中的數(shù)據(jù)一樣髓窜,來訪問 props 中的數(shù)據(jù)并使用程拭。
Vue.component('child', {
// 聲明 props
props: ['message'],
// 就像 data 一樣崖媚,prop 也可以再模板中使用
// 同樣也可以再 vm 實(shí)例中通過 this.message 來使用
template: '<span>{{ message }}</span>'
})
- Vue 組件通信原則:?jiǎn)蜗驍?shù)據(jù)流
父組件數(shù)據(jù)的改變可以影響到子組件荠呐,但是子組件不要去修改父組件的數(shù)據(jù)鞠值。因?yàn)楫?dāng)你的組件嵌套過深的時(shí)候,在子組件中修改某個(gè)父組件的數(shù)據(jù)可能會(huì)讓你的應(yīng)用數(shù)據(jù)流變得非常復(fù)雜而難以理解抵恋。
注意:在 JavaScript 中對(duì)象和數(shù)組是通過引用傳入的,所以對(duì)于一個(gè)數(shù)組或?qū)ο箢愋偷?prop 來說别瞭,在子組件中改變這個(gè)對(duì)象或數(shù)組本身將會(huì)影響到父組件的狀態(tài)墙歪。引用類型數(shù)據(jù)雖然可以修改毕源,但是不建議使用瘩欺,因?yàn)檫@樣就違背了 Vue 組件的通信原則
思考:那子組件要改數(shù)據(jù)呢塌忽?子組件能不能把數(shù)據(jù)給父親呢,讓父組件自己去修改自己的數(shù)據(jù)呢?
父子組件通信:Event Up
父組件使用 prop 傳遞數(shù)據(jù)給子組件吁系。但子組件怎么跟父組件通信呢?這個(gè)時(shí)候 Vue 的自定義事件系統(tǒng)就派的上用場(chǎng)了。
- 在子組件中調(diào)用
$emit()
方法發(fā)布一個(gè)事件
Vue.component('button-counter', {
template: `<button v-on:click="incrementCounter">{{ counter }}</button>`
data: function() {
return {
counter: 0
}
}
methods: {
incrementCounter: function () {
this.counter += 1
// 發(fā)布一個(gè)名字叫 increment 的事件
this.$emit('increment')
}
}
})
- 在父組件中提供一個(gè)子組件內(nèi)部發(fā)布的事件處理函數(shù)
new Vue({
el: '#counter-event-example',
data: {
total: 0
},
methods: {
incrementTotal : function () {
this.total += 1
}
}
})
- 在子組件的模板的標(biāo)簽上訂閱子組件內(nèi)部發(fā)布的事件
<div id="counter-event-example">
<p>{{ total }}</p>
<!--訂閱子組件內(nèi)部發(fā)布的 increment 事件,當(dāng)子組件內(nèi)部 $emit('increment')
發(fā)布的時(shí)候买窟,就會(huì)調(diào)用到父組件中的 incrementTotal 方法-->
<button-counter @increment="incrementTotal"></button-counter>
</div>
非父子組件通信:Event Bus
專業(yè)組件通信:Vuex
Vuex 是 Vue 配套的公共數(shù)據(jù)管理工具,它可以把一些共享的數(shù)據(jù)变丧,保存到 Vuex 中攻晒,方便整個(gè)程序的任何組件直接獲取或修改我們的公共數(shù)據(jù)。如果組件之間有共享的數(shù)據(jù),可以直接掛載到 Vuex 中曹质,而不必通過父子組件之間傳值。
Vuex 是一個(gè)全局的共享數(shù)據(jù)存儲(chǔ)區(qū)域姨夹,就相當(dāng)于是一個(gè)數(shù)據(jù)的倉(cāng)庫(kù)
vuex 的使用
配置vuex的步驟
- 運(yùn)行 cnpm i vuex -S
- 導(dǎo)入包:
import Vuex from 'vuex'
- 注冊(cè) vuex 到 vue 中:
Vue.use(Vuex)
- new Vuex.Store() 實(shí)例,得到一個(gè) 數(shù)據(jù)倉(cāng)儲(chǔ)對(duì)象菇肃。
var store = new Vuex.Store({
state: {
// 專門用來存儲(chǔ)數(shù)據(jù)的
},
mutations: {
// 專門用來定義方法的
}
- 將 vuex 創(chuàng)建的 store 掛載到 VM 實(shí)例上笑跛, 只要掛載到了 vm 上,任何組件都能使用 store 來存取數(shù)據(jù)
})
import App from './App.vue'
const vm = new Vue({
el: '#app',
render: c => c(App),
store
- 操作共享的數(shù)據(jù)與方法惊窖。
- 如果在組件中想要訪問store 中的數(shù)據(jù),只能通過
this.$store.state
來訪問。 - 如果組件想要調(diào)用 mutations 中的方法纲酗,只能使用
this.$store.commit('方法名')
欣簇。 - 如果要操作 store 中的 state 值,只能通過 調(diào)用 mutations 提供的方法衫仑,才能操作對(duì)應(yīng)的數(shù)據(jù)文狱,不推薦直接操作 state 中的數(shù)據(jù)苏研,因?yàn)槿f一導(dǎo)致了數(shù)據(jù)的紊亂摹蘑,不能快速定位到錯(cuò)誤的原因塘安,因?yàn)榍星總€(gè)組件都可能有操作數(shù)據(jù)的方法孩哑。
- mutations 的 函數(shù)參數(shù)列表中,最多支持兩個(gè)參數(shù):
- param1: 是 state 狀態(tài)
+param2: 通過 commit 提交過來的參數(shù)
要想傳遞多個(gè)參數(shù)孟岛,可以通過對(duì)象或者數(shù)組去傳遞。
- param1: 是 state 狀態(tài)
- Vuex 中除了 state 和 mutations 選項(xiàng)參數(shù)督勺,還有 getters 選項(xiàng)參數(shù)渠羞,只負(fù)責(zé)對(duì)外提供數(shù)據(jù),不修改數(shù)據(jù)(想要修改 state 中的數(shù)據(jù)用 mutations) 智哀。
- getters 中的方法次询,和過濾器比較類似,因?yàn)檫^濾器和 getter 都沒有修改原數(shù)據(jù)瓷叫,只是把原數(shù)據(jù)做了一層包裝屯吊,提供給調(diào)用者
- getters 正好也引用了這個(gè)數(shù)據(jù),那么就會(huì)立即觸發(fā) getters 重新求值摹菠。
- 組件訪問 getters 要用
this.$store.getters
來訪問
路由
什么是路由盒卸?
- 后端路由:對(duì)于普通的網(wǎng)站,所有的超鏈接都是URL地址次氨,所有的URL地址都對(duì)應(yīng)服務(wù)器上對(duì)應(yīng)的資源蔽介。
- 前端路由:對(duì)于單頁(yè)面應(yīng)用程序來說,主要通過URL中的hash(#號(hào))來實(shí)現(xiàn)不同頁(yè)面之間的切換,同時(shí)虹蓄,hash有一個(gè)特點(diǎn):HTTP請(qǐng)求中不會(huì)包含hash相關(guān)的內(nèi)容犀呼;所以,單頁(yè)面程序中的頁(yè)面跳轉(zhuǎn)主要用hash實(shí)現(xiàn)薇组。
vue-router
vue-router官方文檔:https://router.vuejs.org/zh/
安裝:
npm install vue-router
引包:
<script src="node_modules/vue-router/dist/vue-router.js"></script>
箭頭函數(shù)綁定父級(jí)上下的 this
路由外臂、和服務(wù)端交互、webpack