利用 Vue Slots 开发可高度定制的 Tabs 组件

构建可重用且具备自定义扩展的 Tab 组件。

概述:Vue.js 具备一个 Slots 功能,它以当前的 Web Components 规范草案为蓝本。如果在组件中使用插槽,那么我们可以在这些插槽部分中填充我们想要的任何内容。这样,组件可以专注于处理逻辑部分,让组件的用户来自行构建视图部分。


最终效果

我们有一个窗口,其中有四个标签显示的对应 label。单击 label 可显示关联视图部分。

插槽在这里起什么作用呢?

到目前为止,已经有很多 Tabs 组件的实现,而且大多数缺少的是可定制性。实现可能会采用这样的选项卡内容列表。

在这里,每个选项卡传递字符串,并且样式是固定的,满足不了插入图片或者其它内容的需求。

另一个缺点是,在使用该 Tabs 组件时,template 需要显示的数据 data 与脚本耦合在一起。而我们想要的是显示的内容应保留在模板部分中,脚本部分应仅包含逻辑。

那么我们如何允许该传递 Vue 组件而不是字符串?这样 Tabs 组件可以包含我们想要的任何内容,并且呈现它。

这是Vue.js插槽的用武之地。Vue.js组件可以具有多个命名的插槽,当我们使用该组件时,我们可以告诉每个插槽应该放置什么标记,同时插槽可以包含字符串, HTML 标签或其他 Vue 组件。

使用插槽实现选项卡组件

组件的基本结构如下图

也就是主要将 Tabs 组件拆分为两个部分

Tab 组件用于管理当前的标签页的 label 以及相关视图的展示;

Tabs 组件则是用于管理它内部所有的 Tab 组件,对应生成标签页以及确定视图区域。

基于这个结构,构建代码,首先确定 Tabs 组件与 Tab 组件的通信方式。利用 provide 以及 inject 将 Tabs 组件注入到 Tab 中。

Tab 组件

主要完成以下几个任务:

  • slot:在模板中,利用 slot 允许用户自行插入相关的内容;
  • created:在 Tab 组件创建的时候,访问 Tabs 组件,将其 pushchildrens 数组中,进行统一管理;
  • isOpen:匹配 Tabs 组件的 activeId,判断展示的是否是当前 Tab 组件;
  • destroyed:若 Tab 组件注销时,则从 childrens中将其删除。主要目的在于,如果 Tab 组件是利用 v-for 指令生成的,则数据变动时,整体Tabs组件也应该发生变化。

Tabs 组件

Tabs组件的childrens中包含所有的子Tab组件,利用它来构建选项卡

当 Tab 组件 created 时候,会修改 childrens,其中存在所有 Tab 组件。利用这些数据先生成标签页的 label 。

同时利用 slot 设定 Tabs 组件的视图区域,并创建一个状态用于标识当前活跃的 Tab 的activeId

封装

进一步将其封装成Vue的组件,配置其model,以及相关处理,当value发生变化时,将其赋值给activeId,相关Tab会自动更新。

实例地址:Tabs 实例

代码地址:Github UI-Library


往期文章:

原创声明: 该文章为原创文章,转载请注明出处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue 3 中封装一个 tabs 组件,你需要做如下几件事: 1. 创建一个 Vue 3 组件: ```js import { defineComponent } from 'vue'; export default defineComponent({ name: 'Tabs', // ... }); ``` 2. 为组件定义 props,用于接收外部传入的数据: ```js import { defineComponent, PropType } from 'vue'; export default defineComponent({ name: 'Tabs', props: { // 传入的标签页数据 tabs: { type: Array as PropType<{ label: string; content: string }[]>, required: true, }, // 当前选中的标签页索引 activeIndex: { type: Number, default: 0, }, }, // ... }); ``` 3. 在组件的 template 中定义 DOM 结构,显示标签页。你可以使用 v-for 指令来循环渲染标签页。 ```html <template> <div> <!-- 标签页标签 --> <div class="tabs-labels"> <template v-for="(tab, index) in tabs"> <div :class="{ 'tab-label': true, active: index === activeIndex }" @click="activeIndex = index" > {{ tab.label }} </div> </template> </div> <!-- 标签页内容 --> <div class="tabs-contents"> <template v-for="(tab, index) in tabs"> <div v-if="index === activeIndex">{{ tab.content }}</div> </template> </div> </div> </template> ``` 4. 在组件的 script 中,可以使用 computed 属性来计算当前选中的标签页的内容。 ```js import { defineComponent } from 'vue'; export default defineComponent({ name: 'Tabs', props: { // ... }, computed: { activeTab() { return this.tabs[this.activeIndex]; }, }, // ... }); ``` 5. 在组件的 script 中,可以

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值