You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

145 lines
4.1 KiB

5 months ago
  1. <template>
  2. <view class="u-tabbar">
  3. <view
  4. class="u-tabbar__content"
  5. ref="u-tabbar__content"
  6. @touchmove.stop.prevent="noop"
  7. :class="[border && 'u-border-top', fixed && 'u-tabbar--fixed']"
  8. :style="[tabbarStyle]"
  9. >
  10. <view class="u-tabbar__content__item-wrapper">
  11. <slot />
  12. </view>
  13. <u-safe-bottom v-if="safeAreaInsetBottom"></u-safe-bottom>
  14. </view>
  15. <view
  16. class="u-tabbar__placeholder"
  17. v-if="placeholder"
  18. :style="{
  19. height: placeholderHeight + 'px',
  20. }"
  21. ></view>
  22. </view>
  23. </template>
  24. <script>
  25. import { props } from './props';
  26. import { mpMixin } from '../../libs/mixin/mpMixin';
  27. import { mixin } from '../../libs/mixin/mixin';
  28. import { addStyle, deepMerge, sleep } from '../../libs/function/index';
  29. // #ifdef APP-NVUE
  30. const dom = uni.requireNativePlugin('dom')
  31. // #endif
  32. /**
  33. * Tabbar 底部导航栏
  34. * @description 此组件提供了自定义tabbar的能力
  35. * @tutorial https://ijry.github.io/uview-plus/components/tabbar.html
  36. * @property {String | Number} value 当前匹配项的name
  37. * @property {Boolean} safeAreaInsetBottom 是否为iPhoneX留出底部安全距离默认 true
  38. * @property {Boolean} border 是否显示上方边框默认 true
  39. * @property {String | Number} zIndex 元素层级z-index默认 1
  40. * @property {String} activeColor 选中标签的颜色默认 '#1989fa'
  41. * @property {String} inactiveColor 未选中标签的颜色默认 '#7d7e80'
  42. * @property {Boolean} fixed 是否固定在底部默认 true
  43. * @property {Boolean} placeholder fixed定位固定在底部时是否生成一个等高元素防止塌陷默认 true
  44. * @property {Object} customStyle 定义需要用到的外部样式
  45. *
  46. * @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>
  47. */
  48. export default {
  49. name: 'u-tabbar',
  50. mixins: [mpMixin, mixin, props],
  51. data() {
  52. return {
  53. placeholderHeight: 0
  54. }
  55. },
  56. computed: {
  57. tabbarStyle() {
  58. const style = {
  59. zIndex: this.zIndex
  60. }
  61. // 合并来自父组件的customStyle样式
  62. return deepMerge(style, addStyle(this.customStyle))
  63. },
  64. // 监听多个参数的变化,通过在computed执行对应的操作
  65. updateChild() {
  66. return [this.value, this.activeColor, this.inactiveColor]
  67. },
  68. updatePlaceholder() {
  69. return [this.fixed, this.placeholder]
  70. }
  71. },
  72. watch: {
  73. updateChild() {
  74. // 如果updateChildren中的元素发生了变化,则执行子元素初始化操作
  75. this.updateChildren()
  76. },
  77. updatePlaceholder() {
  78. // 如果fixed,placeholder等参数发生变化,重新计算占位元素的高度
  79. this.setPlaceholderHeight()
  80. }
  81. },
  82. created() {
  83. this.children = []
  84. },
  85. mounted() {
  86. this.setPlaceholderHeight()
  87. },
  88. methods: {
  89. updateChildren() {
  90. // 如果存在子元素,则执行子元素的updateFromParent进行更新数据
  91. this.children.length && this.children.map(child => child.updateFromParent())
  92. },
  93. // 设置用于防止塌陷元素的高度
  94. async setPlaceholderHeight() {
  95. if (!this.fixed || !this.placeholder) return
  96. // 延时一定时间
  97. await sleep(20)
  98. // #ifndef APP-NVUE
  99. this.$uGetRect('.u-tabbar__content').then(({height = 50}) => {
  100. // 修复IOS safearea bottom 未填充高度
  101. this.placeholderHeight = height
  102. })
  103. // #endif
  104. // #ifdef APP-NVUE
  105. dom.getComponentRect(this.$refs['u-tabbar__content'], (res) => {
  106. const {
  107. size
  108. } = res
  109. this.placeholderHeight = size.height
  110. })
  111. // #endif
  112. }
  113. }
  114. }
  115. </script>
  116. <style lang="scss" scoped>
  117. @import "../../libs/css/components.scss";
  118. .u-tabbar {
  119. @include flex(column);
  120. flex: 1;
  121. justify-content: center;
  122. &__content {
  123. @include flex(column);
  124. background-color: #fff;
  125. &__item-wrapper {
  126. height: 50px;
  127. @include flex(row);
  128. justify-content: space-around;
  129. }
  130. }
  131. &--fixed {
  132. position: fixed;
  133. bottom: 0;
  134. left: 0;
  135. right: 0;
  136. }
  137. }
  138. </style>