123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446 |
- <template>
- <view class="m-tabbar-box" :style="tabbarBoxStyle" v-if="isShowTabBar">
- <view class="m-tabbar__fill" v-if="fill || native" :class="{'m-tabbar__safe': (safeBottom || native)}"
- :style="tabbarFillStyle"></view>
- <view id="m-tabbar" class="m-tabbar"
- :class="{'fixed': (fixed || native), 'm-tabbar__safe': (safeBottom || native)}" :style="tabbarStyle">
- <view class="m-tabbar__border" v-if="borderStyle === 'black' "></view>
- <view class="m-tabbar__flex">
- <view @click="tabChange(index)" v-for="(item, index) in tabbarList" :key="index" class="m-tabbar__item"
- :class="{
- 'm-tabbar__item__active': index === currentIndex,
- }">
- <slot :name="`tabbar_index_${index}`">
- <view class="m-tabbar__icon">
- <view class="m-tabbar__badge" v-if="item.dot">{{item.dot}}</view>
- <image :src="currentIndex === index ? item.selectedIconPath : item.iconPath"
- class="m-tabbar__icon_img" />
- </view>
- <view class="m-tabbar__label"
- :style="{'color': index === currentIndex ? tabbarConfig.selectedColor : tabbarConfig.color }">
- {{ item.text }}
- </view>
- </slot>
- </view>
- </view>
- </view>
- </view>
- </template>
- <script>
- const obj2strStyle = (obj) => {
- let style = ''
- for (let key in obj) {
- style += `${key}:${obj[key]};`
- }
- return style
- }
- const padFirstSymbol = (str, smb) => {
- if (str.startsWith(smb) || str.startsWith('http')) {
- return str
- }
- return `/${str}`
- }
- const replaceTabbarList = (list) => {
- if (!list.length > 0) {
- return []
- }
- return list.map(item => {
- if (item.iconPath) {
- item.iconPath = padFirstSymbol(item.iconPath, '/')
- }
- if (item.pagePath) {
- item.pagePath = padFirstSymbol(item.pagePath, '/')
- }
- if (item.selectedIconPath) {
- item.selectedIconPath = padFirstSymbol(item.selectedIconPath, '/')
- }
- return item
- })
- }
- import PageConfig from '@/pages.json'
- export default {
- emits: ['change', 'click'],
- props: {
- current: {
- type: [Number, String],
- default: 0
- },
- tabbar: {
- type: Object,
- default () {
- return {}
- }
- },
- fixed: {
- type: Boolean,
- default: false
- },
- fill: {
- type: Boolean,
- default: false
- },
- zIndex: {
- type: [Number, String],
- default: 9999
- },
- native: {
- type: Boolean,
- default: false
- },
- safeBottom: {
- type: Boolean,
- default: true
- },
- beforeChange: {
- type: Function,
- default: null
- },
- tabbarHeight: {
- type: [Number, String],
- default: 100
- }
- },
- data() {
- return {
- isShowTabBar: false,
- currentIndex: 0,
- beforeData: {},
- reload: false
- }
- },
- watch: {
- current(val) {
- this.currentIndex = val * 1
- }
- },
- computed: {
- tabbarConfig() {
- const {
- native,
- reload
- } = this
- if (reload) {}
- if (native) {
- const {
- tabBar
- } = PageConfig
- if (!tabBar) {
- console.error('Native mode, Pages.json no tabbar config')
- return {
- borderStyle: 'black',
- list: []
- }
- }
- return tabBar
- }
- return this.tabbar
- },
- tabbarList() {
- const {
- reload
- } = this
- const {
- list
- } = this.tabbarConfig
- if (reload) {}
- if (list) {
- return replaceTabbarList(list)
- }
- console.error('No tabbar config')
- return []
- },
- borderStyle() {
- const {
- reload
- } = this
- const {
- borderStyle
- } = this.tabbarConfig
- if (reload) {}
- return borderStyle
- },
- tabbarBoxStyle() {
- const {
- zIndex,
- reload
- } = this
- if (reload) {}
- return obj2strStyle({
- 'z-index': zIndex,
- })
- },
- tabbarFillStyle() {
- const {
- tabbarHeight,
- safeBottom,
- reload
- } = this
- if (reload) {}
- return obj2strStyle({
- 'height': `${tabbarHeight}rpx`
- })
- },
- tabbarStyle() {
- const {
- tabbarHeight,
- reload
- } = this
- const {
- backgroundColor
- } = this.tabbarConfig
- if (reload) {}
- return obj2strStyle({
- 'height': `${tabbarHeight}rpx`,
- 'background-color': backgroundColor || '#fff',
- })
- },
- tabbarItemStyle() {
- const {
- currentIndex,
- reload
- } = this
- const {
- color,
- selectedColor
- } = this.tabbarConfig
- if (reload) {}
- return obj2strStyle({
- 'color': currentIndex ? selectedColor : color
- })
- }
- },
- mounted() {
- this.initTabbar()
- },
- methods: {
- initTabbar() {
- const {
- current,
- fill,
- native,
- tabbarList
- } = this
- this.currentIndex = current * 1
- if (native) {
- const currentPage = `/${getCurrentPages()[0].route}`
- const currentIndex = tabbarList.findIndex(item => item.pagePath === currentPage)
- this.currentIndex = currentIndex
- if (tabbarList.length > 0) {
- uni.hideTabBar()
- }
- }
- setTimeout(() => {
- this.isShowTabBar = true
- })
- },
- reLoad() {
- this.reload = true
- setTimeout(() => {
- this.reload = false
- })
- },
- checkMaxIndex(index) {
- if (!this.tabbarConfig.list[index]) {
- console.error('Max tabbar index')
- return false
- }
- return true
- },
- setTabBarBadge(obj) {
- const {
- index,
- text
- } = obj
- if (this.checkMaxIndex(index)) {
- this.tabbarConfig.list[index].dot = text
- this.reLoad()
- }
- },
- setTabBarItem(obj) {
- const {
- index,
- text,
- pagePath: newPagePath,
- iconPath,
- selectedIconPath
- } = obj
- const {
- pagePath: oldPagePath
- } = this.tabbarConfig.list[index]
- if (this.checkMaxIndex(index)) {
- this.tabbarConfig.list[index] = {
- pagePath: newPagePath ? newPagePath : oldPagePath,
- text,
- iconPath,
- selectedIconPath
- }
- this.reLoad()
- }
- },
- showTabBar() {
- this.isShowTabBar = true
- },
- hideTabBar() {
- this.isShowTabBar = false
- },
- tabChange(index) {
- const {
- currentIndex
- } = this
- this.$emit('click', index)
- if (index === currentIndex) {
- return
- }
- this.beforeData = {
- newIndex: index,
- oldIndex: currentIndex,
- next: this.jumpPage
- }
- if (this.beforeChange) {
- this.beforeChange(this.jumpPage)
- } else {
- this.jumpPage()
- }
- },
- jumpPage() {
- const {
- native,
- beforeData,
- tabbarList: list
- } = this
- const {
- newIndex: index
- } = beforeData
- const {
- pagePath: url,
- openType
- } = list[index]
- if (url) {
- if (native) {
- uni.switchTab({
- url
- })
- } else {
- if (openType !== 'navigate') {
- this.currentIndex = index
- }
- switch (openType) {
- case 'navigate':
- uni.navigateTo({
- url
- })
- break;
- case 'redirect':
- uni.redirectTo({
- url
- })
- break;
- case 'reLaunch':
- uni.reLaunch({
- url
- })
- break;
- case 'switchTab':
- uni.switchTab({
- url
- })
- break;
- case 'navigateBack':
- uni.navigateBack({
- delta: 1
- })
- break;
- default:
- uni.reLaunch({
- url
- })
- }
- }
- }
- this.$emit('change', index)
- }
- }
- };
- </script>
- <style lang="scss" scoped>
- .m-tabbar-box {
- position: relative;
- z-index: 9999;
- }
- .m-tabbar {
- position: relative;
- &.fixed {
- position: fixed;
- bottom: 0;
- left: 0;
- width: 100vw;
- }
- &__safe {
- padding-bottom: env(safe-area-inset-bottom);
- }
- }
- .m-tabbar__fill {
- pointer-events: none;
- opacity: 0;
- }
- .m-tabbar__flex {
- display: flex;
- flex-direction: row;
- }
- .m-tabbar__border {
- background-color: rgba(0, 0, 0, 0.33);
- width: 100%;
- height: 1rpx;
- transform: scaleY(0.5);
- }
- .m-tabbar__item {
- display: flex;
- flex-direction: column;
- align-items: center;
- flex: 1;
- padding: 4px 0 2px;
- }
- .m-tabbar__icon {
- width: 48rpx;
- height: 48rpx;
- margin-bottom: 6rpx;
- position: relative;
- &_img {
- display: block;
- width: 100%;
- height: 100%;
- }
- .m-tabbar__badge {
- color: #fff;
- background-color: #f00;
- border-radius: 20rpx;
- font-size: 22rpx;
- position: absolute;
- right: -25rpx;
- left: 40rpx;
- padding: 2rpx 0;
- width: 100%;
- text-align: center;
- white-space: nowrap;
- }
- }
- .m-tabbar__label {
- font-size: 24rpx;
- }
- </style>
|