Vue 組件間通訊

vuejs

最近回顧前端,先是 React 現(xiàn)在因工作需又要開始 vue 了。開發(fā)過程中多半時(shí)間我們需要結(jié)構(gòu),有層次有上下級,有秩序。有了秩序也就是約束,有了約束也就是有了規(guī)則。從而減少我們思考時(shí)間。因?yàn)辂湲?dāng)勞只是在 10 點(diǎn)半前提供早餐,我們就無需考慮在 10 點(diǎn)半后買到經(jīng)濟(jì)實(shí)惠的早餐。


mc 早餐

但有時(shí)候我們還需要打破秩序,逆流而上。做 web 開發(fā)有一段時(shí)間,最近遇到復(fù)雜業(yè)務(wù)還是有點(diǎn)摸不到頭腦,再加上時(shí)間緊任務(wù)重往往寫出繁瑣難懂 code。一直在想如何能夠輕松地開發(fā)出流暢 web。

其實(shí) web 應(yīng)用中,數(shù)據(jù)流是從服務(wù)端流出在流回到服務(wù)端,知道程序啟動(dòng)了這個(gè)數(shù)據(jù)就開始流動(dòng)。但是有的人會(huì)問,那么從服務(wù)端獲取列表數(shù)據(jù)展示,數(shù)據(jù)也沒有流回到服務(wù)端,這樣可以想象為原封不動(dòng)地流回到服務(wù)端。希望我們多一點(diǎn)想象。

我們應(yīng)用是界面是一顆 UI 樹,每一個(gè)節(jié)點(diǎn)可能是原生 DOM 或是自定義 component ,component 也是 DOM 組成。樹接口是非線性的,但是也是有層次的。我們控制數(shù)據(jù)在這棵樹上流動(dòng)。數(shù)據(jù)讓我們應(yīng)用之樹變得絢麗多彩,數(shù)據(jù)是 UI 樹的血液,數(shù)據(jù)讓 UI 樹有了生命力。

我們將樹進(jìn)行劃分區(qū)域來控制數(shù)據(jù),我們控制數(shù)據(jù)流動(dòng)范圍,控制數(shù)據(jù)流動(dòng)方向。

數(shù)據(jù)多數(shù)流三種方式,框架都應(yīng)該給出這種三種流動(dòng)方式給出答案

  • 從父級向子級傳遞數(shù)據(jù)
  • 從子級向父級傳遞數(shù)據(jù)
  • 跨越多重級別傳遞數(shù)據(jù)

從父組件向子組件傳遞數(shù)據(jù)(props)

<template>
    <div>
        <div class="text-4xl text-white bg-blue-200">{{title}}</div>
    </div>
</template>
  • 在子組件中定義 props 可以接受從父級傳過來變量
  • 父組件
<template>
    <div >
        <Title class="text-lg" title="user list"/>
        <div class="" v-for="user in users" :key="user.id">
            <User message="hello" v-bind:user="user"/>
        </div>
    </div>
</template>
  • 父級調(diào)用子組件(User) 可以通過屬性 message 傳遞字符串 hello 給子組件,這種方式我們只能傳遞字符串。如果傳遞 data 中一個(gè)對象 user 這種方式是無法接受到 user 而是接受到 ”user“ 的字符串。這時(shí)候我們就需要用到動(dòng)態(tài)綁定。

動(dòng)態(tài)綁定

  • 下面示例是一個(gè)在父級獲取用戶列表然后將列表中 User 對象傳遞給 User 組件顯示出來用戶信息。
父組件
<template>
    <div >
        <div class="" v-for="user in users" :key="user.id">
            <User message="hello" v-bind:user="user"/>
        </div>
    </div>
</template>

<script>
import axios from "axios";
import User from "../components/User.vue";
export default {
  name: "Users",
  components: {
    User
  },
  data: () => {
    return {
      users: []
    };
  },
  created() {
    axios.get("https://jsonplaceholder.typicode.com/users").then(response => {
      console.log(response.data);
      this.users = response.data;
    });
  }
};
</script>

<style>
</style>

  • v-bind:user 這種方式可以將 user 對象傳遞給子組件 User
子組件
<template>
    <div>
        <p>{{user.name}}</p>
        <p>{{user.email}}</p>
    </div>
</template>

<script>
export default {
  name: "User",
  props: ["user", "message"],
  data: () => {
    return {};
  }
};
</script>

<style>
</style>

我們可以為 prop 定義類型,定義了類型也就是約束少了一些選擇,選擇少了我們就更明確我們能夠得到什么 string 類型必填的 title 的屬性。

export default {
  name: "Title",
  props: {
    title: {
      type: String,
      required: true
    }
  }
};

從子組件向父組件傳遞數(shù)據(jù)(事件)

父組件

這個(gè)實(shí)例是這樣的,一個(gè)課程列表,列表中每個(gè)課程都有一個(gè)等級,通過 rating 屬性來表示為 1 - 5 。我們選擇了一個(gè)課程,這是現(xiàn)實(shí)該課程的等級,等級信息是從父級組件 Tuts
傳遞給 Rating 子組件,不過在子組件如果修改了 Rating 反過來也會(huì)修改父級組件中的該對象的 Rating 的值,也就是(從子組件向父組件傳遞數(shù)據(jù))

