目录
目录
uniapp自定义tabBar方案
一、pages.json文件中添加tarBar
二、把原生的tabBar隐藏起来
三、自定义一个tabBar组件
四、全局引用组件
五、路由跳转
补充1:自定义switchTab跳转方法
补充2:在app中$route找不到的问题
六、相关代码
该方案,可以在切换tabBar的时候,路由也跟着变化,方便平时进行页面测试使用,不过有个缺点,第一次切换的时候会出现闪烁现象。
解决闪烁的问题:
1、可以把tabBar和页面组件都放在单页中用v-if判断,进行切换,单页切换的缺点是不能进行路由跳转(不能路由跳转)
2、把组件注入App.vue中,实现全局引用,但是uniapp不建议在App.vue中使用页面组件,也不要使用,不然出现各种问题,uniapp不能像vue那样在App.vue使用router-view实现选项卡功能(不推荐)
3、 所以要同时实现首次不闪烁,而且可以进行路由切换的功能,目前不知道如何处理。(未知)
首次加载闪烁,严格意义上说,可以被认定为bug。小编在想能不能用vue的路由方式去实现router-view呢?因此尝试的去自定义router-view,却发现uniapp内置了路由,当想用vue插件方式,重写路由时,发现冲突了。
其实关于自定义,在uniapp中,官方目前不推荐大家去自定义的,如果业务场景需要根据不同权限,显示不同tabBar,我们可以去跟需求谈,换另外一方式,也是可以的。例如用下图的方式
(方案还有需要完善的地方,这里仅供大家参考)
因为需要用到tabBar跳转,因此可以往原来的tabBar.list中多添加几个,用于做判断是否tabBar切换(这里可以只添加路径,icon和text可以不需要)
在App.vue中把原生的tabBar先隐藏起来
onLaunch: function() {
console.log('App Launch')
uni.hideTabBar()
},
在components中新建一个tabBar.vue的页面,用来封装组件
HTML代码,这里循环遍历自己定义的tabBar.list(可根据需求来定义)
{{item.text}}
data里面定义变量和循环列表,list即是自己定义的tabBar,和pages.json的tabBar写法一样
data() {
return {
selectedIndex: 0, // 标记
showselected: false, // 是否在页面使用tarBar
tabBar: {
list: [{
"pagePath": "pages/index/index",
"iconPath": "/static/tabIcon/icon1.png",
"selectedIconPath": "/static/tabIcon/icon2.png",
"text": "首页"
}, {
"pagePath": "pages/team/team",
"iconPath": "/static/tabIcon/icon3.png",
"selectedIconPath": "/static/tabIcon/icon4.png",
"text": "团队"
}, {
"pagePath": "pages/promotion/promotion",
"iconPath": "/static/tabIcon/icon5.png",
"selectedIconPath": "/static/tabIcon/icon6.png",
"text": "推广圈"
},
{
"pagePath": "pages/my/my",
"iconPath": "/static/tabIcon/icon7.png",
"selectedIconPath": "/static/tabIcon/icon8.png",
"text": "我的"
}
]
},
}
},
如果需要根据不同用户来渲染不同tabBar,可用vuex来保存tabBar的list列表
const user_1 = [{
"pagePath": "../pages/test/me",
"iconPath": "../static/xxx.png",
"selectedIconPath": "../static/xxx.png",
"text": "me"
}, {
"pagePath": "../pages/test/you",
"iconPath": "../static/xxx.png",
"selectedIconPath": "../static/xxx.png",
"text": "you"
}, {
"pagePath": "../pages/test/other",
"iconPath": "../static/xxx.png",
"selectedIconPath": "../static/xxx.png",
"text": "other"
},
]
const user_2 = [{
"pagePath": "../pages/test/our",
"iconPath": "../static/xxx.png",
"selectedIconPath": "../static/xxx.png",
"text": "our"
}, {
"pagePath": "../pages/test/his",
"iconPath": "../static/xxx.png",
"selectedIconPath": "../static/xxx.png",
"text": "his"
},
]
export default {
user_1,
user_1
}
往main.js注入组件
// main.js
import tabBar from 'components/tab-bar/tabBar.vue'
Vue.component('tab-bar',tabBar) //挂载
在每一个页面中引入
我是首页
我是推广圈页
我是团队页
tabBar定义成了组件,因此需要一个全局变量来判断它的切换和路由的跳转。
首先,进入到uniapp的官方tabBar源码中,可以看到这样一段代码,下面的这段代码,就是路由跳转的依据,把他复制到自己的组件中,进行改造。该监听方式只能在uniapp中有效,在app中无法监听,详情往下看【补充2】
watch: {
$route: {
immediate: true,
handler (to) {
if (to.meta.isTabBar) { // 判断是否属于tarBar
// this.__path__ = to.path
// 判断路由的路径和tarBar.list的pagePath是否相同,来确定一个全局的index
const index = this.list.findIndex(item => to.meta.pagePath === item.pagePath)
if (index > -1) {
this.selectedIndex = index // 标记是第几个tarBar
}
}
}
}
},
定义跳转的方法,这里用的是uni.switchTab进行跳转,不然url不会发生变化。注释掉的代码是官方的代码,这里是直接复制过来自己用。注:后续要使用switchTab进行跳转的话,就需要到自定义的方法,毕竟已经自定义了tabBar,跳转方式也需要自定义。自定义跳转方法请看文章后面的【补充1】
methods: {
switchTab(index, item) {
let url = '/' + item.pagePath
let pagePath = url
const detail = {
index,
pagePath
}
if (this.$route.path !== url) {
// this.__path__ = this.$route.path
uni.switchTab({
from: 'tabBar',
url,
detail
})
} else {
// UniServiceJSBridge.emit('onTabItemTap', detail)
}
this.selectedIndex = index
// this.$emit('switchTab', detail)
}
},
由于在子组件中已经存在switchTab方法,现只需做一下调整即可,先调整一下switchTab方法,如下:
/*
// 调整前
methods: {
switchTab(index, item) {
let url = '/' + item.pagePath
let pagePath = url
const detail = {
index,
pagePath
}
if (this.$route.path !== url) {
// this.__path__ = this.$route.path
uni.switchTab({
from: 'tabBar',
url,
detail
})
} else {
// UniServiceJSBridge.emit('onTabItemTap', detail)
}
this.selectedIndex = index
// this.$emit('switchTab', detail)
}
}, */
// 调整后,1、调换入参顺序,方便传值,2、循环判断一下index,
switchTab(item, index) {
let url = '/' + item.pagePath
let pagePath = url
const detail = {
index,
pagePath
}
if (this.$route.path !== url) {
// this.__path__ = this.$route.path
let s = uni.switchTab({
url,
detail
})
} else {
// UniServiceJSBridge.emit('onTabItemTap', detail)
}
this.tabBar.list.forEach((v, i) => {
if (item.pagePath === v.pagePath) {
this.selectedIndex = i
}
})
// this.$emit('switchTab', detail)
}
这里的index和item也要调换一下位置 ,@click="switchTab(item,index)"
index和item调换
{{item.text}}
父组件中使用ref="tabBar"来获取子组件
我是首页
通过方法来触发子组件方法即可, 对象中的pagePath是与tabBar.list数组里面的pagePath是对应的。
toMY() {
this.$refs.tabBar.switchTab({
pagePath:'pages/team/team'
})
},
打包到小程序之后,$route会像下面图片那样显示undefined,即在小程序中,是没有像$route这样的路由方式。那么,就不能用这样的方式,来监听index的变化。
如何解决?
利用uni.setStorageSync()全局保存一下点击tabBar的index即可,进入到tabBar.vue文件。
1、重写switchTab()方法
2、注释掉$route的监听。
3、调整data中定义的变量selectedIndex
最后进入App.vue文件中,清除一下selectedIndex的缓存,不在tabBar.vue的created生命周期清除selectedIndex的原因是:只希望,每次重新进入程序后重置,tabBar的高亮重新回到第一个,而不是每次进入页面的重置,而且每次进入页面重置,是有问题。
在App.vue中把原生的tabBar先隐藏起来和清除index
onLaunch: function() {
console.log('App Launch')
uni.removeStorageSync('selectedIndex'); // 清除缓存
uni.hideTabBar()
},
tabBar.vue
{{item.text}}
main.js注入组件
// main.js
import tabBar from 'components/tab-bar/tabBar.vue'
Vue.component('tab-bar',tabBar) //挂载
在每一个页面中引入
page/index.vue 首页
我是首页
我是推广圈页
我是团队页