1. 程式人生 > 程式設計 >解決父子元件通訊的三種Vue插槽

解決父子元件通訊的三種Vue插槽

目錄
  • 前言
  • 環境準備
    • Category元件
    • App元件
  • 一、預設插槽
    • 二、具名插槽
      • 三、作用域插槽
        • 總結

          前言

          插槽可以說是 中非常重要的一部分吧,在我學習和練習的過程中,當元件搭配著插槽一起使用的時候,會發揮的更好一些。更多時候也會更加方便。

          今天介紹Vue中三種插槽吧:預設插槽、具名插槽、作用域插槽。

          環境準備

          先搭個初始環境給大家看看哈。一步一步講完這個插槽。

          就是寫了一個類別元件,分別渲染這三種資料。

          image-20211120150949138

          Category元件

          <template>
            <div class="category">
              <h1>{{title}}</h1>
              <ul>
                <li 
                v-for="(item,index) in listData"
                :key="index">{{item}}</li>
              </ul>
            </div>
          </template>
          <script>
          export default {
            props: {
              listData:Array,title: String
            }
          }
          </script>
          <style scoped>
          .category{
            width: 200px;
            height: 300px;
            background-color:pink;
          }
          </style>

          App元件

          <template>
            <div id="app">
              <Category :listData="games" :title="'Games'" />
              <Category :listData="movies" :title="'Movies'" />
              <Category :listData="foods" :title="'Foods'" />
            </div>
          </template>
          <script>
          import Category from './components/Category.vue'
          export default {
            name: 'App',components: {
              Category
            },data () {
              return {
                games:['穿越火線','qq飛車','洛克王國'],movies:['你好,李煥英','青春派','匆匆那年'],foods:['邵陽米粉','長沙茶顏','重慶火鍋']
              }
            }
          }
          </script>
          <style>
          #app {
            font-family: Avenir,Helvetica,Arial,sans-serif;
            -webkit-font-smoothing: antialiased;
            -moz-osx-font-smoothing: grayscale;
            text-align: center;
            color: #2c3e50;
            margin-top: 60px;
            display: flex;
            justify-content: space-between;
          }
          </style>

          最開始就是如上圖一樣的需求,但是現在業務需求更改了,電影變成了只宣傳其中一個,其他的不進行宣傳,吃的也變成只宣傳一個拉。

          如下圖:

          image-20211120151432264

          我們怎麼改合適呢?

          是在Category元件中加if一個個進行判斷嗎?還是有更好的方法勒???

          一個個判斷是不行的,那樣子程式碼會變得十分繁雜,不易閱讀,萬一以後又要更改業務需求,程式碼都不好動。

          接下來就到預設插槽的出現拉。

          一、預設插槽

          我們在子元件中不用再用props 接收資料,也不做渲染,而是定義一個插槽。

          <template>
          <div class="category">
              <!-- 定義插槽,插槽預設內容 -->
              <slot>如果當父元件不傳值過來,即顯示此預設</slot>
              </div>
          </template>
          <script>
              export default {
                  props: {
                  }
              }
          </script>

          App元件也作出更改

          <template>
          <div id="app">
              <Category>
                  <h1>Games</h1>
                  <!-- <ul>
          <li v-for="(item,index) in games" :key="index">{{ item }}</li>
              </ul> -->
                  <img src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fi0.hdslb.com%2Fbfs%2Farticle%2Fb352264fa7bfdb6d211f2e71e87cc2c48d85b805.jpg&refer=http%3A%2F%2Fi0.hdslb.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639931135&t=0b2c6c622c84a1e387196cce8f50455e">
              </Category>
              
              <Category>
                  <h1>Movies</h1>
                  <img class="movies" src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Finews.gtimg.com%2Fnewsapp_bt%2F0%2F13236694597%2F641.jpg&refer=http%3A%2F%2Finews.gtimg.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639931502&t=f89c2197bda9bb129d9404d3c4b30f2f">
                  <!-- <ul> -->
                  <!-- <li v-for="(item,index) in movies" :key="index">{{ item }}</li> -->
                  <!-- </ul> -->
              </Category>
              <Category>
                  <h1>Foods</h1>
                  <ul>
                      <li v-for="(item,index) in foods" :key="index">{{ item }}</li>
              </ul>
              </Category>
              
              <!-- 當我們什麼都沒有寫的時候,看展示什麼 -->
              <Category>
              </Category>
              </div>
          </template>
           
          <script>
              import Category from './components/Category.vue'
           
              export default {
                  name: 'App',components: {
                      Category
                  },data () {
                      return {
                          games:['穿越火線','重慶火鍋']
                      }
                  }
              }
          </script>

          顯示效果:

          image-20211120152024922

          解釋:

          我們在子元件寫了一個<slot>如果當父元件不傳值過來,即顯示此預設</slot> 標籤,此處就相當於佔了一個位置。

          我們在父元件中,也不再像之前一樣<Category/>寫自閉和標籤,而是寫了非自閉和標籤<Category> 內容 </Category>。這樣做,Vue就會預設的將寫在元件標籤中的內容渲染完,然後再放回子元件中的 <slot></slot> 佔好位置的地方去。

          注意:樣式寫在父元件或者子元件中都是可以的,因為它是渲染完後才放回子元件中的。寫在子元件中,就是在放回子元件中時渲染。

          寫完這裡,客戶突然覺得你們這麼厲害,不滿足啦,又開始給你們整么蛾子。

          image-20211120152906020

          接下來就又到具名插槽登場啦哈。

          二、具名插槽

          竟然我們能夠想到用一個插槽啦,那麼為什麼不能想著用兩個插槽來試一試勒?

          改造子元件

          <template>
            <div class="category">
              <!-- 必須加上名稱 在父元件中才能指定要放入那個插槽 這也是為什麼叫做具名插槽的原因--->
              <slot name="slot1">如果當父元件不傳值過來,即顯示此預設</slot>
              <slot name="slot2"></slot>
            </div>
          </template>
          <script>
          export default {
            props: {
            }
          }
          </script>

          父元件

          <template>
          	<div id="app">
              	<Category>
                 	 <template slot="slot1">
                    	  <h1>Games</h1>
                      <img src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fi0.hdslb.com%2Fbfs%2Farticle%2Fb352264fa7bfdb6d211f2e71e87cc2c48d85b805.jpg&refer=http%3A%2F%2Fi0.hdslb.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639931135&t=0b2c6c622c84a1e387196cce8f50455e"
                           />
          	</template>
          	<template slot="slot2">
          		<button > qq登入</button>
          		&www.cppcns.comlt;button > 微信登入</button>
          	</template>
           
          </Category>
          <Category>
              <template slot="slot1">
          		<h1>Movies</h1>
          			<img
               class="movies"
               src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Finews.gtimg.com%2Fnewsapp_bt%2F0%2F13236694597%2F641.jpg&refer=http%3A%2F%2Finews.gtimg.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639931502&t=f89c2197bda9bb129d9404d3c4b30f2f"
               />
              </template>
              <template slot="slot2">
          		<button > 點選購票</button>
              </template>
          </Category>
           
          <Category>
              <template slot="slot1">
          		<h1>Foods</h1>
          		<ul>
              		<li v-for="(item,index) in foods" :key="index">{{ item }}</li>
                  </ul>
              </template>
          </Category>
           
          <!-- 當我們什麼都沒有寫的時候,看展示什麼 -->
          <Category> </Category>
          </div>
          </template>
           
          <script>
              import Category from './components/Category.vue'
           
              export default {
                  name: 'App',data () {
                      return {
                          games:['穿越火線','重慶火鍋']
                      }
                  }
              }
          </script>

          效果展示

          image-20211120153500451

          解釋:

          我們可以在元件中放多個slot,但是多個的時候必須要給他們命名,另外父元件中也要進行指定,這樣才不會放不進去。

          三、作用域插槽

          作用域插槽和前面稍稍有點不同,之前都是資料在父元件中,而作用域插槽是資料在子元件中,反過來傳遞給父元件,讓父元件定義結構進行渲染。

          改造的子元件

          <template>
            <div class="category">
              <slot name="slot1">如果當父元件不傳值過來,即顯示此預設</slot>
              <slot name="slot2" :foods="foods">如果當父元件不傳值過來,即顯示此預設</slot>
            </div>
          </template>
          <script>
          export default {
            data () {
              return{
                foods:['邵陽米粉','重慶火鍋']
              }
            }
          }
          </script>

          父元件

          <template>
            <div id="app">
              <Category>
                <template slot="slot1">
                  <h1>Foods</h1>
                </template>
                <template slot="slot2" scope="listData">
                  <!--如果不知道的 咱們可以輸出看看這是什麼 {{listData}}  -->
                  <ul>
                    <li v-for="(item,index) in listData.foods" :key="index">
                      {{ item }}
                    </li>
                  </ul>
                </template>
              </Category>
              <Category>
                <template slot="slot1">
                  <h1>Foods</h1>
                </template>
                <template slot="slot2" scope="listData">
                  <ol>
                    <li v-for="(item,index) in listData.foods" :key="index">
                  http://www.cppcns.com    {{ item }}
                    </li>
                  </ol>
                </template>
              </Category>
              <Category>
                <template slot="slot1">
                  <h1>Foods</h1>
                </template>
                <template slot="slot2" scope="listData">
                    <h4 v-for="(item,index) in listData.foods" :key="index">
                      {{ item }}
                    </h4>
                </template>
              </Category>
              <Category>
                <template slot="slot1" scope="listData">	
          {{listData}}
                </template>
              </Category>
            </div>
          </template>
           
          <script>
          import Category from './components/Category.vue'
           
          export default {
            name: 'App',components: {
              Category
            }
          }
          </script>

          效果圖

          image-20211120154438477

          這種我在學習及練習過程中,並沒有想到哪些使用場景,但是在官網上有案例,我想它必定是有存在的理由,只是我的見識太少,而未能利用到而已。

          解釋:

          子元件中通過:變數名="定義的資料" 向父元件傳值,父元件用 <templatewww.cppcns.com slot="slot2" scope="不用和子元件傳遞過來的名稱相同"> 接收,因為還要. 一層,才到

          <template slot="slot2" scope="listData">
          <!--如果不知道的 咱們可以輸出看看這是什麼 {{listData}}  -->
          <ul>
              <li v-for="(item,index) in listData.foods" :key="index">
                  {{ item }}
              </li>
              </ul>
          </template>

          總結

          本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注我們的更多內容!