vue3 实现一个tab切换组件
vue
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
项目地址:https://gitcode.com/gh_mirrors/vu/vue
免费下载资源
·
一. 效果图
二. 代码
文件 WqTab.vue:
<template>
<div ref="wqTabs" class="wq-tab">
<template v-for="tab in tabs" :key="tab">
<div class="tab-item" :class="{ ac: tabActive === tab.key }" @click="tabActive = tab.key">{{ tab.value || tab.key }}</div>
</template>
<div
class="bg"
:style="{
width: bgWidth + 'px',
left: bgLeft + 'px',
}"
></div>
</div>
</template>
<script setup lang="ts">
import { computed, nextTick, ref, watch } from 'vue';
import { Tab } from '@/components/WqTab/wqTabType';
type Props = {
tabs: Tab[];
active: string;
};
const props = withDefaults(defineProps<Props>(), {});
const emit = defineEmits(['update:active']);
const tabActive = computed<string>({
get() {
return props.active;
},
set(newValue) {
// 改变值
emit('update:active', newValue);
},
});
// wqTabs 元素
const wqTabs = ref();
// bg宽度
const bgWidth = ref<number>(0);
// bg 位置
const bgLeft = ref<number>(0);
watch(
tabActive,
(newValue, oldValue) => {
// 改变背景
nextTick(() => {
const tabIndex = props.tabs.findIndex((item) => item.key === newValue);
if (tabIndex >= 0) {
/**
* 当找到值时
* 1. 找到相应的元素
* 2. 获取元素的当前位置以及大小
* 3, 将bg大小进行调整 并移动到相应的位置
*/
nextTick(() => {
const tabs: Element[] | any = wqTabs.value.querySelectorAll('.tab-item');
if (!tabs || !tabs.length) {
// 若没有找到tab
console.error('tab dom find error');
return;
}
const tab = tabs[tabIndex];
bgLeft.value = tab.offsetLeft as number;
bgWidth.value = tab.clientWidth;
// console.log('value', bgLeft.value, bgWidth.value);
});
} else {
// 没有找到值的时候找default
const defaultTab = props.tabs.find((item) => item.default);
tabActive.value = defaultTab?.key || props.tabs[0].key;
}
});
},
{ immediate: true }
);
</script>
<style scoped lang="scss">
.wq-tab {
//width: 500px;
//height: 50px;
//width: 100%;
margin: auto;
display: flex;
align-items: center;
//justify-content: center;
position: relative;
border-radius: 25px;
border: 1px solid #dfe4ea;
overflow: hidden;
.tab-item {
flex: 1;
text-align: center;
//width: 100px;
//padding: 0 30px;
//max-width: 100px;
height: 40px;
line-height: 40px;
position: relative;
z-index: 2;
//overflow: hidden;
cursor: pointer;
user-select: none;
}
.ac {
color: #fff;
}
.bg {
position: absolute;
left: 0;
top: 0;
z-index: 1;
//width: 150px;
height: 50px;
background: #b2bec3;
transition: all 0.5s;
}
}
</style>
文件: wqTabType
export type Tab = {
// 唯一值
key: string;
// 非必需, 如果没有将使用key进行替换
value?: string;
// 是否为默认选项
default?: boolean;
};
三. 使用:
<template>
<wq-tab v-model:active="tabActive" :tabs="tabs"></wq-tab>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import WqTab from '@/components/WqTab/WqTab.vue';
import { Tab } from '@/components/WqTab/wqTabType';
const tabActive = ref('');
const tabs: Tab[] = [
{
key: 'comp',
value: '组件',
default: true, // 这里是默认值
},
{
key: 'app',
value: '应用',
},
{
key: 'web',
value: '网站',
},
];
</script>
四. 补充
- 这个组件的宽度是基于父元素给的,
- 传递的 active 是v-model的
- 个人代码水平一般, 如果有什么不合理的地方欢迎大佬们留言
- 组件的父元素如果是可变大小的可能会产生样式错误, 比如父元素宽度使用vh, vw这种,
GitHub 加速计划 / vu / vue
207.54 K
33.66 K
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:2 个月前 )
73486cb5
* chore: fix link broken
Signed-off-by: snoppy <michaleli@foxmail.com>
* Update packages/template-compiler/README.md [skip ci]
---------
Signed-off-by: snoppy <michaleli@foxmail.com>
Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 4 个月前
e428d891
Updated Browser Compatibility reference. The previous currently returns HTTP 404. 5 个月前
更多推荐
已为社区贡献3条内容
所有评论(0)