09Vue.js快速入門(mén)-Vue入門(mén)之Vuex實(shí)戰(zhàn)

9.1. 引言

Vue組件化做的確實(shí)非常徹底篱蝇,它獨(dú)有的vue單文件組件也是做的非常有特色。組件化的同時(shí)帶來(lái)的是:組件之間的數(shù)據(jù)共享和通信的難題徽曲。 尤其Vue組件設(shè)計(jì)的就是零截,父組件通過(guò)子組件的prop進(jìn)行傳遞數(shù)據(jù),而且數(shù)據(jù)傳遞是單向的秃臣。也就是說(shuō):父組件可以把數(shù)據(jù)傳遞給子組件涧衙,但是 反之則不同。如下圖所示:

vue父子傳遞

9.2. 單向數(shù)據(jù)流動(dòng)

單方向的數(shù)據(jù)流動(dòng)帶來(lái)了非常簡(jiǎn)潔和清晰的數(shù)據(jù)流奥此,純展示性或者獨(dú)立性較強(qiáng)的模塊的開(kāi)發(fā)確實(shí)非常方便和省事弧哎。 但是復(fù)雜的頁(yè)面邏輯,組件之間的數(shù)據(jù)共享處理就會(huì)需要通過(guò)事件總線的方式解決或者使用Vue的Vuex框架了稚虎。

9.3. 子組件通知父組件數(shù)據(jù)更新:事件方式的實(shí)現(xiàn)

子組件可以在子組件內(nèi)觸發(fā)事件撤嫩,然后在父容器中添加子組件時(shí)綁定父容器的方法為事件響應(yīng)方法的方式.如下圖所示:

vue父子傳遞
  • 使用 v-on 綁定自定義事件
每個(gè) Vue 實(shí)例都實(shí)現(xiàn)了事件接口(Events interface),即:
使用 $on(eventName) 監(jiān)聽(tīng)事件
使用 $emit(eventName) 觸發(fā)事件

參考代碼案例:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Vue入門(mén)之event message</title>
  <!-- 新 Bootstrap 核心 CSS 文件 -->
  <link rel="stylesheet" >

  <!-- 可選的Bootstrap主題文件(一般不用引入) -->
  <link rel="stylesheet" >

  <!-- jQuery文件蠢终。務(wù)必在bootstrap.min.js 之前引入 -->
  <script src="http://cdn.bootcss.com/jquery/1.11.1/jquery.min.js"></script>

  <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
  <script src="http://cdn.bootcss.com/bootstrap/3.3.0/js/bootstrap.min.js"></script>

  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
</head>

<body>
  <div id="app">
    <p>推薦次數(shù):{{ voteCount }}</p>
    <hr>
    <!--綁定兩個(gè)自定義事件序攘,當(dāng)組件內(nèi)部觸發(fā)了事件后,會(huì)自定調(diào)用父容器綁定的methods的方法寻拂,達(dá)到了子容器向父容器數(shù)據(jù)進(jìn)行通信同步的方法-->
    <vote-btn v-on:vote="voteAction" v-on:sendmsg="sendMsgAction"></vote-btn>
    <hr>
    <ul class="list-group">
      <li v-for="o in msg" class="list-group-item">{{o}}</li>
    </ul>
  </div>
  <script>
    Vue.component('vote-btn', {
      template: `
        <div>
          <button class="btn btn-success" v-on:click="voteArticle">推薦</button>
          <hr/>
          <input type="text" v-model="txtMsg" />
          <button v-on:click="sendMsg" class="btn btn-success">發(fā)送消息</button>
        </div>
      `,
      data: function () {
        return {
          txtMsg: ""
        }
      },
      methods: {
        voteArticle: function () {
          // 觸發(fā)事件程奠,vote
          this.$emit('vote')
        },
        sendMsg: function () {
          // 觸發(fā)事件,sendmsg祭钉,并
          this.$emit('sendmsg', this.txtMsg)
        }
      }
    })

    var app = new Vue({
      el: '#app',
      data: {
        voteCount: 0,
        msg: []
      },
      methods: {
        voteAction: function() {  // 事件觸發(fā)后瞄沙,會(huì)直接執(zhí)行此方法
          this.voteCount += 1
        },
        sendMsgAction: function (item) {
          this.msg.push(item)
        }
      }
    });
  </script>
</body>

</html>

9.4. 事件總線方式解決非父子組件數(shù)據(jù)同步

