5. Vue 組件化

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)建工具。

    image.png

組件的復(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)簽进泼,比較麻煩
todoMVC 的 Vue 組件化構(gòu)建

使用 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>
運(yùn)行結(jié)果

組件通信

在 Vue 中旺韭,父子組件的關(guān)系可以總結(jié)為 prop 向下傳遞,事件向上傳遞。父組件通過 prop 給子組件下發(fā)數(shù)據(jù),子組件通過事件給父組件發(fā)送消息唐全。


父子組件關(guān)系

父子組件通信:Props Down

  1. 在父組件中通過子組件標(biāo)簽聲明屬性的方式傳遞數(shù)據(jù)剪勿。注意:只有 v-bind 才可以傳遞動(dòng)態(tài)數(shù)據(jù)厕吉。
<child message="hello!"></child>
  1. 在子組件中聲明 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>'
})
  1. 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)了。

  1. 在子組件中調(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')
    }
  }
})
  1. 在父組件中提供一個(gè)子組件內(nèi)部發(fā)布的事件處理函數(shù)
new Vue({
  el: '#counter-event-example',
  data: {
    total: 0
  },
  methods: {
    incrementTotal : function () {
      this.total += 1
    }
  }
})
  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的步驟

  1. 運(yùn)行 cnpm i vuex -S
  2. 導(dǎo)入包:import Vuex from 'vuex'
  3. 注冊(cè) vuex 到 vue 中:Vue.use(Vuex)
  4. new Vuex.Store() 實(shí)例,得到一個(gè) 數(shù)據(jù)倉(cāng)儲(chǔ)對(duì)象菇肃。
var store = new Vuex.Store({
  state: {
    // 專門用來存儲(chǔ)數(shù)據(jù)的
  },
  mutations: {
  // 專門用來定義方法的
}
  1. 將 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 
  1. 操作共享的數(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ù)組去傳遞。
  • 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來訪問

路由

什么是路由盒卸?

  1. 后端路由:對(duì)于普通的網(wǎng)站,所有的超鏈接都是URL地址次氨,所有的URL地址都對(duì)應(yīng)服務(wù)器上對(duì)應(yīng)的資源蔽介。
  2. 前端路由:對(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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末律胀,一起剝皮案震驚了整個(gè)濱河市专钉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌累铅,老刑警劉巖跃须,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異娃兽,居然都是意外死亡菇民,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門投储,熙熙樓的掌柜王于貴愁眉苦臉地迎上來第练,“玉大人,你說我怎么就攤上這事玛荞〗刻停” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵勋眯,是天一觀的道長(zhǎng)婴梧。 經(jīng)常有香客問我,道長(zhǎng)客蹋,這世上最難降的妖魔是什么塞蹭? 我笑而不...
    開封第一講書人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮讶坯,結(jié)果婚禮上番电,老公的妹妹穿的比我還像新娘。我一直安慰自己辆琅,他們只是感情好漱办,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著婉烟,像睡著了一般娩井。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上隅很,一...
    開封第一講書人閱讀 51,443評(píng)論 1 302
  • 那天撞牢,我揣著相機(jī)與錄音率碾,去河邊找鬼。 笑死屋彪,一個(gè)胖子當(dāng)著我的面吹牛所宰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播畜挥,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼仔粥,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了蟹但?” 一聲冷哼從身側(cè)響起躯泰,我...
    開封第一講書人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎华糖,沒想到半個(gè)月后麦向,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡客叉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年诵竭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片兼搏。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡卵慰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出佛呻,到底是詐尸還是另有隱情裳朋,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布吓著,位于F島的核電站鲤嫡,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏夜矗。R本人自食惡果不足惜泛范,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望紊撕。 院中可真熱鬧,春花似錦赡突、人聲如沸对扶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)浪南。三九已至,卻和暖如春漱受,著一層夾襖步出監(jiān)牢的瞬間络凿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留絮记,地道東北人摔踱。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像怨愤,于是被迫代替她去往敵國(guó)和親派敷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354