Vue3組件化(一):父子組件的通信

本文整理來自深入Vue3+TypeScript技術(shù)棧-coderwhy大神新課,只作為個人筆記記錄使用,請大家多支持王紅元老師阀湿。

認(rèn)識組件的嵌套

前面我們是將所有的邏輯放到一個App.vue組件中池磁,如果我們將所有的代碼邏輯都放到一個App.vue組件中,我們會發(fā)現(xiàn)清女,代碼是非常的臃腫和難以維護的。并且在真實開發(fā)中,我們會有更多的內(nèi)容和代碼邏輯结澄,對于擴展性和可維護性來說都是非常差的。所以岸夯,在真實開發(fā)中麻献,我們會對組件進行拆分,拆分成一個個功能的小組件猜扮,再將這些組件組合嵌套在一起勉吻,最終形成我們的應(yīng)用程序。

組件的拆分

原來的代碼:

我們可以按照如下的方式進行拆分:

按照如上的拆分方式后破镰,我們開發(fā)對應(yīng)的邏輯只需要去對應(yīng)的組件編寫就可餐曼。

推薦插件

Vue代碼高亮的插件:Vetur压储、Volar。
代碼片段插件:Vue VSCode Snippets源譬、Vue3 Snippets集惋。

對于組件的導(dǎo)入,不加后綴名也不會報錯踩娘,因為VueCLI是基于webpack的刮刑,而webpack又有resolve.extensions用來解析擴展名,Vue已經(jīng)內(nèi)置在extensions里面添加了.vue养渴,所以不寫.vue后綴名也可以雷绢。

但是最好帶上后綴名,比如:import Header from './Header.vue';理卑,如果不帶有兩個問題:

  1. 使用組件的時候沒有提示
  2. 點擊路徑不會跳轉(zhuǎn)到對應(yīng)組件代碼

如果加上.vue后綴就沒有上面兩個問題了翘紊。

Vue3的scoped偶爾失效的問題

vue2中我們給樣式添加scoped就會避免樣式被污染的問題,這是因為標(biāo)簽上被添加上了一個屬性藐唠,設(shè)置樣式的時候用了屬性選擇器帆疟,有這個屬性才會設(shè)置此樣式。

但是vue3中經(jīng)常會出現(xiàn)樣式污染的問題宇立,因為vue2中組件都有根元素踪宠,但是vue3中可以沒有根元素,沒有根元素的時候就會出現(xiàn)這個bug妈嘹。因為沒有根元素柳琢,上個組件的屬性會穿透到下個組件,所以他們就有重復(fù)的屬性了润脸,樣式就會被污染柬脸,如下:

所以,Vue3組件也要有個根元素毙驯。

組件的通信

上面的嵌套邏輯如下肖粮,它們存在如下關(guān)系:
App組件是Header、Main尔苦、Footer組件的父組件涩馆;
Main組件是Banner、ProductList組件的父組件允坚;

在開發(fā)過程中魂那,我們會經(jīng)常遇到需要組件之間相互進行通信。比如App可能使用了多個Header稠项,每個地方的Header展示的內(nèi)容不同涯雅,那么我們就需要使用者傳遞給Header一些數(shù)據(jù),讓其進行展示展运。又比如我們在Main中一次性請求了Banner數(shù)據(jù)和ProductList數(shù)據(jù)活逆,那么就需要傳遞給它們來進行展示精刷。也可能是子組件中發(fā)生了事件,需要由父組件來完成某些操作蔗候,那就需要子組件向父組件傳遞事件怒允。

總之,在一個Vue項目中锈遥,組件之間的通信是非常重要的環(huán)節(jié)纫事,所以接下來我們就具體學(xué)習(xí)一下組件之間是如何相互之間傳遞數(shù)據(jù)的。

父子組件之間通信的方式

父子組件之間如何進行通信呢所灸?

  • 父組件傳遞給子組件:通過props屬性丽惶;
  • 子組件傳遞給父組件:通過$emit觸發(fā)事件;

父組件給子組件傳遞數(shù)據(jù)

在開發(fā)中很常見的就是父子組件之間通信爬立,比如父組件有一些數(shù)據(jù)钾唬,需要子組件來進行展示,這個時候我們可以通過props來完成組件之間的通信侠驯。

什么是Props呢知纷?
Props是你可以在組件上注冊一些自定義的attribute,父組件給這些attribute賦值陵霉,子組件通過attribute的名稱獲取到對應(yīng)的值。

Props有兩種常見的用法:
方式一:字符串?dāng)?shù)組伍绳,數(shù)組中的字符串就是attribute的名稱踊挠;
方式二:對象類型,對象類型我們可以在指定attribute名稱的同時冲杀,指定它需要傳遞的類型效床、是否是必須的、默認(rèn)值等等权谁;

Props的數(shù)組用法

上面是傳遞寫死的值剩檀,如果傳遞data里面的值就需要進行綁定:

