uniapp-自定义底部切换栏

举报
林太白 发表于 2025/03/31 14:37:37 2025/03/31
【摘要】 uniapp-自定义底部切换栏

uniapp-自定义底部切换栏

自定义底部切换栏

首先我们必须清楚一个小的配置

要去掉默认的导航栏,即设置navigationStyle为custom;

预览

最后写出来的方式可以看出来最后就是这个样子

image.png

导航栏参数解析

🐟 globalStyle:默认页面的窗口表现

我们看到底部导航栏上面有个添加的这种特殊的标记,一般我们是没办法直接在tabBar之中进行配置的,这个时候我们就只能自己进行定义开发一个特殊类型的导航栏

想要自定义导航栏,那么我们就需要自己进行定义配置,先认识一下简单的参数

  • "path": "pages/user/user":页面路径。
  • "navigationBarTitleText": "我的":设置页面标题,在使用自定义导航栏的时候这个属性不会生效。
  • "enablePullDownRefresh": false:禁用下拉刷新功能。
  • "navigationStyle": "custom":启用自定义导航栏

所以我们首页正常就是这样子

{
    "path": "pages/tabBar/index/index",
    "style": {
            "navigationBarTitleText": "首页",
            "enablePullDownRefresh": false,
            "navigationStyle": "custom"
    }
},

这里我们使用tabbar告诉微信哪些页面属于tabbar页面,也可以同时在这些页面使用switchBar

自定义导航栏实现

接下来我们建立一个fooBar 组件,然后在我们的页面之中直接引用

component =>fooBar=> import('@/components/fooBar/fooBar.vue')

vue2写法

vue2+webpack

之前我们在vue2之中结合webpack的方式可能是这样子的

<script>
export default {
  props: {
    /* 当前导航栏 */
    currPage: {
      type: Number,
      default: 0
    }
  },
  data() {
    return {
      curItem: 0, // 当前所选导航栏
	  // 导航栏列表
      tabbarList: [
        {
          id: 0,
          pagePath: "/pages/tabBar/index/index",
          iconPath: "/static/tabBar/home.png",
          selectedIconPath: "/static/tabbar/homeact.png",
          text: "首页",
          centerItem: false
        },
		{
		  id: 1,
		  pagePath: "/pages/tabBar/center/center",
		  iconPath: "/static/tabbar/center.png",
		  selectedIconPath: "/static/tabbar/centeract.png",
		  text: "分类",
		  centerItem: false
		},
		{
		  id: 2,
		  pagePath: "/pages/tabBar/tougao/index",
		  iconPath: "/static/tabBar/tougaoact.png",
		  selectedIconPath: "/static/tabBar/tougao.png",
		  text: "发布",
		  centerItem: true
		},
		{
		  id: 3,
		  pagePath: "pages/tabBar/list/list",
		  iconPath: "/static/tabbar/find.png",
		  selectedIconPath: "/static/tabbar/findact.png",
		  text: "榜单",
		  centerItem: false
		},
        {
          id: 4,
          pagePath: "/pages/tabBar/user/user",
          iconPath: "/static/tabbar/user.png",
          selectedIconPath: "/static/tabbar/useract.png",
          text: "我的",
          centerItem: false
        },
      ] 
    };
  },
  mounted() {
    this.curItem = this.currPage; // 当前所选导航栏
    // #ifdef H5
    uni.hideTabBar(); // 隐藏 tabBar 导航栏
    // #endif
  },
  methods: {
    /* 导航栏切换 */
    changeItem(e) {
		console.log('点击',e);
      // 中间凸起按钮
      if (e.id === 1) {
        // todo
        return;
      }
      uni.switchTab({ url: e.pagePath }); // 跳转到其他 tab 页面
    }
  }
};
</script>

vue3写法

自定义底部切换栏

vue3+vite

之前我们的底部切换栏采用的是vue2的方式写法,接下来我们就实现并且更换成vue3+vite的方式

uni.switchTab(OBJECT)的作用 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。

//方式一 函数类型式跳转
 function changeItem(e) {
     console.log(e,'.target.value');
     console.log(e.id,'.target.value');
	
    // 中间凸起按钮
     if (e.id === 2) {
       // todo
       return;
     }
     uni.switchTab({ url:e.pagePath }); // 跳转到其他 tab 页面
}
//方式二  箭头类型式跳转
const changeItem = (e) => {
	console.log(e,'.target.value');
	console.log(e.id,'.target.value');
	if (e.id === 2) {
		  // todo
		  return;
	}
  uni.switchTab({
    url: e.pagePath,
  });
};

封装组件

现在我们可以看到,点击出来的本质其实是这个页面,那么如何进行底部切换或者说隐藏底部菜单呢

接下来我们封装并作出一些优化,让这个底部切换栏组件化,让我们的底部菜单栏更加的贴合现在我们使用

去掉底部菜单栏

首先,我们给写成一个组件,在每个页面加载的时候去掉显示的底部菜单栏,那么方法就是加载的时候隐藏菜单,这里需要注意‘引入的地方’

import { onLoad } from "@dcloudio/uni-app";
 onLoad(() => {
    uni.hideTabBar();
 });

进行每个页面的组件传值和引入

<foo-bar :current="1"></foo-bar>
<foo-bar :current="2"></foo-bar>
<foo-bar :current="3"></foo-bar>
<foo-bar :current="4"></foo-bar>
 function changeNav(index) {
    console.log("底部导航:", index);
}

当我们需要切换底部监听栏的时候使用

<foo-bar :current="5" @change="changeNav"></foo-bar>

生命周期处理

生命周期问题

接下来我们尝试一下

点击分类,这里我们显示正常,可是点击榜单怎么回事呢

image.png

第一次点击榜单的时候我们这里没反应,只有第二次点击才能传过去

