Day 24:「Switch 也要换游戏片啦~」- Slot 插槽

Day24-Banner-not-yet

不知道大家有没有买 Switch 呢?

虽然兔兔没有 Switch,
但我知道有游戏片都不便宜呀!

然後,游戏总会有玩腻的时候
这时候就要把记忆卡插槽里的卡片拿出来,
接着插一张新的进去。

不过其实,
你不知道有没有发现,
我们自定义的元件都是只有标签,
都没在里面放内容呢?

<Box :number="1" />

<Box :number="2">
</Box>

我们目前都是把所有的资料丢在属性,

可是其实原生的写法应该要可以做到这样

<Box>1</Box>

<Box>2</Box>

但你会发现在自定义的元件之中这样用是没反应的

WHY?
我们接下来就来谈谈为什麽!
 

carrotPoint 插槽 Slot

如果要像前面所说,想要可以跟原生的写法一样能够在里面加上内容的话,Slot 就是你要找的功能!

不过我们就要解释一下为何得靠其他功能来解决,而不能直接放在里面。

让我们先看看元件实际上的意义:

<!-- 看起来的样子 -->
<Menu />

<!-- 实际上的样子 -->
<ul>
  <li>首页</li>
  <li>关於</li>
  <li>卖场</li>
  <li>服务</li>
</ul>

没错,就是做结构简化整理

那麽如果今天在元件内加入内容呢?

<!-- 看起来的样子 -->
<Menu>
  这是我们的选单。
</Menu>

<!-- 实际上的样子 -->
<ul>
  <li>首页</li>
  <li>关於</li>
  <li>卖场</li>
  <li>服务</li>
</ul>

没反应,因为他不知道你要把这些内容实际上是要安排在 template 中的哪里!

没错,就是这麽简单的问题。

所以 slot 的功能就是要用来告诉 vue 我们要把内容插在实际上结构的哪个地方

而其实 slot 的用法很单纯又简单,
我们只要加上 <slot></slot> 就好。

举例:

<!-- Menu.vue -->
<template>
  <ul>
    <slot></slot>
    <li v-for="link in links">{{ link }}</li>
  </ul>
</template>

<script>
export default {
  data() {
    return {
      links: ["首页","关於","卖场","服务"]
    }
  }
}
</script>

那麽效果就会是这样:

<!-- 看起来的样子 -->
<Menu>
  这是我们的选单。
</Menu>

<!-- 实际上的样子 -->
<ul>
  这是我们的选单。
  <li>首页</li>
  <li>关於</li>
  <li>卖场</li>
  <li>服务</li>
</ul>

是不是很轻松简单?

但你可能会纳闷:

「目前这个效果用 props 也能做到啊!」

噢,没错,你说的对。
不过这样呢?

<!-- 看起来的样子 -->
<Menu>
  <div>
    <img src="banner.jpg" />
    <span>欢迎光临 myfone</span>
  </div>
</Menu>

<!-- 实际上的样子 -->
<ul>
  <div>
    <img src="banner.jpg" />
    <span>欢迎光临 myfone</span>
  </div>
  <li>首页</li>
  <li>关於</li>
  <li>卖场</li>
  <li>服务</li>
</ul>

如果今天要抛入的是元素,是不是就很困难啦?
但是使用 slot 就简单太多啦!
 

carrotPoint 使用时机

其实应该也没有很明确的使用时机,
不过多半会用在需要替换内容的元件,比如 modal。

而有时候使用他是为了架构清晰,保持与视觉一致

还有一点我觉得很重要的,
就是如果你要 跨祖孙元件交换资料 的时候,
可以更方便。

因为这麽做等於平坦化,
原本要祖孙元件沟通,现在可以降维成父子元件沟通

举例:

<!-- 主画面 -->
<div>
  <List @modify="change($event)" />
</div>

<!-- List.vue -->
<div>
  <div>标题</div>
  <ul>
    <Item v-for="i in 10" @modify="$emit('modify', $event)" />
  </ul>
</div>

<!-- Item.vue -->
<li>
  <input type="text" />
  <button @click="$emit('modify', text)">修改</button>
</li>

像上述这样的祖孙结构,
资料传递起来就很麻烦。

因为你 props 跟 emit 可能都需要连传两层
但为何说 slot 可以平坦化、降成父子关系?

看了就明白了:

<!-- 主画面 -->
<div>
  <List>
    <Item v-for="i in 10" @modify="$emit('modify', $event)" />
  </List>
</div>

<!-- List.vue -->
<div>
  <div>标题</div>
  <ul>
    <slot>
      目前没有任何文章。
    </slot>
  </ul>
</div>

<!-- Item.vue -->
<li>
  <input type="text" />
  <button @click="$emit('modify', text)">修改</button>
</li>

顺带一提,slot 是可以给予预设内容的,在没有从外部填入内容之前,可以维持显示预设内容。

 
这样我在主画面之中就可以直接对 Item 元件存取了,
而且结构上看起来可读性比较高。

