tabBar.vue 11.3 KB
Newer Older
fxy060608's avatar
fxy060608 已提交
1
<template>
fxy060608's avatar
fxy060608 已提交
2
  <uni-tabbar :class="['uni-tabbar-'+position]">
3 4 5 6 7 8
    <div
      :style="{
        backgroundColor:tabbarBackgroundColor,
        'backdrop-filter':blurEffect !== 'none' ? 'blur(10px)' : blurEffect
      }"
      class="uni-tabbar"
fxy060608's avatar
fxy060608 已提交
9
    >
10 11 12
      <div
        :style="{backgroundColor:borderColor}"
        class="uni-tabbar-border"
fxy060608's avatar
fxy060608 已提交
13
      />
14
      <div
15
        v-for="(item,index) in visibleList"
16
        :key="item.isMidButton ? index : item.pagePath"
17
        :style="item.isMidButton ? {flex:'0 0 ' + item.width,position:'relative'} : {}"
18 19
        class="uni-tabbar__item"
        @click="_switchTab(item,index)"
Q
qiang 已提交
20
      >
21 22 23 24 25 26 27
        <!-- midButton iconPath -->
        <div
          v-if="item.isMidButton"
          class="uni-tabbar__mid"
          :style="_uniTabbarBdStyle(item)"
        >
          <img
28
            v-if="item.iconPath"
29 30
            :style="{width: item.iconWidth,height:item.iconWidth}"
            :src="_getRealPath(item.iconPath)"
Q
qiang 已提交
31
          >
32 33 34 35 36 37 38
        </div>
        <!-- tabbar button -->
        <div
          class="uni-tabbar__bd"
          :style="{height:height}"
        >
          <div
d-u-a's avatar
d-u-a 已提交
39
            v-if="getIconPath(item,index) || item.iconfont || item.iconPath || item.isMidButton"
40 41 42
            :class="{'uni-tabbar__icon__diff':!item.text}"
            class="uni-tabbar__icon"
            :style="{width: iconWidth,height:iconWidth}"
D
DCloud_LXH 已提交
43 44 45 46 47 48 49 50 51 52
          >
            <div
              v-if="item.iconfont"
              :style="{
                color:selectedIndex === index ? item.iconfont.selectedColor : item.iconfont.color,
                fontSize: item.iconfont.fontSize || iconWidth
              }"
              class="uni-tabbar__iconfont"
            >
              {{ selectedIndex === index ? item.iconfont.selectedText : item.iconfont.text }}
d-u-a's avatar
d-u-a 已提交
53
            </div>
54
            <img
d-u-a's avatar
d-u-a 已提交
55
              v-else-if="!item.isMidButton"
56
              :src="_getRealPath(getIconPath(item,index))"
57
            >
fxy060608's avatar
fxy060608 已提交
58
          </div>
59 60 61 62 63 64 65 66 67
          <div
            v-if="item.text"
            :style="{
              color:selectedIndex === index ? selectedColor : color,
              fontSize: fontSize,
              lineHeight: !item.iconPath ? 1.8 : 'normal',
              marginTop: !item.iconPath ? 'inherit' : spacing
            }"
            class="uni-tabbar__label"
Q
qiang 已提交
68
          >
fxy060608's avatar
fxy060608 已提交
69
            {{ item.text }}
70 71 72 73 74 75 76
          </div>
          <div
            v-if="item.redDot"
            :class="{'uni-tabbar__badge':!!item.badge}"
            class="uni-tabbar__reddot"
          >
            {{ item.badge }}
fxy060608's avatar
fxy060608 已提交
77 78 79 80
          </div>
        </div>
      </div>
    </div>
81 82 83 84
    <div
      class="uni-placeholder"
      :style="{height:height}"
    />
fxy060608's avatar
fxy060608 已提交
85 86 87 88
  </uni-tabbar>
</template>

<style>
fxy060608's avatar
fxy060608 已提交
89 90 91 92 93 94
  uni-tabbar {
    display: block;
    box-sizing: border-box;
    width: 100%;
    z-index: 998;
  }
fxy060608's avatar
fxy060608 已提交
95

fxy060608's avatar
fxy060608 已提交
96 97 98 99 100
  uni-tabbar .uni-tabbar {
    display: flex;
    z-index: 998;
    box-sizing: border-box;
  }