//直接綁定
<show-message :title="title" :content="content"></show-message>
//綁定對象的屬性
<show-message :title="message.title" :content="message.content"></show-message>
//綁定對象,就會把對象的所有屬性綁定到組件上旺芽,這種寫法和上一行效果一樣
<show-message v-bind="message"></show-message>

//數(shù)據(jù)
data() {
  return {
    title: "嘻嘻嘻",
    content: "我是嘻嘻嘻嘻",
    message: {
      title: "嘿嘿嘿",
      content: "我是嘿嘿嘿"
    }
  }
}

Props的對象用法

數(shù)組用法中我們只能說明傳入的attribute的名稱沪猴,并不能對其進行任何形式的限制,接下來我們來看一下對象的寫法是如何讓我們的props變得更加完善的采章,真實開發(fā)中我們就使用對象用法运嗜。

當(dāng)使用對象語法的時候,我們可以對傳入的內(nèi)容限制更多:

  • 比如指定傳入的attribute的類型悯舟;
  • 比如指定傳入的attribute是否是必傳的担租;
  • 比如指定沒有傳入?yún)?shù)時,attribute的默認(rèn)值抵怎;

那么type的類型都可以是哪些呢奋救?

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol

Props對象語法補充

如果有多個可能的類型岭参,按如下寫法:

props: {
  //可能是String也可能是Number
  IDNumber: [String, Number]
}
  • 對象或數(shù)組的默認(rèn)值必須從一個工廠函數(shù)中獲取。這是因為組件是復(fù)用的尝艘,如果默認(rèn)傳遞一個對象演侯,那么這個對象(引用類型)也會被其他組件引用,所以我們傳遞一個函數(shù)利耍,返回一個對象蚌本。
  • 我們也可以自定義驗證函數(shù),保證傳遞的值是我們指定的值隘梨。

Prop的大小寫命名

  • 如果是瀏覽器解析程癌,因為HTML 中的 attribute 名是大小寫不敏感的,所以下面camelCase (駝峰命名)方式的的messageInfo會被解析成messageinfo轴猎,就會有問題嵌莉,所以我們可以換成等價的kebab-case (短橫線分隔命名) 寫法。
  • 但是在.vue文件中捻脖,template是給vue-loader解析的锐峭,vue-loader解析的就不會有問題,所以在.vue文件中可婶,兩種寫法都可以沿癞,但是官方還是推薦kebab-case (短橫線分隔命名)。

非Prop的Attribute

什么是非Prop的Attribute呢矛渴?
當(dāng)我們傳遞給一個組件某個屬性椎扬,但是該屬性并沒有定義對應(yīng)的props或者emits時,就稱之為非Prop的Attribute具温,常見的包括class蚕涤、style、id屬性等铣猩。

Attribute繼承:當(dāng)組件有單個根節(jié)點時揖铜,非Prop的Attribute將自動添加到組件的根節(jié)點的Attribute中。想想也很容易理解达皿,因為給組件添加屬性沒啥意義啊天吓,所以只要組件有單個根節(jié)點就會把屬性添加到單個根節(jié)點上。

如果我們不希望組件的根節(jié)點繼承attribute峦椰,可以在組件中設(shè)置 inheritAttrs: false失仁。禁用attribute繼承的常見情況是需要將attribute應(yīng)用于根元素之外的其他元素。比如下面我們不想將class屬性添加到div上们何,可以在組件中設(shè)置inheritAttrs: false萄焦,然后通過$attrs來訪問所有的非props的attribute,然后再設(shè)置到h2上就行了。

當(dāng)非props的attribute比較多的時候拂封,我們也可以直接綁定對象:

<div>
  我是NotPropAttribute組件
  <h2 v-bind="$attrs"></h2>
</div>

多個根節(jié)點的attribute如果沒有顯示的綁定茬射,那么會報警告,我們必須手動的指定要綁定到哪一個屬性上:

子組件給父組件傳遞數(shù)據(jù)

什么情況下子組件需要傳遞內(nèi)容到父組件呢冒签?
當(dāng)子組件有一些事件發(fā)生的時候在抛,比如在組件中發(fā)生了點擊,父組件需要切換內(nèi)容萧恕;
子組件有一些內(nèi)容想要傳遞給父組件的時候刚梭;

我們?nèi)绾瓮瓿缮厦娴牟僮髂兀?br> 首先,我們需要在子組件中定義好在某些情況下觸發(fā)的事件名稱票唆,其次朴读,在父組件中以v-on的方式傳入要監(jiān)聽的事件名稱,并且綁定到對應(yīng)的方法中走趋,最后衅金,在子組件中發(fā)生某個事件的時候,根據(jù)事件名稱觸發(fā)對應(yīng)的事件簿煌。

傳遞流程

我們封裝一個CounterOperation.vue的組件氮唯,內(nèi)部其實是監(jiān)聽兩個按鈕的點擊,點擊之后通過this.$emit的方式發(fā)出去事件姨伟。