不过这种用法还是要经过考虑和评估,
因为如果太滥用,等於所有资料都得跑在父层上
太混杂了,肯定维护起来不容易

(就跟以不好的观念使用 vuex 一样,很可怕。)
 

carrotPoint 具名插槽

其实不只可以有一个插槽,也可以有 N 个。

只是,结构里面就一个区域啊,
怎麽知道我要指定插到哪个插槽?

这时候就是具名插槽该登场的时候啦~

具名插槽也很简单,就是这样定义:

<!-- Menu.vue -->
<template>
  <ul>
    <slot name="title"></slot>
    <li v-for="link in links">{{ link }}</li>
  </ul>
  <slot name="description"></slot>
</template>

<script>
export default {
  data() {
    return {
      links: ["首页","关於","卖场","服务"]
    }
  }
}
</script>

对,简单的加上 name,然後使用时只要像 v-on:v-bind: 那类的语法一般,加上 v-slot: 以及名称。

不过必须用 <template></template> 将区块包裹起来。

所以就会是这样:

<!-- 使用时看起来的样子 -->
<Menu>
  <template v-slot:title>
    这是我们的选单。
  </template>
  
  <template v-slot:description>
    选单项目将会不定时更新,敬请期待。
  </template>
</Menu>

<!-- 实际上的样子 -->
<ul>
  这是我们的选单。
  <li>首页</li>
  <li>关於</li>
  <li>卖场</li>
  <li>服务</li>
</ul>
选单项目将会不定时更新,敬请期待。

什麽? 你期待这个也有短语法

我说你啊,人不能这麽懒,
而且这种功能要什麽短...

等等,还真的有!

试着用 # 来替代 v-slot 当缩短语法:

<Menu>
  <template #title>
    这是我们的选单。
  </template>
  
  <template #description>
    选单项目将会不定时更新,敬请期待。
  </template>
</Menu>

嘿,丢啦!
这样就可以了。
 

carrotPoint 插槽 Props

「兔兔! 元件放到插槽之後,就没办法吃到前一层元件的变数了欸,那这样怎麽办!」

哈哈哈哈哈!
当然不会有这麽不方便的事情存在啊!

其实插槽是有 Props 的!

我们来看看该如何帮插槽设置 props:

<!-- Menu.vue -->
<template>
  <div>
    {{ title }}
  </div>
  <div>
    <ul>
      <slot :list="links"></slot>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      title: "选单",
      links: ["首页","关於","卖场","服务"]
    }
  }
}
</script>

就跟一般平时你给 props 的方式一模一样!

不过存取的方式不一样:

<Menu v-slot="slotProps">
  <li v-for="item in slotProps.list">
    {{ item }}
  </li>
</Menu>

要透过在 v-slot 後加上 ="slotProps"

slotProps 是 slot 预设的 props 组名称,传递过来的 props 都是 slotProps 下的一个属性。

当然我们也能解构:

<Menu v-slot="{ list }">
  <li v-for="item in list">
    {{ item }}
  </li>
</Menu>

这样能存取到上层的变数,是不是又更方便了呢!

(虽然我想不太到使用时机)
 

哇! slot 就这麽介绍了!
其实还有一些更细部的功能啦,
但那些应该要自己去阅读文件,

我的 vue 篇主要是为了,
把我们之後做元件会用到的功能都先带过一遍。

那其实 vue 篇就这样结束啦!
(帮 vue 篇完结洒花)

我们後面接着就要来开始实作元件了!

好期待,不知道大家会不会觉得好玩呢?
 

carrotPoint 给你们的回家作业:

  • 作业实施要点:
    • 复习 Tailwind 篇
    • 复习 Vue 篇
       

关於兔兔们:


 


( # 兔兔小声说 )

在你们的国度,驾照都是用鸡腿换的。

在兔兔这里,你们知道用的是什麽吗?

「红萝卜!」

啧啧啧,你以为红萝卜在我这里这麽好价嘛!
那可是相当於米饭的存在欸!

来,凑近点,我告诉你答案。
其实是:

黄根!!


<<:  DAY 13 『 Realm 新增、修改、删除 』Part1

>>:  Day19 K平均演算法实作

Angular RxJs 各种解订阅方式

昨天说到了将资料订阅出来渲染在页面上的事,那麽就就来说说 RxJs 解订阅这件事吧。 这也是为了避免...

Day 27:专案07 - 天气小助理01 | 气象资料API

图片来源:https://www.epochtimes.com/b5/18/1/5/n100268...

数位转型

在疫情的情况之下,所有的节奏都被打乱了,在全球都在这样的情况之下,大家都在求新求变,不论是办公还是教...

【Day29】综合练习:台铁即时时刻表(1/2)

本日小作品: https://codepen.io/linchinhsuan/pen/OJXVgdo...

【Day 23】Bubble sort 范例

不知道大家对於 Bubble sort 的程序有没有甚麽问题呢? 今天,我们就来讨论一下程序码! 我...