美文网首页
制作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