如果非父子組件怎么通過(guò)事件進(jìn)行同步數(shù)據(jù),或者同步消息呢朴皆?Vue中的事件觸發(fā)和監(jiān)聽(tīng)都是跟一個(gè)具體的Vue實(shí)例掛鉤帕识。 所以在不同的Vue實(shí)例中想進(jìn)行事件的統(tǒng)一跟蹤和觸發(fā),那就需要一個(gè)公共的Vue實(shí)例遂铡,這個(gè)實(shí)例就是公共的事件對(duì)象肮疗。

image

參考下面做的一個(gè)購(gòu)物車(chē)的案例的代碼:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Vue入門(mén)之event message</title>
  <!-- 新 Bootstrap 核心 CSS 文件 -->
  <link rel="stylesheet" >

  <!-- 可選的Bootstrap主題文件(一般不用引入) -->
  <link rel="stylesheet" >

  <!-- jQuery文件。務(wù)必在bootstrap.min.js 之前引入 -->
  <script src="http://cdn.bootcss.com/jquery/1.11.1/jquery.min.js"></script>

  <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
  <script src="http://cdn.bootcss.com/bootstrap/3.3.0/js/bootstrap.min.js"></script>

  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
</head>

<body>
  <div id="app">
    <product-list :products="products" v-on:addpro="addToCarts"> </product-list>
    <hr>  
    <cart :cart-products="carts"> </cart>
  </div>
  <script>
    var eventBus = new Vue()

    Vue.component('cart', {
      template: `
      <table class="table table-borderd table-striped table-hover">
      <thead>
        <tr>
          <th>商品編號(hào)</th>
          <th>商品名</th>
          <th>數(shù)量</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="item in cartProducts">

          <td>{{ item.id }}</td>
          <td>{{ item.name }}</td>
          <td>
            {{ item.count }}
          </td>
          <td>
            <button type="button" @click="removeCarts(item)" class="btn btn-success"><i class="glyphicon glyphicon-remove"></i></button>
          </td>
        </tr>
      </tbody>
    </table>
      `,
      data: function () {
        return {
        }
      },
      methods: {
        removeCarts: function (item) {
          eventBus.$emit('remo', item)
        }
      },
      props: ['cartProducts']
    })

    Vue.component('product-list', {
      template: `
      <table class="table table-borderd table-striped table-hover">
      <thead>
        <tr>
          <th>商品編號(hào)</th>
          <th>商品名</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="item in products">
          <td>{{ item.id }}</td>
          <td>{{ item.name }}</td>
          <td>
            <button type="button" v-on:click="addToCarts(item)" class="btn btn-success"><i class="glyphicon glyphicon-shopping-cart"></i></button>
          </td>
        </tr>
      </tbody>
    </table>
      `,
      data: function () {
        return {
        }
      },
      methods: {
        addToCarts: function (item) {
          this.$emit('addpro', item)
        }
      },
      props: ['products'],

    })

    var app = new Vue({
      el: '#app',
      data: {
        products: [
          { id: '1', name: '鱷魚(yú)' },
          { id: '2', name: '蛇' },
          { id: '3', name: '兔子' },
          { id: '4', name: '驢' },
          { id: '5', name: '孔雀' }
        ],
        carts: []
      },
      methods: {
        addToCarts: function (item) {
          var isExist = false
          for(var i=0; i<this.carts.length; i++) {
            if( item.id === this.carts[i].id ) {
              item.count = this.carts[i].count + 1
              Vue.set(this.carts, i, item)
              isExist = true
            }
          }
          !isExist && (item.count = 1, this.carts.push(item))
        },
        removeCarts: function (item) {
          for(var i =0; i<this.carts.length; i++) {
            if( item.id === this.carts[i].id) {
              this.carts.splice(i,1)
            }
          }
        }
      },
      mounted: function () {
        self = this;
        eventBus.$on('remo', function (item) {
          self.removeCarts(item)
        })
      }
    });
  </script>
</body>

</html>

9.5. Vuex解決復(fù)雜單頁(yè)面應(yīng)用

上面的方式只能解決一些簡(jiǎn)單的頁(yè)面中的組件的通信問(wèn)題扒接,但是如果是復(fù)雜的單頁(yè)面應(yīng)用就需要使用更強(qiáng)大的Vuex來(lái)幫我們進(jìn)行狀態(tài)的統(tǒng)一管理和同步伪货。

當(dāng)?shù)谝淮谓佑|Vuex的時(shí)候,眼前一亮钾怔,之前經(jīng)過(guò)Redux之后碱呼,被它繁瑣的使用令我痛苦不已,雖然思路很清晰宗侦,其實(shí)完全可以設(shè)計(jì)的更簡(jiǎn)單和高效愚臀。 當(dāng)我接觸到Vuex之后,發(fā)現(xiàn)這就是我想要的矾利。的確簡(jiǎn)潔就是一種藝術(shù)姑裂。

