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


<<:  JavaScript Day 27. AJAX、Request、Response

>>:  【网页制作证书】点止学嘢

CSS微动画 - 动起来番外篇!谈谈Animation的Step

Q: 今天是教师节呢,怎麽没有放假? A: 认真上课黑!本篇是可能实用,但更可能杀光脑细胞的ste...

Spring 初探 (二)

Spring 初探 (二) Spring初探(二) ...

Day19-React Router 篇-下篇

这篇要来介绍 React router v5 加入的几个 hook,包括 useParams、use...

Day 24. VR菜单2

昨天打完程序码後,出现下面的Bug: Assets/LineRendererSetting.cs(5...

Day 21:总汇复习-Vuex、Route

前几篇介绍了 Vuex 管理资料状态,以及在生命周期或导航守卫发送 API 的时机点,再次回到专案范...