vue3基础组件开发-tabs(标签栏)

3,406 阅读2分钟

前言

使用了vue3有很长一段时间了,写了很多的基础组件在自己使用,整理一下(尽量使用最简单的方式实现),当做对自己知识的梳理。

tips:对于标签页,vue官方已经有了非常好的实现方式,本篇文章更多的是对这种实现方式原理的梳理。

官方tabs实现

技术栈

vue3 + tailwindcss + ts

实现

根据官方的例子,自己实现一个标签栏组件,代码如下

<template>
  <div class="flex flex-col">
    <h2 class="ml-5">角色设置</h2>
    <div class="px-5 mt-6 grid grid-cols-[171px_minmax(0,_1fr)]">
      <div>
        <button
          v-for="(_, tab) in tabs"
          :key="tab"
          :class="[
            'block px-4 py-2 rounded-lg',
            { 'bg-[#F2F2F2]': currentTab === tab },
          ]"
          @click="currentTab = tab as string"
        >
          {{ tabsName.get(tab) }}
        </button>
      </div>

      <component :is="tabs[currentTab]" class="tab"></component>
    </div>
  </div>
</template>

<script lang="ts" setup>
import AllRole from './AllRole.vue'
import SuperRole from './SuperRole.vue'

const currentTab = ref('all')
const tabsName = new Map().set('all', '全体成员权限').set('super', '超级管理员')

const tabs = ref<{
  [key: string]: any
}>({
  all: markRaw(AllRole),
  super: markRaw(SuperRole),
})
</script>

演示如下:

image.png

自己实现的标签栏还是有一些地方和官方例子中不同的地方,主要在以下几点:

  1. 官方是横向的标签栏,我改成的竖向的。
  2. 使用了map对显示的标签名进行了替换,这一步主要是考虑到标签栏很可能不是固定的,是可以动态标签栏的,使用map后可以非常方便的添加新的标签。这里可能有一个疑惑,为啥不用中文字符串当做key呢,这样的话,map就可以不用写了。实际上,在各大浏览器或者服务器中,对中文的编码格式有所偏差;所以使用中文字符串当做对象key,可能有意外的bug出现。
  3. 使用 markRaw 对组件进行了包装,markRaw的作用是对一个对象不做深入的响应式绑定;说白一点,就是没有双向绑定了(不正确说法)。在vue3开发的过程中,我们要明白一件事情,那就是,vue组件对象是不需要响应式的;所以,如果你想要对vue组件对象做一些如props传递,动态新增之类的操作的时候,可以使用markRaw进行包装,可以提高性能。
  4. 实际上,对于一个基础的标签栏组件来说,我们不应该在tabs组件的内部引入其它的组件,基础组件保持存粹性是一件很好的事情;所以,我们可以通过props接收外面传进来的动态组件的方式去做标签切换,map的名字也可集成到props传进来的值的内部。这里我为什么不这么做呢,原因已经在我写的button组件文章里面有所体现了,嗯,我一个项目里面有差不多4种tabs标签样式,都封装在一个组件里面没有必要,自己每个单独写一遍吧,想咋改咋改。

vue中动态组件的原理

不太好解释,我画了一张简图,看图理解吧。

image.png

尾声

其实在vue3的动态组件中,还有很多可以玩空间,大佬们可以去试一试。

水平有限,如有错漏之处欢迎各位大佬指正。