微信小程序之自定义导航

背景

在开始以前呢,先提示一下你们,这里所说的自定义导航指的是底部的tabbar!不要问我为何,我也不知道。vue

其实我我的是不推荐自定义tabbar的,但为何我仍是这么去作了呢?主要缘由是咱们的业务须要根据客群的不一样展现不一样的tabbar,若是用原生的tabbar是没法实现的。所以咱们最后决定经过自定义的方式来实现。不想看文字也没事,看一下个人示意图你就知道需求了...╮(╯_╰)╭json

是否是秒懂!😎小程序

自定义导航的优劣势

自定义导航最大的优点就是自定义,这不是废话吗...😂我总结了如下优点供你们参考:数组

  • 随意组合tab的item成为新的tabbar;
  • 能够在导航上的写一些动画;
  • 在tabbar的UI上也可以更加自由;
  • ......

自定义导航的优点仁者见仁智者见智。可能由于业务的不一样,所体现的优点也不同,我就不在这里掰扯了。缓存

说了这些优点,其实自定义导航的劣势也比较明显:bash

  • 自定义导航须要在每一个tab页面进行引入,麻烦。
  • 须要本身实现手机的适配。
  • 页面切换的时候,会有闪现得状况。
  • 必要的时候还须要考虑维护路由。
  • ......

实现方案

由于tabbar是一个比较独立的模块,因此能够写成组件的形式,这样子也方便维护。引入组件方法要是不熟悉的话,你们能够看官方的文档。自定义组件微信

建立组件

目录结构

这里我把组件命名为nav,目录结构以下:app

能够看到组件模块的目录结构和普通的page页面没什么区别,固然page页面须要在app.json里边进行引入,可是组件的话是不须要的。异步

json文件的配置

接下来,咱们须要在组件的json文件中配置一下:xss

{
  "component": true,
  "usingComponents": {}
}
复制代码

其余的就不须要再进行配置了。固然,假如你的组件里边须要引入其余的组件,能够用一样的方式,而且在"usingComponents": {}里边引入就行。

wxml的结构

接下来就是wxml文件的书写。这个页面的话就和page页面同样就好了。这里不须要考虑里边的节点数,由于最后小程序会把他们再封装到一个根节点上,因此你们没必要要再本身再添加一个根节点。

其余的话,有一个地方可能须要和你们提醒一下,记得给iPhoneX作一下兼容!这里个人tabbar用的是fixed的布局方式,因此可能会遮住一些元素

<view class="nav-placeholder" style="padding-bottom: {{isIpx ? 68 : 0}}rpx;"></view>
复制代码

我解决的方案如上,采用的是一个空白的元素进行占位。

引用组件的时候须要在目标页面的json文件中声明一下:

"usingComponents": {
    "x-nav":"../../",
}
复制代码

而后在模板中直接引用就好了:

<x-nav show="{{true}}" cartcount="{{cartcount}}" catchtouchmove="ture"></x-nav>
复制代码

wxss的结构

这里的样式就不要再具体说明了,由于组件的存在因此里边的类名不会被污染,你们放心的使用,你们能够在里边加各类动画,好比下边这样:

这个只是一个思路,要是我真这么设计,估计明天就会由于鞋带是蝴蝶结的被开除。大家可让设计作一些高大上的东西出来。

若是你非要用外部的样式的话也能够,可是你本身须要注意类名命名的问题,能够经过声明options来实现:

options:{
    addGlobalClass: true
},
复制代码

js的结构

js的结构可能会有一些不同,由于是组件,因此再也不是经过page({})这样子的方式去建立,而会改为Component({})的方式。

其余的写法和vue就比较像了。

props就变成了properties,格式以下:

properties: {
	val1: {
		type: Boolean,
		value: false,
		observer: function(newVal, oldVal) {
			console.log(newVal, oldVal);
		}
	},
	val2: {
		type: String,
		value: '0',
		observer: function(newVal, oldVal) {
			console.log(newVal, oldVal);
		}
	},
	...
},
复制代码