子組件通過$emit觸發(fā)事件惩琉,并且通過emits指明我們都有哪些觸發(fā)事件。

父組件通過v-on監(jiān)聽事件:

上面代碼和vue2比夺荒,其實就是多了emits: ["add", "sub", "addN"]瞒渠。

傳遞參數(shù)和驗證

自定義事件的時候,我們也可以傳遞一些參數(shù)給父組件:

在vue3中般堆,emits除了是數(shù)組,還可以是個對象诚啃,對象寫法的目的是為了進行參數(shù)的驗證淮摔。實際開發(fā)中,emits一般我們都是使用數(shù)組始赎。

// emits: ["add", "sub", "addN"],
// 對象寫法的目的是為了進行參數(shù)的驗證
emits: {
  add: null, //不需要驗證
  sub: null,
  addN: (num, name, age) => {
    console.log(num, name, age);
    if (num > 10) {
      return true
    }
    return false; //如果驗證不通過和橙,參數(shù)還是可以傳過去,只不過會報警告
  }
}

組件間通信案例練習(xí)

我們來做一個相對綜合的練習(xí):父組件給子組件傳遞標(biāo)題數(shù)據(jù)造垛,點擊子組件通知父組件切換到相應(yīng)頁面魔招。

父組件App.vue代碼:

<template>
  <div>
    <tab-control :titles="titles" @titleClick="titleClick"></tab-control>
    <h2>{{contents[currentIndex]}}</h2>
  </div>
</template>

<script>
  import TabControl from './TabControl.vue';

  export default {
    components: {
      TabControl
    },
    data() {
      return {
        titles: ["衣服", "鞋子", "褲子"],
        contents: ["衣服頁面", "鞋子頁面", "褲子頁面"],
        currentIndex: 0
      }
    },
    methods: {
      titleClick(index) {
        this.currentIndex = index;
      }
    }
  }
</script>

<style scoped>

</style>

子組件TabControl.vue代碼:

<template>
  <div class="tab-control">
    <div class="tab-control-item" 
         :class="{active: currentIndex === index}"
         v-for="(title, index) in titles" 
         :key="title"
         @click="itemClick(index)">
      <!-- span里面放標(biāo)題, 設(shè)置下面的紅色橫線 -->
      <span>{{title}}</span>
    </div>
  </div>
</template>

<script>
  export default {
    emits: ["titleClick"],
    props: {
      titles: {
        type: Array,
        default() {
          return []
        }
      }
    },
    data() {
      return {
        currentIndex: 0
      }
    },
    methods: {
      itemClick(index) {
        this.currentIndex = index;
        this.$emit("titleClick", index);
      }
    }
  }
</script>

<style scoped>
  .tab-control {
    display: flex;
  }

  .tab-control-item {
    flex: 1;
    text-align: center;
  }

  .tab-control-item.active {
    color: red;
  }

  .tab-control-item.active span {
    border-bottom: 3px solid red;
    padding: 5px 10px;
  }
</style>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市五辽,隨后出現(xiàn)的幾起案子办斑,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乡翅,死亡現(xiàn)場離奇詭異鳞疲,居然都是意外死亡,警方通過查閱死者的電腦和手機蠕蚜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門尚洽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人靶累,你說我怎么就攤上這事腺毫。” “怎么了挣柬?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵潮酒,是天一觀的道長。 經(jīng)常有香客問我凛忿,道長澈灼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任店溢,我火速辦了婚禮叁熔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘床牧。我一直安慰自己荣回,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布戈咳。 她就那樣靜靜地躺著心软,像睡著了一般。 火紅的嫁衣襯著肌膚如雪著蛙。 梳的紋絲不亂的頭發(fā)上删铃,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天,我揣著相機與錄音踏堡,去河邊找鬼猎唁。 笑死,一個胖子當(dāng)著我的面吹牛顷蟆,可吹牛的內(nèi)容都是我干的诫隅。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼帐偎,長吁一口氣:“原來是場噩夢啊……” “哼逐纬!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起削樊,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤豁生,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體沛硅,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡眼刃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了摇肌。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片擂红。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖围小,靈堂內(nèi)的尸體忽然破棺而出昵骤,到底是詐尸還是另有隱情,我是刑警寧澤肯适,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布变秦,位于F島的核電站,受9級特大地震影響框舔,放射性物質(zhì)發(fā)生泄漏蹦玫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一刘绣、第九天 我趴在偏房一處隱蔽的房頂上張望樱溉。 院中可真熱鬧,春花似錦纬凤、人聲如沸福贞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽挖帘。三九已至,卻和暖如春恋技,著一層夾襖步出監(jiān)牢的瞬間拇舀,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工蜻底, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留骄崩,地道東北人。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓朱躺,卻偏偏與公主長得像刁赖,于是被迫代替她去往敵國和親搁痛。 傳聞我的和親對象是個殘疾皇子长搀,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,514評論 2 348

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