iT邦幫忙

2021 iThome 鐵人賽

DAY 22
0
自我挑戰組

Vue.js 從零開始系列 第 22

Vue.js 從零開始:Slot

學完component是怎麼傳遞之後,看似完美,如果某天PM丟出一個需求,初步了解狀況後,發現有很多地方都可以組成元件來重複使用,但其實沒有這麼簡單,看起來一樣的區塊,其實裏面有很多結構不一樣,這時就可以針對裡面的小區域去做修改。


Slot

Vue官網翻譯Slot為插槽,我聯想到線上遊戲的武器,也會有各種插槽,用這個方式去想會比較容易理解:
https://ithelp.ithome.com.tw/upload/images/20211002/20118347ydgU0ObQHx.png
你的人物角色就像是外部元件,你的名刀不知火就是內元件,遊戲系統有卡片功能,卡片可以插在你的道具上面(內元件),卡片就是你想要的從外部放入的文字,但前提是道具要打洞成插槽:

<div id="app">
  <h3> {{ text }} </h3>
  <out-text>
    <p>打洞成功</p>
  </out-text>
  <out-text>
  </out-text>
</div>
const app = Vue.createApp({
  data() {
    return {
      text: "外層元件",
      product: {
        name: "名刀不知火",
        price: 200000,
      }
    }
  }
});
app.component("outText",{
  template: `
  <div class="box">
    <h3> {{ text }} </h3>
    <div class="header">header</div>
    <div class="main">
      <slot> 預設值!</slot>
    </div>
    <div class="footer">footer</div>
  </div>
  `,
  data() {
    return {
      text: "內部元件",
      num: 3,
    };
  }
});
app.mount("#app");

內層元件的模板某區塊如果要由外層元件定義時,子元件一定要加上slot,外層元件的模板打洞成功才能正常顯示。
如果外層元件的模板,沒有任何元素時,就會顯示<slot> 預設值!</slot>,可以觀察兩個子元件畫面渲染的差異。


slot 具名插槽

一把武器只有一個插槽那怎麼夠啊!那我要四個該怎麼做呢?

https://ithelp.ithome.com.tw/upload/images/20211002/20118347gfzvgfyKz9.jpg

這種情況握緊拳頭是沒有用的,在建立四個插槽需要先瞭解slot有個屬性:name,可以使用它來為插槽命名,子元件模板則使用v-slot讓外層傳遞到子元件:

<div id="app">
    <h3> {{ product.name }} </h3>
    <out-text>
        <template v-slot:header>波利卡片</template>
        <template v-slot:main>瘋兔卡片</template>
        <template v-slot:default></template>
        <template v-slot:footer>禿鷹卡片</template>
    </out-text>
</div>
const app = Vue.createApp({
  data() {
    return {
      text: "外層元件",
      product: {
        name: "名刀不知火",
        price: 200000,
      }
    }
  }
});
app.component("outText",{
  template: `
  <div class="box">
    <div class="header">
      <slot name="header"></slot>
    </div>
    <div class="main">
      <slot name="main"></slot>
        <div>
            <slot>未插卡!</slot>
        </div>
    </div>
    <div class="footer">
      <slot name="footer"></slot>
    </div>
  </div>
  `,
  data() {
    return {
      text: "內部元件",
      num: 3,
    };
  }
});
app.mount("#app");

v-slot:header可以改為#header的寫法較為簡潔,v-slot:default預設如果主元件沒有值,就會由<slot>未插卡!</slot>來代替。


slot作用域

先來觀察這段程式碼,並猜想畫面會是什麼呢?

<div id="app">
  <h3> {{ product.name }} </h3>
  
  <out-text>
    <p> {{ product.name }} </p>
  </out-text>
</div>
const app = Vue.createApp({
  data() {
    return {
      text: "外層元件",
      product: {
        name: "名刀不知火",
        price: 200000,
      }
    }
  }
});
app.component("outText",{
  template: `
  <div class="box">
  </div>
  `,
  data() {
    return {
      text: "內部元件",
      product: {
        name: "+9 獵人之弓",
        price: 100000,
      }
    };
  }
});
app.mount("#app");





答案是只會顯示外層元件data裡的product.name,因為兩個元件雖然都有一樣product,但各自元件有屬於自己的data與作用域,兩個product是不同的屬性。
<out-text><p> {{ product.name }} </p></out-text>會無法顯示,是因為Vue在編譯時,會以元件模板定義內容為主,會忽略掉{{ product.name }} ,除非在子元件模板加上slot

官網補充:父級模板裡的所有內容都是在父級作用域中編譯的;子模板裡的所有內容都是在子作用域中編譯的。


重點整理:

  1. 子元件template記得打洞變成slot
  2. 插槽名稱:name
  3. 插入卡片請使用v-slot:插槽名稱,可縮寫為#插槽名稱。
  4. 注意元件的作用域,角色(外層元件),武器(內層元件)。

以上如有錯誤,歡迎指教,下一篇講解slot的資料傳遞。


參考資料

六角學院
重新認識 Vue.js


上一篇
Vue.js 從零開始:emit 元件的溝通
下一篇
Vue.js 從零開始:Slot Props
系列文
Vue.js 從零開始30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言