quanyawei
2024-01-10 e13367edf304cb78f978e321f1679299a66b3a23
uni_modules/uview-ui/components/u-tabbar/u-tabbar.vue
New file
@@ -0,0 +1,141 @@
<template>
   <view class="u-tabbar">
      <view
          class="u-tabbar__content"
          ref="u-tabbar__content"
          @touchmove.stop.prevent="noop"
          :class="[border && 'u-border-top', fixed && 'u-tabbar--fixed']"
          :style="[tabbarStyle]"
      >
         <view class="u-tabbar__content__item-wrapper">
            <slot />
         </view>
         <u-safe-bottom v-if="safeAreaInsetBottom"></u-safe-bottom>
      </view>
      <view
          class="u-tabbar__placeholder"
         v-if="placeholder"
          :style="{
            height: placeholderHeight + 'px',
         }"
      ></view>
   </view>
</template>
<script>
   import props from './props.js';
   // #ifdef APP-NVUE
   const dom = uni.requireNativePlugin('dom')
   // #endif
   /**
    * Tabbar 底部导航栏
    * @description 此组件提供了自定义tabbar的能力。
    * @tutorial https://www.uviewui.com/components/tabbar.html
    * @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         定义需要用到的外部样式
    *
    * @example <u-tabbar :value="value2" :placeholder="false" @change="name => value2 = name" :fixed="false" :safeAreaInsetBottom="false"><u-tabbar-item text="首页" icon="home" dot ></u-tabbar-item></u-tabbar>
    */
   export default {
      name: 'u-tabbar',
      mixins: [uni.$u.mpMixin, uni.$u.mixin,props],
      data() {
         return {
            placeholderHeight: 0
         }
      },
      computed: {
         tabbarStyle() {
            const style = {
               zIndex: this.zIndex
            }
            // 合并来自父组件的customStyle样式
            return uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle))
         },
         // 监听多个参数的变化,通过在computed执行对应的操作
         updateChild() {
            return [this.value, this.activeColor, this.inactiveColor]
         },
         updatePlaceholder() {
            return [this.fixed, this.placeholder]
         }
      },
      watch: {
         updateChild() {
            // 如果updateChildren中的元素发生了变化,则执行子元素初始化操作
            this.updateChildren()
         },
         updatePlaceholder() {
            // 如果fixed,placeholder等参数发生变化,重新计算占位元素的高度
            this.setPlaceholderHeight()
         }
      },
      created() {
         this.children = []
      },
      mounted() {
         this.setPlaceholderHeight()
      },
      methods: {
         updateChildren() {
            // 如果存在子元素,则执行子元素的updateFromParent进行更新数据
            this.children.length && this.children.map(child => child.updateFromParent())
         },
         // 设置用于防止塌陷元素的高度
         async setPlaceholderHeight() {
            if (!this.fixed || !this.placeholder) return
            // 延时一定时间
            await uni.$u.sleep(20)
            // #ifndef APP-NVUE
            this.$uGetRect('.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>
   @import "../../libs/css/components.scss";
   .u-tabbar {
      @include flex(column);
      flex: 1;
      justify-content: center;
      &__content {
         @include flex(column);
         background-color: #fff;
         &__item-wrapper {
            height: 50px;
            @include flex(row);
         }
      }
      &--fixed {
         position: fixed;
         bottom: 0;
         left: 0;
         right: 0;
      }
   }
</style>