<template>
    <div class="flex flex-row justify-center align-center">
        <div class="flex flex-col">
            <div class="mr-12" v-for="tut in tuts" :key="tut.id" @click="setSelectedTut(tut)">
            <div >{{tut.name}}({{tut.rating}})</div>
         </div>
        </div>
        <Rating v-if="selectedTut" :selectedTutRating="selectedTut.rating" v-on:ratingUpdated="changeDisplayRating"/>
    </div>
</template>

<script>
const tutList = [
  { id: 0, name: "angularjs", rating: 3 },
  { id: 1, name: "react", rating: 1 },
  { id: 2, name: "vue", rating: 5 }
];
import Rating from "../components/Rating.vue";
export default {
  name: "tuts",
  data() {
    return {
      tuts: [],
      selectedTut: null
    };
  },
  mounted() {
    this.tuts = this.getTuts();
  },
  methods: {
    setSelectedTut(tut) {
      this.selectedTut = tut;
    },
    changeDisplayRating(val) {
      this.tuts[this.selectedTut.id].rating = val;
    },
    getTuts() {
      return [...tutList];
    }
  },
  components: {
    Rating
  }
};
</script>

<style>
</style>

  • 先來看父組件如何向子組件傳遞數(shù)據(jù),數(shù)據(jù)中有兩個(gè)數(shù)據(jù) tuts 課程列表和 selectedTut 表示選中的課程,在 mouted 階段獲取 tuts 數(shù)據(jù),如果沒有選擇任何課程,selectedTut 默認(rèn)為空,通過 v-if 控制 Rating 子組件顯示,沒有選擇也就意味不會(huì)顯示 Rating。如果有選擇,這回通過 :selectedTutRating 將課程的等級數(shù)據(jù)傳遞給子組件 Rating 進(jìn)行顯示。
  • 在 setSelectedTut 這個(gè)方法在選擇課程后會(huì)把選擇課程設(shè)置為 selectedTut。
子組件代碼
<template>
    <div class="inline-block md:inline-flex">
        <form action="">
            <div><input type="radio" value="1" id="oneStarts" v-model="tutRating"><label for="oneStarts">1</label></div>
            <div><input type="radio" value="2" id="twoStarts" v-model="tutRating"><label for="twoStarts">2</label></div>
            <div><input type="radio" value="3" id="threeStarts" v-model="tutRating"><label for="threeStarts">3</label></div>
            <div><input type="radio" value="4" id="fourStarts" v-model="tutRating"><label for="fourStarts">4</label></div>
            <div><input type="radio" value="5" id="fiveStarts" v-model="tutRating"><label for="fiveStarts">5</label></div>
        </form>
    </div>
</template>

<script>
export default {
  data() {
    return {
      tutRating: null
    };
  },
  props: {
    selectedTutRating: {
      type: Number,
      required: false
    }
  },
  mounted() {
    this.tutRating = this.selectedTutRating;
  },
  methods: {
    clearRating() {
      this.tutRating = null;
    }
  },
  watch: {
    tutRating: function(newRating, oldRating) {
      let success = true;
      if (success) {
        this.$emit("ratingUpdated", newRating);
      }
    },
    selectedTutRating: function(newRating, oldRating) {
      this.tutRating = newRating;
    }
  }
};
</script>

<style>
</style>
  • 在子組件中關(guān)鍵是用了 watch 監(jiān)控 tutRating 和 selectTutRating 進(jìn)行控制,當(dāng)我們在 Rating 進(jìn)行選擇就是通過 tutRating 方法中 $emit 發(fā)送給用戶新選擇的等級給父組件的
    v-on:ratingUpdated="changeDisplayRating" 父組件是通過監(jiān)聽ratingUpdated 來從子組件中獲取等級數(shù)據(jù)來實(shí)現(xiàn)從子組件到父組件傳遞數(shù)據(jù)的。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 通過路由帶參數(shù)進(jìn)行傳值 兩個(gè)組件 A和B,A組件通過query把orderId傳遞給B組件(觸發(fā)事件可以是點(diǎn)擊事件...
    接著奏樂接著舞S閱讀 523評論 0 2
  • 總結(jié)起來三種方式 一、eventbus bus.js component1.vue component2.vue ...
    阿啦啦啦啦啦閱讀 240評論 0 0
  • 什么是組件? 組件 (Component) 是 Vue.js 最強(qiáng)大的功能之一。組件可以擴(kuò)展 HTML 元素,封裝...
    youins閱讀 9,708評論 0 13
  • 此文基于官方文檔,里面部分例子有改動(dòng),加上了一些自己的理解 什么是組件? 組件(Component)是 Vue.j...
    陸志均閱讀 3,954評論 5 14
  • 組件(Component)是Vue.js最核心的功能,也是整個(gè)架構(gòu)設(shè)計(jì)最精彩的地方,當(dāng)然也是最難掌握的。...
    六個(gè)周閱讀 5,781評論 0 32

友情鏈接更多精彩內(nèi)容