其實(shí)本質(zhì)上馋袜,Vuex就是一個(gè)大的EventBus對(duì)象的升級(jí)版本,相當(dāng)于一個(gè)特定的倉(cāng)庫(kù)舶斧,所有數(shù)據(jù)都在統(tǒng)一的倉(cāng)庫(kù)中欣鳖,進(jìn)行統(tǒng)一的管理。

幾個(gè)核心的概念:

  • State: Vuex倉(cāng)庫(kù)中的數(shù)據(jù)茴厉。
  • Getter: 類(lèi)似于Vue實(shí)例中的計(jì)算屬性泽台,Getter就是普通的獲取state包裝函數(shù)。
  • Mutations: Vuex 的 store 中的狀態(tài)的唯一方法是提交 mutation矾缓。Vuex 中的 mutations 非常類(lèi)似于事件:每個(gè) mutation 都有一個(gè)字符串的 事件類(lèi)型 (type) 和 一個(gè) 回調(diào)函數(shù) (handler)怀酷。
  • Action: action可以觸發(fā)Mutations,不能直接改變state而账。

看下面一張圖了解一下Vuex整體的數(shù)據(jù)流動(dòng):

image

9.6. Vuex實(shí)例demo

可能前面的圖和概念都太多了胰坟,先看一個(gè)例子因篇,簡(jiǎn)單了解一下Vuex中的倉(cāng)庫(kù)的數(shù)據(jù) 怎么整合到 Vue的實(shí)例中去泞辐。

創(chuàng)建Vuexdemo的項(xiàng)目

# 通過(guò)vue-cli創(chuàng)建vuexdemo的項(xiàng)目,注意首先cd到你的存放項(xiàng)目代碼的目錄
vue init webpack vuexdemo

# 過(guò)程中竞滓,會(huì)有幾個(gè)選項(xiàng)你可以選擇輸入Y或者n來(lái)開(kāi)啟或者關(guān)閉某些選項(xiàng)咐吼。

# 創(chuàng)建完成后,就可以通過(guò)以下命令商佑,進(jìn)行初始化和安裝相關(guān)的依賴項(xiàng)了锯茄。
cd vuexdemo
npm install
npm run dev

# 然后安裝 vuex
npm i vuex -S


聯(lián)系老馬

對(duì)應(yīng)視頻地址:https://chuanke.baidu.com/s5508922.html
老馬qq: 515154084
老馬微信:請(qǐng)掃碼

微信:Flydragon_malun 或者18911865673
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市茶没,隨后出現(xiàn)的幾起案子肌幽,更是在濱河造成了極大的恐慌,老刑警劉巖抓半,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件喂急,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡笛求,警方通過(guò)查閱死者的電腦和手機(jī)廊移,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)探入,“玉大人狡孔,你說(shuō)我怎么就攤上這事》渌裕” “怎么了苗膝?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)植旧。 經(jīng)常有香客問(wèn)我辱揭,道長(zhǎng)芋类,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任界阁,我火速辦了婚禮侯繁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘泡躯。我一直安慰自己贮竟,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布较剃。 她就那樣靜靜地躺著咕别,像睡著了一般。 火紅的嫁衣襯著肌膚如雪写穴。 梳的紋絲不亂的頭發(fā)上惰拱,一...
    開(kāi)封第一講書(shū)人閱讀 49,760評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音啊送,去河邊找鬼偿短。 笑死,一個(gè)胖子當(dāng)著我的面吹牛馋没,可吹牛的內(nèi)容都是我干的昔逗。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼篷朵,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼勾怒!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起声旺,我...
    開(kāi)封第一講書(shū)人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤笔链,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后腮猖,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體鉴扫,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年缚够,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了幔妨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡谍椅,死狀恐怖误堡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情雏吭,我是刑警寧澤锁施,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響悉抵,放射性物質(zhì)發(fā)生泄漏肩狂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一姥饰、第九天 我趴在偏房一處隱蔽的房頂上張望傻谁。 院中可真熱鬧,春花似錦列粪、人聲如沸审磁。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)态蒂。三九已至,卻和暖如春费什,著一層夾襖步出監(jiān)牢的瞬間钾恢,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工鸳址, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瘩蚪,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓氯质,卻偏偏與公主長(zhǎng)得像募舟,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子闻察,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容