properties中假如你传入的值可能会是不一样类型的你能够换成optionalTypes,这个是支持多类型的

data的话就不必细说了,小程序的组件里边依然支持getApp()的方法,假如你有什么方法写在app.js中也是能够直接调用的。

在这里边我会用到show()方法,组件中使用onShow()这种带on的生命周期是有一些特别的,以下:

pageLifetimes:{
	show(){
            consolelog('show');
	},
	hide(){
            consolelog('hide');
	},
	resize(){
            consolelog('hide');
	},
},
复制代码

不带on的话是写在另一个对象中的lifetimes:{}

lifetimes: {
    attached() {
      // 在组件实例进入页面节点树时执行
    },
    detached() {
      // 在组件实例被从页面节点树移除时执行
    },
    created() {
      // 在组件实例刚刚被建立的时候
    },
    ready() {
      // 在组件在视图层布局完成后执行
    },
    moved() {
      // 在组件实例被移动到节点树另外一个位置时执行
    },
    error() {
      // 每当组件方法抛出错误时执行
    }
  },
复制代码

这里可能会有同窗有疑问这个lifetimes里的方法为何能够写在外边,其实写在外边的是旧式的定义方式,能够保持对 <2.2.3> 版本基础库的兼容。

其余的地方有一个navList:[]这个就是导航tab的list了,格式的话,推荐你们能够模仿原生的格式:

navList: [
	{
		name:'***', //nav的名称
		url:'****', //跳转的地址
		actived:true, //是否选中状态
		nomalImg:'***', //不被选中时的icon
		activedImg:'***', //被选中的icon
		type:'***' //导航类型
	},
	{
		name:'***',
		url:'***',
		actived:false,
		nomalImg:'***',
		activedImg:'***',
		type:'***'
	},
	{
		name:'***',
		url:'***',
		actived:false,
		nomalImg:'***',
		activedImg:'***',
		type:'***'
	}
],
复制代码

这里的话你们能够优化一下,由于当时写的比较急,再总结的时候发现好多地方能够优化。好比这个navList你们能够改成对象的模式,由于在getCurrentPages()中的路径其实也是/pages/....这样子的格式,你们能够把路径做为key,这样就不须要每次change的时候都去遍历一次数组,妈耶,当时我怎么就没这么写...😭

还有一点思路能够供给你们做为参考,由于咱们在切换tab的时候须要把actived状态进行修改,这个修改咱们能够不用去过多的去考虑切换的过程,由于原生的切换是使用wx.switchTab的方式进行切换,咱们自定义导航的话也能够模仿这个方式去作,咱们能够wx.redirectTo来代替,由于用的是redirect,因此咱们在判断路由的时候比较方便,直接取路由中的第一个来进行判断就好了。

其实说到路由栈,有一个比较麻烦的地方就是,当这个tab页面变成一个常规的页面时(就是能够经过navigate的方式访问),咱们的访问路径就会复杂起来,举个例子吧:

假如你经过点击tab进行切换页面的时候,这个是正常状况,可是假如你从别的页面访问的时候这个路由的长度可能就会大于1,这个时候你就须要对路由进行更加细致的检查了。

其余的话,我遇到的问题就是背景中提到的根据客群的不一样展现不一样的tabbar

这个的问题点在于,咱们获取用户客群信息的时候是个异步的过程,当请求回来的时候会有一个比较明显的变换过程,可能导航就会从三个变成四个,这个的话,目前的个人方案没有彻底避免,由于我不可能等到请求回来的时候再显示导航条吧,因此我会把用户第一次请求的结果记录下来,以后的话会优先取缓存中的数据,这样除了用户第一次回变换一次,以后的话就不会出现闪烁的状况

总结

你们在可使用小程序原生的tabbar的时候就用原生的,由于原生的体验上会更好一些。固然,若是不得不用自定义导航的时候不如就好好设计一下,充分发挥自定义导航的优点。要是你们有什么别的想法,欢迎你们在底下留言,同时也欢迎你们加我微信交流:zyf348519452,交个朋友也很好啊😎

相关文章
相关标签/搜索