一.如何检查子组件的类型
<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
技巧,来调试控制台。
- 输入以下代码
console.log({ ...context});
会在控制台中显示如下数据,如图所示:
- 用
js
获取插槽内容,const default =context.slots.default()
(注意default
是一个函数),会在控制台中显示如下数据,如图所示:
-
在模板中引入如下代码
<component :is="defaults[0]" <component :is="defaults[0]" />
,来获取Tab组件的内容 -
判断其为引入组件的类型是否为Tab,如果不是Tab则抛出错误。
console.log(defaults[0].type === Tab); //true
二.渲染嵌套的插槽
- 在
Tab组件中的代码
<template>
<div><slot /></div>
</template>
- 在
TabsDemo
组件中引入Tabs和Tab
的组件
<Tabs :selected="x" @update:selected="x = $event">
<Tab title="导航一">脚踏实地</Tab>
<Tab title="导航二">仰望星空</Tab>
</Tabs>
-
Tab
是Tabs
的子组件,在Tabs
中使用Tab
组件
<component :is="defaults[0]" />
<component :is="defaults[1]" />
三.显示被选中的导航。
- 在
Tab
组件上设置selected
<Tabs selected="导航一">
<Tab title="导航一">脚踏实地</Tab>
<Tab title="导航二">仰望星空</Tab>
</Tabs>
- 获取
Tab
组件中的title
const titles= defaults.map(tag=>{
return tag.props.title
})
- 在
Tab
组件title
中设置被选中的内容
<div
:class="{selected:selected===t}"
v-for="(t, index) in titles"
:key="index"
>
{{ t }}
</div>
- 在
Tab
组件的内容区中设置被选中的内容(注意:v-if
的优先级大于v- for
的优先级)
<template v-for='c in defaults'>
<component is='c' v-if='c.props.title===selected' />
</template>
- 点击被显示的内容
<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
的用法 )
- 在数组中使用
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>
- 利用
log(console.log({...navItems})
调试法我们可以观察到navItems(Object)
里面的值,如下图:
- 获取选中元素
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";
})
//在更新时在重新写一次
网友评论