| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 | <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() {        // 如果fixed,placeholder等参数发生变化,重新计算占位元素的高度        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>
 |