u-tabbar-item.vue 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. <template>
  2. <view
  3. class="u-tabbar-item"
  4. @tap="clickHandler"
  5. >
  6. <view class="u-tabbar-item__content" :class="[`u-tabbar-item__content--${parentData.mode}`]" :style="[contentStyle]">
  7. <view
  8. class="u-tabbar-item__icon"
  9. :class="{'u-tabbar-item__icon--middle': middle}"
  10. :style="[{backgroundColor: middle && iconBgColor}]"
  11. >
  12. <u-icon
  13. v-if="icon"
  14. :name="icon"
  15. :color="middle ? iconColor : (isActive ? parentData.activeColor : parentData.inactiveColor)"
  16. :size="iconSize"
  17. ></u-icon>
  18. <slot v-if="isActive" name="active-icon"/>
  19. <slot v-else name="inactive-icon"/>
  20. <u-badge
  21. absolute
  22. :offset="[0, dot ? '34rpx' : badge > 9 ? '14rpx' : '20rpx']"
  23. :customStyle="badgeStyle"
  24. :isDot="dot"
  25. :value="badge || (dot ? 1 : null)"
  26. :show="dot || badge > 0"
  27. ></u-badge>
  28. </view>
  29. <view v-if="middle && text" :style="{height: baseIconSize + 'px'}"></view>
  30. <slot name="text">
  31. <text
  32. v-if="text"
  33. class="u-tabbar-item__text"
  34. :style="[{
  35. color: isActive? parentData.activeColor : parentData.inactiveColor
  36. }]"
  37. >{{ text }}</text>
  38. </slot>
  39. </view>
  40. </view>
  41. </template>
  42. <script>
  43. import props from './props.js';
  44. import mixin from '../../libs/mixin/mixin'
  45. import mpMixin from '../../libs/mixin/mpMixin';
  46. /**
  47. * TabbarItem 底部导航栏子组件
  48. * @description 此组件提供了自定义tabbar的能力。
  49. * @tutorial https://uview.d3u.cn/components/tabbar.html
  50. * @property {String | Number} name item标签的名称,作为与u-tabbar的value参数匹配的标识符
  51. * @property {String} icon uView内置图标或者绝对路径的图片
  52. * @property {String | Number} badge 右上角的角标提示信息
  53. * @property {Boolean} dot 是否显示圆点,将会覆盖badge参数(默认 false )
  54. * @property {String} text 描述文本
  55. * @property {Object | String} badgeStyle 控制徽标的位置,对象或者字符串形式,可以设置top和right属性(默认 'top: 6px;right:2px;' )
  56. * @property {Object} customStyle 定义需要用到的外部样式
  57. *
  58. * @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>
  59. */
  60. export default {
  61. name: 'u-tabbar-item',
  62. mixins: [mpMixin, mixin, props],
  63. data() {
  64. return {
  65. isActive: false, // 是否处于激活状态
  66. baseIconSize: 20,
  67. parentData: {
  68. value: null,
  69. mode: 'normal',
  70. activeColor: '',
  71. inactiveColor: ''
  72. }
  73. }
  74. },
  75. computed:{
  76. contentStyle() {
  77. let style = {};
  78. if(this.isActive && this.parentData.mode === 'tag') {
  79. style.backgroundColor = uni.$u.colorToRgba(this.parentData.activeColor, 0.15);
  80. }
  81. return style;
  82. }
  83. },
  84. created() {
  85. this.init()
  86. },
  87. // #ifdef VUE3
  88. emits: ["click"],
  89. // #endif
  90. methods: {
  91. init() {
  92. // 支付宝小程序不支持provide/inject,所以使用这个方法获取整个父组件,在created定义,避免循环引用
  93. this.updateParentData()
  94. if (!this.parent) {
  95. uni.$u.error('u-tabbar-item必须搭配u-tabbar组件使用')
  96. }
  97. // 本子组件在u-tabbar的children数组中的索引
  98. const index = this.parent.children.indexOf(this)
  99. for(let i = 0; i < this.parent.children.length; i++) {
  100. if(!this.parent.children[i].middle) {
  101. this.baseIconSize = this.parent.children[i].iconSize
  102. break
  103. }
  104. }
  105. // 判断本组件的name(如果没有定义name,就用index索引)是否等于父组件的value参数
  106. this.isActive = (this.name || index) === this.parentData.value
  107. },
  108. updateParentData() {
  109. // 此方法在mixin中
  110. this.getParentData('u-tabbar')
  111. },
  112. // 此方法将会被父组件u-tabbar调用
  113. updateFromParent() {
  114. // 重新初始化
  115. this.init()
  116. },
  117. clickHandler() {
  118. this.$nextTick(() => {
  119. const index = this.parent.children.indexOf(this)
  120. const name = this.name || index
  121. // 点击的item为非激活的item才发出change事件
  122. if (name !== this.parent.value) {
  123. this.parent.onChange(name)
  124. }
  125. this.$emit('click', name)
  126. // 如果配置了url(此props参数通过mixin引入)参数,跳转页面
  127. this.openPage();
  128. })
  129. }
  130. },
  131. }
  132. </script>
  133. <style lang="scss" scoped>
  134. @import "../../libs/css/components.scss";
  135. .u-tabbar-item {
  136. @include flex(column);
  137. align-items: center;
  138. justify-content: center;
  139. flex: 1;
  140. padding: 10px;
  141. &__content{
  142. @include flex(column);
  143. align-items: center;
  144. justify-content: center;
  145. flex: 1;
  146. width: 60px;
  147. /* #ifdef H5 */
  148. cursor: pointer;
  149. /* #endif */
  150. &--tag{
  151. border-radius: 100px;
  152. }
  153. }
  154. &__icon {
  155. @include flex;
  156. position: relative;
  157. justify-content: center;
  158. &--middle{
  159. width: 40px;
  160. height: 40px;
  161. position: absolute;
  162. top: -20px;
  163. z-index: 999;
  164. border-radius: 100px;
  165. box-shadow: 0 -1px 4px rgba(0, 0, 0, 0.1);
  166. }
  167. }
  168. &__text {
  169. margin-top: 2px;
  170. font-size: 12px;
  171. color: $u-content-color;
  172. }
  173. }
  174. /* #ifdef MP */
  175. // 由于小程序都使用shadow DOM形式实现,需要给影子宿主设置flex: 1才能让其撑开
  176. :host {
  177. flex: 1
  178. }
  179. /* #endif */
  180. </style>