fxy060608's avatar
fxy060608 已提交
101

fxy060608's avatar
fxy060608 已提交
102 103 104 105 106 107 108 109
  uni-tabbar.uni-tabbar-top,
  uni-tabbar.uni-tabbar-bottom,
  uni-tabbar.uni-tabbar-top .uni-tabbar,
  uni-tabbar.uni-tabbar-bottom .uni-tabbar {
    position: fixed;
    left: var(--window-left);
    right: var(--window-right);
  }
fxy060608's avatar
fxy060608 已提交
110

fxy060608's avatar
fxy060608 已提交
111 112 113 114 115 116 117 118
  .uni-app--showlayout+uni-tabbar.uni-tabbar-top,
  .uni-app--showlayout+uni-tabbar.uni-tabbar-bottom,
  .uni-app--showlayout+uni-tabbar.uni-tabbar-top .uni-tabbar,
  .uni-app--showlayout+uni-tabbar.uni-tabbar-bottom .uni-tabbar {
    left: var(--window-margin);
    right: var(--window-margin);
  }

fxy060608's avatar
fxy060608 已提交
119 120 121 122 123 124
  uni-tabbar.uni-tabbar-bottom .uni-tabbar {
    bottom: 0;
    padding-bottom: 0;
    padding-bottom: constant(safe-area-inset-bottom);
    padding-bottom: env(safe-area-inset-bottom);
  }
fxy060608's avatar
fxy060608 已提交
125

fxy060608's avatar
fxy060608 已提交
126 127 128 129 130 131
  uni-tabbar .uni-tabbar~.uni-placeholder {
    width: 100%;
    margin-bottom: 0;
    margin-bottom: constant(safe-area-inset-bottom);
    margin-bottom: env(safe-area-inset-bottom);
  }
fxy060608's avatar
fxy060608 已提交
132

fxy060608's avatar
fxy060608 已提交
133 134 135
  uni-tabbar .uni-tabbar * {
    box-sizing: border-box;
  }
fxy060608's avatar
fxy060608 已提交
136

fxy060608's avatar
fxy060608 已提交
137 138 139 140 141 142 143 144 145 146
  uni-tabbar .uni-tabbar__item {
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    flex: 1;
    font-size: 0;
    text-align: center;
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
  }
fxy060608's avatar
fxy060608 已提交
147

fxy060608's avatar
fxy060608 已提交
148 149 150 151 152 153 154 155
  uni-tabbar .uni-tabbar__bd {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    cursor: pointer;
  }
156

fxy060608's avatar
fxy060608 已提交
157 158 159 160 161
  uni-tabbar .uni-tabbar__icon {
    position: relative;
    display: inline-block;
    margin-top: 5px;
  }
fxy060608's avatar
fxy060608 已提交
162

fxy060608's avatar
fxy060608 已提交
163 164 165 166 167
  uni-tabbar .uni-tabbar__icon.uni-tabbar__icon__diff {
    margin-top: 0px;
    width: 34px;
    height: 34px;
  }
fxy060608's avatar
fxy060608 已提交
168

fxy060608's avatar
fxy060608 已提交
169 170 171
  uni-tabbar .uni-tabbar__icon img {
    width: 100%;
    height: 100%;
D
DCloud_LXH 已提交
172 173 174 175
  }

  uni-tabbar .uni-tabbar__iconfont {
    font-family: 'UniTabbarIconFont';
fxy060608's avatar
fxy060608 已提交
176
  }
fxy060608's avatar
fxy060608 已提交
177

fxy060608's avatar
fxy060608 已提交
178 179 180 181 182
  uni-tabbar .uni-tabbar__label {
    position: relative;
    text-align: center;
    font-size: 10px;
  }
fxy060608's avatar
fxy060608 已提交
183