image.png

这是怎么回事呢,这里我们再次看一下uniapp之中vue3之中的生命周期

在 Vue 3 中使用 UniApp 时,UniApp 提供了类似小程序的生命周期钩子,比如 onShowonLoad

我们分析一下它们的优先级和触发时机:

  1. onLoad 生命周期钩子
    • onLoad 生命周期钩子在页面加载时触发,就是页面首次加载时执行。
    • 一般用于页面初始化(数据加载、参数解析)。
  2. onShow 生命周期钩子
    • onShow 生命周期钩子在页面显示时触发,包括页面首次加载时也会触发。
    • 当页面被切换到前台时(比如从其他页面返回到当前页面),也会触发 onShow 方法,也就是处理(每次显示更新的数据和刷新)

优先级和触发时机的关系

  • 在页面首次加载时,onLoad 钩子首先触发,用于页面的初始化。
  • 随后页面显示时(比如从其他页面返回),会依次触发 onShow 钩子,用于处理页面每次显示时需要执行的逻辑。

因此, onLoad 用于页面初始化完成然后 onShow 展示执行

onLoad 生命周期剖析

这里用白话文解释一下onLoad执行的整个过程,结合vue的v-if的销毁来进行理解:

// 加载
onLoad(() => {
  uni.hideTabBar();
});

当我们第一次点击的时候

组件进行了赋值操作curItem.value=e.id; 这个时候进行了切换``uni.switchTab() 方式来创建组件,这个时候组件刚刚加载出来,所以组件此刻的状态其实还是在上次状态中

第二次点击

组件这个时候还是拿到给的赋值,也就是上次curItem.value=e.id; 组件切换``uni.switchTab(),这个时候组件已经加载出来,所以组件此刻的状态跟上次对上

总的来说就是后来总是慢一拍

onShow 生命周期剖析

那么如果我们把上面的onLoad改成 onShow展示执行呢

onShow(() => {
  uni.hideTabBar();
});

我们这里直接在页面打印出来看看
image.png

这里我们可以看到我们的id是这样子的
image.png

点击第一次分类以后

在一瞬间竟然进行了短暂的切换,随后又再次切换回去,不过可以看到我们的方法已经成功了

image.png

点击第二次分类以后

image.png

还是那个页面,但是我们页面对应的值已经可以看到切换过去了,带动的我文字也正常显示
image.png

过程:

每次进入页面都执行了一下组件初始化

如何解决呢?

思路一:把切换的方式交出去

之前我们写切换的时候,这个切换总是放在我们公共组件之中,现在我们把这个方法交给上头,提交出去,让分页面之中进行控制。

那这个时候就是页面onLoad以后,我们在这个页面切换,那必然可以。

/* 导航栏切换 --更改前 */
	const changeItem = (e) => {
		console.log(e, '.target.value');
		// console.log(e.id, '.target.value');
		curItem.value=e.id;
		if (e.id === 2) {
			// todo
			return;
		}else{
		 uni.switchTab({
		 	url: e.pagePath,
		 	success() {
		 	   emits("change", e);
		    },
		 });
		}
};
/* 导航栏切换 ---更改以后 */
    const changeItem = (e) => {
            console.log(e, '.target.value');
            // console.log(e.id, '.target.value');
            curItem.value=e.id;
            if (e.id === 2) {
                    // todo
                    return;
            }else{
                    emits("change", e);
                    // uni.switchTab({
                    // 	url: e.pagePath,
                    // 	success() {
                    // 	   emits("change", e);
                    // 	},
                    // });
            }
    };

这里记得把我们状态每次的判断给改一下
image.png

抽离我们的方法

/* 导航栏切换 */
	const changeItem = (e) => {
		console.log(e, '.target.value');
		// console.log(e.id, '.target.value');
		curItem.value=e.id;
		if (e.id === 2) {
			// todo
			return;
		}else{
			emits("change", e.id);
			if(curItem.value == 0){
				uni.switchTab({
					url: '/pages/tabBar/index/index'
				})
			}else if(curItem.value == 1){
				uni.switchTab({
					url: '/pages/tabBar/center/center'
				})
			}else if(curItem.value == 3){
				uni.switchTab({
					url: '/pages/tabBar/list/list'
				})
			}else if(curItem.value == 4){
				uni.switchTab({
					url: '/pages/tabBar/user/user'
				})
			}else{
				
			}
		}
	};

现在再次进行尝试,毫无问题

思路二 使用状态存储

这里还有一种比较好的思路,就是pinia的持久化存储,不过我们切换部分暂时比较简单一些,这个可以稍后放入我们的优化部分之中

优化

这里我们优化一下,可以把其他所有组件的onLoad隐藏

uni.hideTabBar();

这个方法写到公共组件之中

把其他的加载都拿到公共组件中

image.png

这里我们优化底部切换栏完毕!

问题归纳处理和优化

(1)tabBar配置必须已经配置在pages之中

这里需要注意,下面tabBar配置的页面必须已经在pages之中配置好,不然就会报错

image.png

解决方式: 只要对应上即可
image.png

(2)uview-ui的使用 (这里我们放弃踩这个坑)

1、在根目录uview-ui中放入组件 2、在main.js之中进行全局引入和使用

// 引入全局uView
import uView from 'uview-ui'
Vue.use(uView);

(3)遇到的闪烁问题的解决

在这个过程的开发之中我们也遇到了问题

在pages.json 中设置隐藏自带的 tabbar 导航栏

这里我们需要在 pages.json配置一下,防止每次都闪烁页面

"tabBar": {
  "custom": true,
}
"custom": true, // 开启自定义tabBar(不填每次原来的tabbar在重新加载时都回闪现)

结果设置这个以后,我们的页面跳转反而出错,最后我们还是隐藏掉

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。