美文网首页
制作tab组件的思路分析

制作tab组件的思路分析

作者: 晨曦的杂货铺 | 来源:发表于2022-06-14 22:29 被阅读0次

一.如何检查子组件的类型

<template>
  <div>
    Tabs组件
    <component :is="defaults[0]" />
    <component :is="defaults[0]" />
  </div>
</template>
<script lang="ts">
import Tab from "./Tab.vue";
export default {
  setup(props, context) {
    const defaults = context.slots.default();// 
    console.log(defaults[0].type === Tab); //true
    defaults.forEach((tag) => {
      if (tag.type !== Tab) {
        throw new Error("Tabs子组件必须是Tab");
      }
    });
    return {
      defaults,
    };
  },
};
</script>

首先我们先用log技巧,来调试控制台。

  1. 输入以下代码console.log({ ...context});会在控制台中显示如下数据,如图所示:
1.png
  1. js获取插槽内容,const default =context.slots.default()(注意default是一个函数),会在控制台中显示如下数据,如图所示:
2.png
  1. 在模板中引入如下代码 <component :is="defaults[0]" <component :is="defaults[0]" />,来获取Tab组件的内容

  2. 判断其为引入组件的类型是否为Tab,如果不是Tab则抛出错误。console.log(defaults[0].type === Tab); //true

二.渲染嵌套的插槽

  1. Tab组件中的代码
<template>
  <div><slot /></div>
</template>
  1. TabsDemo组件中引入Tabs和Tab的组件
<Tabs :selected="x" @update:selected="x = $event">
  <Tab title="导航一">脚踏实地</Tab>
  <Tab title="导航二">仰望星空</Tab>
</Tabs>
  1. TabTabs的子组件,在Tabs中使用Tab组件
  <component :is="defaults[0]" />
  <component :is="defaults[1]" />

三.显示被选中的导航。

  1. Tab组件上设置selected
<Tabs selected="导航一">
  <Tab title="导航一">脚踏实地</Tab>
  <Tab title="导航二">仰望星空</Tab>
 </Tabs>
  1. 获取Tab组件中的title
const titles= defaults.map(tag=>{
  return tag.props.title
})
  1. Tab组件title中设置被选中的内容
<div
  :class="{selected:selected===t}"
  v-for="(t, index) in titles"
  :key="index"
  >
  {{ t }}
</div>

  1. Tab组件的内容区中设置被选中的内容(注意:v-if的优先级大于v- for的优先级)
<template v-for='c in defaults'>
<component is='c' v-if='c.props.title===selected' />
</template>
  1. 点击被显示的内容
<div
  @click="select(t)"
  :class="{selected:selected===t}"
  v-for="(t, index) in titles"
  :key="index"
     >
 {{ t }}
</div>

setup(props,context){
 const select(title:string)=>{
 context.emit("update:selected",title)
 } 
}

在父组件修改传递过来的值

<Tabs :selected="x" @update:selected="x = $event">
  <Tab title="导航一">脚踏实地</Tab>
  <Tab title="导航二">仰望星空</Tab>
</Tabs>

四.js动态设置div的宽度(template ref的用法 )

  1. 在数组中使用ref可以观察如下代码:
<div>
  class="ui-tabs-nav-item"
  :class="{ selected: t === selected }"
  v-for="(t, index) in titles"
  :ref="
    (el) => {
     if (el) navItems[index] = el;
           }
        "
  :key="index"
      >
  {{ t }}
</div>
  1. 利用log(console.log({...navItems})调试法我们可以观察到navItems(Object)里面的值,如下图:
4.png.png
  1. 获取选中元素div的宽度
setup(props, context) {
const navItems = ref<HTMLDivElement[]>([]); //有两个数组其默认值为空数组
const indicator = ref<HTMLDivElement>(null); //其只有一个数组
const container = ref<HTMLDivElement>(null);
}
//在挂载之后获取元素,只在第一次渲染之后执行.
onMounted(()=>{
  //将横线的宽设置为选中div的宽度.
   const divs = navItems.value;
    const result = divs.filter((div) =>
      div.classList.contains("selected")
    )[0]; //filter的支持性更好,其会返回一个数组
    const { width } = result.getBoundingClientRect();//注意getBoundingClientRect可支持left,top,width,height
    indicator.value.style.width = width + "px"; 
    //将选中div的left减去nav的left
    const { left: left1 } = container.value.getBoundingClientRect();
    const { left: left2 } = result.getBoundingClientRect();
    const left = left2 - left1;
    indicator.value.style.left = left + "px";
})
//在更新时在重新写一次

相关文章

网友评论

      本文标题:制作tab组件的思路分析

      本文链接:https://www.haomeiwen.com/subject/lrrtvrtx.html