vue3 vant4 Tabbar 标签栏组件的封装 和Popup弹出层的封装
需求如上,标签栏里第三个是图片,整个项目有两种场景,
- 标签栏正常跳转页面,
- 标签拦渲染别的图片时候,点击就是打开弹出层,
封装了标签栏,弹出层两部分,作为公共组件
标签栏的封装
<template>
<div class="customTabbar">
<van-tabbar v-model="state.active">
<template v-for="(item, index) in state.iconList" :key="index">
<van-tabbar-item :icon="getDisplayIcon(item)" :to="item.url" :badge= "index === 3 ? state.message : null">
{{ item.name }}
<template v-if="item.type === 'image'">
<img :src="item.icon" alt="" class="navImg" @click="handleImageClick(item)" />
</template>
</van-tabbar-item>
</template>
</van-tabbar>
</div>
</template>
<script setup>
import { defineProps, reactive } from 'vue';
import { Tabbar, TabbarItem } from 'vant';
import aaa from '../../../assets/aaaa.png';
const state = reactive({
active: 0,
iconList: [
{ name: "首页", icon: "home-o", url: "", type: "normal" },
{ name: "分析", icon: "search", url: "", type: "normal" },
{ name: "", icon: aaa, url: "",type: "image" }, // 新增的图片图标
{ name: "消息", icon: "chat-o", url: "", type: "normal" },
{ name: "我的", icon: "contact", url: "", type: "normal" }, // 保留之前的最后一个图标
],
message:null,
});
const getDisplayIcon = (item) => (item.type === "image" ? "" : item.icon);
const emit = defineEmits(['show-popup-visible']);
const handleImageClick = (item) => {
// if (!item.url) {
// 打开弹出层的逻辑 给父组件传入自定义事件,专门用于打开弹出层
// emit('show-popup-visible', true)
// }
};
</script>
<style lang="less" scoped>
.customTabbar {
.navImg {
width: 7.3rem;
height: 7.3rem;
border-radius: 50%;
}
}
:deep(.van-tabbar-item__icon) {
font-size: 44px;
}
:deep.van-tabbar {
height: 7.3rem;
}
:deep .van-tabbar-item__text {
font-size: 1rem;
}
</style>
徽标样式需要调整,list现在是自己暂时再state里写的假数据
下面是再使用标签组件时候
<CustomTabbar />
或者是
<CustomTabbar @show-popup-visible = popupVisible />
@show-popup-visible = popupVisible 这里作用往下看,是打开弹出层的事件
直接引用再内容区域使用
如果不是需要打开弹出层的操作,不需要写上自定义事件,需要再加上
这里有个坑 <img :src=“item.icon” alt=“” class=“navImg” @click=“handleImageClick(item)” />
如果图片采用是变量方式渲染
如果不导入图片import aaa from ‘…/…/…/assets/aaaa.png’
引用图片时候是不会展示的,
相反直接把地址写在img上是可以正常渲染
----------------------------------------------------------------------------------------------
弹出层的封装,这里是子组件和父组件的数据可以实现双向数据绑定
<template>
<van-popup :show="showPopupVisible" :position="position" :closeable="closeable" :close-icon-position="closeIconPosition" :style="{ height: '30%' }" :overlay=false @close="onClose">
<template v-slot:default>
<!-- 弹出层的内容 -->
<slot></slot>
</template>
</van-popup>
</template>
<script setup>
import { ref, defineProps, defineEmits } from 'vue';
import { Popup } from 'vant';
const props = defineProps({
showPopupVisible: {
type: Boolean,
default: false,
},
});
const emit = defineEmits(['update-showPopupVisible']);
const popupVisible = ref(props.showPopupVisible);
const position = 'bottom';
const closeable = true;
const closeIconPosition = 'top-right';
const onClose = () => {
popupVisible.value = false;
emit('update-showPopupVisible', popupVisible.value);
};
</script>
----父组件调用弹出层时候:-----
<CustomPopup :show-popup-visible="state.showPopupVisible" @update-showPopupVisible="onPopupUpdate">
插入需要弹出的内容
</CustomPopup>
父组件声明
const state = reactive({
showPopupVisible: false
})
这里的
state.showPopupVisible 组件显示关闭的状态值
这里的
state.showPopupVisible 组件显示关闭的状态值
触发打开弹出层事件
const popupVisible = (flag) => {
state.showPopupVisible = ! state.showPopupVisible
}
------@update-showPopupVisible 关闭弹出层时传递过来自定义事件-----
const onPopupUpdate = (value) => {
state.showPopupVisible = value;
}