mall-uniapp/sheep/ui/su-tabbar/su-tabbar.vue

228 lines
6.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!-- 底部导航栏 -->
<template>
<view class="u-tabbar">
<view
class="u-tabbar__content"
ref="u-tabbar__content"
@touchmove.stop.prevent=""
:class="[border && 'u-border-top', fixed && 'u-tabbar--fixed', { 'mid-tabbar': midTabBar }]"
:style="[tabbarStyle]"
>
<view class="u-tabbar__content__item-wrapper">
<slot></slot>
</view>
<view v-if="safeAreaInsetBottom" :style="[{ height: safeBottomHeight + 'px' }]"></view>
</view>
<view
class="u-tabbar__placeholder"
v-if="placeholder"
:style="{
height: placeholderHeight + 'px',
}"
></view>
</view>
</template>
<script>
// #ifdef APP-NVUE
const dom = uni.requireNativePlugin('dom');
// #endif
/**
* Tabbar 底部导航栏
* @description 此组件提供了自定义tabbar的能力。
* @property {String | Number} value 当前匹配项的name
* @property {Boolean} safeAreaInsetBottom 是否为iPhoneX留出底部安全距离默认 true
* @property {Boolean} border 是否显示上方边框(默认 true
* @property {String | Number} zIndex 元素层级z-index默认 1
* @property {String} activeColor 选中标签的颜色(默认 '#1989fa'
* @property {String} inactiveColor 未选中标签的颜色(默认 '#7d7e80'
* @property {Boolean} fixed 是否固定在底部(默认 true
* @property {Boolean} placeholder fixed定位固定在底部时是否生成一个等高元素防止塌陷默认 true
* @property {Object} customStyle 定义需要用到的外部样式
*
*/
import { deepMerge, addStyle, sleep } from '@/sheep/helper';
import sheep from '@/sheep';
export default {
name: 'su-tabbar',
props: {
customStyle: {
type: [Object, String],
default: () => ({}),
},
customClass: {
type: String,
default: '',
},
// 跳转的页面路径
url: {
type: String,
default: '',
},
// 页面跳转的类型
linkType: {
type: String,
default: 'navigateTo',
},
// 当前匹配项的name
value: {
type: [String, Number, null],
default: '',
},
// 是否为iPhoneX留出底部安全距离
safeAreaInsetBottom: {
type: Boolean,
default: true,
},
// 是否显示上方边框
border: {
type: Boolean,
default: true,
},
// 元素层级z-index
zIndex: {
type: [String, Number],
default: 10,
},
// 选中标签的颜色
activeColor: {
type: String,
default: '#1989fa',
},
// 未选中标签的颜色
inactiveColor: {
type: String,
default: '#7d7e80',
},
// 是否固定在底部
fixed: {
type: Boolean,
default: true,
},
// fixed定位固定在底部时是否生成一个等高元素防止塌陷
placeholder: {
type: Boolean,
default: true,
},
midTabBar: {
type: Boolean,
default: false,
},
},
data() {
return {
placeholderHeight: 0,
safeBottomHeight: sheep.$platform.device.safeAreaInsets.bottom,
};
},
computed: {
tabbarStyle() {
const style = {
zIndex: this.zIndex,
};
// 合并来自父组件的customStyle样式
return deepMerge(style, addStyle(this.customStyle));
},
// 监听多个参数的变化通过在computed执行对应的操作
updateChild() {
return [this.value, this.activeColor, this.inactiveColor];
},
updatePlaceholder() {
return [this.fixed, this.placeholder];
},
},
watch: {
updateChild() {
// 如果updateChildren中的元素发生了变化则执行子元素初始化操作
this.updateChildren();
},
updatePlaceholder() {
// 如果fixedplaceholder等参数发生变化重新计算占位元素的高度
this.setPlaceholderHeight();
},
},
created() {
this.children = [];
},
mounted() {
this.setPlaceholderHeight();
},
methods: {
updateChildren() {
// 如果存在子元素则执行子元素的updateFromParent进行更新数据
this.children.length && this.children.map((child) => child.updateFromParent());
},
getRect(selector, all) {
return new Promise((resolve) => {
uni.createSelectorQuery()
.in(this)
[all ? 'selectAll' : 'select'](selector)
.boundingClientRect((rect) => {
if (all && Array.isArray(rect) && rect.length) {
resolve(rect);
}
if (!all && rect) {
resolve(rect);
}
})
.exec();
});
},
// 设置用于防止塌陷元素的高度
async setPlaceholderHeight() {
if (!this.fixed || !this.placeholder) return;
// 延时一定时间
await sleep(20);
// #ifndef APP-NVUE
this.getRect('.u-tabbar__content').then(({ height = 50 }) => {
// 修复IOS safearea bottom 未填充高度
this.placeholderHeight = height;
});
// #endif
// #ifdef APP-NVUE
dom.getComponentRect(this.$refs['u-tabbar__content'], (res) => {
const { size } = res;
this.placeholderHeight = size.height;
});
// #endif
},
},
};
</script>
<style lang="scss" scoped>
.u-tabbar {
display: flex;
flex: 1;
justify-content: center;
&__content {
display: flex;
flex-direction: column;
background-color: #fff;
box-shadow: 0px -2px 4px 0px rgba(51, 51, 51, 0.06);
&__item-wrapper {
height: 50px;
display: flex;
justify-content: space-around;
align-items: center;
}
}
.mid-tabbar {
border-radius: 30rpx 30rpx 0 0;
}
&--fixed {
position: fixed;
bottom: -1px;
left: 0;
right: 0;
}
}
</style>