fxy060608's avatar
fxy060608 已提交
184 185 186 187 188 189 190 191 192 193 194
  uni-tabbar .uni-tabbar-border {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 1px;
    transform: scaleY(0.5);
  }

  uni-tabbar .uni-tabbar__reddot {
    position: absolute;
195
    top: 2px;
fxy060608's avatar
fxy060608 已提交
196 197 198 199 200 201
    right: 0;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background-color: #f43530;
    color: #ffffff;
202
    transform: translate(40%, 0%);
fxy060608's avatar
fxy060608 已提交
203 204 205 206 207 208 209 210 211 212 213 214 215
  }

  uni-tabbar .uni-tabbar__badge {
    width: auto;
    height: 16px;
    line-height: 16px;
    border-radius: 16px;
    min-width: 16px;
    padding: 0 2px;
    font-size: 12px;
    text-align: center;
    white-space: nowrap;
  }
216 217 218 219 220 221 222 223

  uni-tabbar .uni-tabbar__mid {
    display: flex;
    justify-content: center;
    position: absolute;
    bottom: 0;
    background-size: 100% 100%;
  }
fxy060608's avatar
fxy060608 已提交
224 225 226 227
</style>

<script>
import getRealPath from 'uni-platform/helpers/get-real-path'
228
import { isPlainObject } from 'uni-shared'
D
DCloud_LXH 已提交
229
import { publish } from 'uni-platform/service/bridge'
d-u-a's avatar
d-u-a 已提交
230
import { loadFontFace } from 'uni-core/view/bridge/subscribe/font'
231
function cssSupports (css) {
232
  return window.CSS && CSS.supports && (CSS.supports(css) || CSS.supports.apply(CSS, css.split(':')))
D
DCloud_LXH 已提交
233
}
d-u-a's avatar
d-u-a 已提交
234
const UNI_TABBAR_ICON_FONT = 'UniTabbarIconFont'
fxy060608's avatar
fxy060608 已提交
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
export default {
  name: 'TabBar',
  props: {
    position: {
      default: 'bottom',
      validator (value) {
        return ['bottom', 'top'].indexOf(value) !== -1
      }
    },
    color: {
      type: String,
      default: '#999'
    },
    selectedColor: {
      type: String,
      default: '#007aff'
    },
    backgroundColor: {
      type: String,
254
      default: ''
fxy060608's avatar
fxy060608 已提交
255 256
    },
    borderStyle: {
257 258
      type: String,
      default: 'black'
D
DCloud_LXH 已提交
259 260 261 262
    },
    iconfontSrc: {
      type: String,
      default: ''
fxy060608's avatar
fxy060608 已提交
263 264 265 266 267 268
    },
    list: {
      type: Array,
      default: function () {
        return []
      }
fxy060608's avatar
fxy060608 已提交
269 270 271 272 273 274
    },
    matchMedia: {
      type: Object,
      default: function () {
        return {}
      }
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
    },
    blurEffect: {
      type: String,
      default: 'none'
    },
    fontSize: {
      type: String,
      default: '10px'
    },
    iconWidth: {
      type: String,
      default: '24px'
    },
    spacing: {
      type: String,
      default: '3px'
    },
    height: {
      type: String,
      default: '50px'
    },
    midButton: {
      type: Object,
      default: null
fxy060608's avatar
fxy060608 已提交
299 300 301 302
    }
  },
  data () {
    return {
303
      selectedIndex: 0,
D
DCloud_LXH 已提交
304 305
      visibleList: [],
      internalMidButton: {}
fxy060608's avatar
fxy060608 已提交
306 307 308
    }
  },
  computed: {
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
    tabbarBackgroundColor () {
      // 背景色 区分 高斯模糊 分别返回
      const DefaultBgColor = '#f7f7fa'

      if (this.backgroundColor) return this.backgroundColor

      if (cssSupports('backdrop-filter:blur(10px)') && this.blurEffect !== 'none') {
        if (this.blurEffect === 'dark') {
          return 'rgb(0, 0, 0, 0.8)'
        }

        if (['light', 'extralight'].includes(this.blurEffect)) {
          return 'rgb(250, 250, 250, 0.8)'
        }
      }

      return DefaultBgColor
    },
fxy060608's avatar
fxy060608 已提交
327
    borderColor () {
328 329 330 331
      // 不再限制可配置颜色值
      if (this.borderStyle === 'white') return 'rgba(255, 255, 255, 0.33)'
      if (this.borderStyle === 'black') return 'rgba(0, 0, 0, 0.33)'
      return this.borderStyle
fxy060608's avatar
fxy060608 已提交
332 333 334
    }
  },
  watch: {
fxy060608's avatar
fxy060608 已提交
335 336
    $route: {
      immediate: true,
337 338 339 340 341 342 343 344 345 346 347
      handler () {
      // 只在此做一次 visibleList 的初始化
        if (!this.visibleList.length) this._initVisibleList()
        this.setSelectedIndex()
      }
    },
    list: {
      deep: true,
      handler () {
        this._initVisibleList()
        this.setSelectedIndex()
fxy060608's avatar
fxy060608 已提交
348
      }
D
DCloud_LXH 已提交
349 350 351
    },
    midButton (config) {
      this._initVisibleList()
fxy060608's avatar
fxy060608 已提交
352 353
    }
  },
354
  created () {
355 356 357 358
    this.list.forEach(item => {
      if (item.visible === undefined) {
        this.$set(item, 'visible', true)
      }
D
DCloud_LXH 已提交
359 360 361 362 363 364 365 366 367
    })

    if (this.iconfontSrc) {
      loadFontFace({
        options: {
          family: UNI_TABBAR_ICON_FONT,
          source: `url("${this.iconfontSrc}")`
        }
      })
368
    }
369
  },
fxy060608's avatar
fxy060608 已提交
370 371 372 373
  beforeCreate () {
    this.__path__ = this.$route.path
  },
  methods: {
374 375 376 377 378 379 380 381 382 383 384 385 386 387
    getIconPath (item, index) {
      return (this.selectedIndex === index ? item.selectedIconPath || item.iconPath : item.iconPath) || ''
    },
    setSelectedIndex () {
      if (this.$route.meta.isTabBar) {
        this.__path__ = this.$route.path
        const index = this.visibleList.findIndex(item => this.$route.meta.pagePath === item.pagePath)
        this.selectedIndex = index
      }
    },
    _initVisibleList () {
      this.visibleList = this._initMidButton(this.list.filter(item => item.visible !== false))
    },
    _getRealPath (filePath = '') {
388 389 390 391 392
      const SCHEME_RE = /^([a-z-]+:)?\/\//i
      const DATA_RE = /^data:.*,.*/
      if (!(SCHEME_RE.test(filePath) || DATA_RE.test(filePath)) && filePath.indexOf('/') !== 0) {
        filePath = '/' + filePath
      }
fxy060608's avatar
fxy060608 已提交
393 394 395 396
      return getRealPath(filePath)
    },
    _switchTab ({
      text,
397 398
      pagePath,
      isMidButton = false
fxy060608's avatar
fxy060608 已提交
399
    }, index) {
400 401 402 403
      if (isMidButton) {
        publish('onTabBarMidButtonTap')
        return
      }
fxy060608's avatar
fxy060608 已提交
404
      this.selectedIndex = index
fxy060608's avatar
fxy060608 已提交
405 406 407
      let url = '/' + pagePath
      if (url === __uniRoutes[0].alias) {
        url = '/'
Q
qiang 已提交
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422
      }
      const detail = {
        index,
        text,
        pagePath
      }
      if (this.$route.path !== url) {
        this.__path__ = this.$route.path
        uni.switchTab({
          from: 'tabBar',
          url,
          detail
        })
      } else {
        UniServiceJSBridge.emit('onTabItemTap', detail)
fxy060608's avatar
fxy060608 已提交
423
      }
424
    },
425 426
    _initMidButton (list) {
      const listLength = list.length
427 428
      // 偶数则添加midButton
      if (listLength % 2 === 0 && isPlainObject(this.midButton)) {
D
DCloud_LXH 已提交
429 430 431 432 433 434 435 436 437 438
        this.internalMidButton = Object.assign(
          {
            width: '50px',
            height: '50px',
            iconWidth: '24px'
          },
          this.internalMidButton,
          this.midButton
        )
        list.splice(~~(listLength / 2), 0, Object.assign({}, this.internalMidButton, { isMidButton: true }))
439
      }
440
      return list
441 442 443 444 445 446 447
    },
    _uniTabbarBdStyle (item) {
      return Object.assign({}, {
        width: item.width,
        height: item.height,
        backgroundImage: item.backgroundImage ? 'url(\'' + this._getRealPath(item.backgroundImage) + '\')' : ''
      })
fxy060608's avatar
fxy060608 已提交
448 449 450
    }
  }
}
451
</script>