某天使用橙心优选小程序,咦这个选项卡还可以放到这里的吗??
噢对了,之前用ColorUI (opens new window)的时候见过类似的组件,如果不想用框架,那就自己来写一个吧(^▽^)!

# 1.页面配置

.json文件,全局配置就修改app.json

{
  "navigationStyle": "custom"
}

修改之后,只保留了右上角的胶囊按钮悬浮在上方并且导航失去高度,页面内容会直接顶到最上方,并且与手机状态栏的时间、wifi、电量重叠。

# 2.计算位置

不同的手机状态栏高度肯定不一样,所以适配需要计算以下值:

  1. 整个导航栏的高度;
  2. 胶囊距离顶部的距离;
  3. 胶囊按钮与右侧的距离;
  4. 胶囊按钮与底部的距离;
  5. 整个导航栏的宽度;

通过 wx.getMenuButtonBoundingClientRect() 获取胶囊按钮的信息 , wx.getSystemInfo() 获取设备信息

//胶囊
console.log(wx.getMenuButtonBoundingClientRect())
//{width: 87, height: 32, left: 278, top: 24, right: 365, bottom: 56}

//设备信息
wx.getSystemInfo({
  success (res) {
    console.log(res.windowWidth)
    console.log(res.statusBarHeight)
  }
})
//375
//20

所以:

  1. 整个导航栏高度 = statusBarHeight + height + (top-statusBarHeight)*2
  2. 胶囊距离顶部的距离 = top
  3. 胶囊按钮与右侧的距离 = windowWidth - right
  4. 胶囊按钮与底部的距离 = top - statusBarHeight
  5. 整个导航栏的宽度 = windowWidth
  • 自定义导航的高度 = 1 , 子元素均绝对定位
  • 选项卡的top = 2
  • 返回箭头的left = 3
  • 选项卡理想情况与底部的距离 = 4 (实际没什么用)
  • 选项卡的left = (5-自身width)/2 (这里居中的方法太多,直接css就行)

# 3.封装成组件(可选)

如果全局修改了app.json ,那就把导航封装成组件引用比较方便。

思路:组件内部点击事件,把选项值传给父级,采用子组件调用父组件的方法来实现。 组件知识点请看关于组件

<!--component/oredr-navbar.wxml-->
<view class="navbar" style="height:{{navProperty.height}}px">
	<view class="back" style="left:{{navProperty.left}}px; top:{{navProperty.top}}px">返回</view>
	<view class="tabcon" style="top:{{navProperty.top}}px">
		<view class="tab {{ tabid == 1 ? 'active':''}}" bindtap="switchTab" data-id="1">自提订单</view>
		<view class="tab {{ tabid == 2 ? 'active':''}}" bindtap="switchTab" data-id="2">快递订单</view>
	</view>
</view>
// component/oredr-navbar.js
Component({
  /**
   * 组件的初始数据
   */
  data: {
    navProperty:{},
    tabid:1
  },
  /**
   * 组件的生命周期
   */
  lifetimes: {
    attached: function () {
      var that = this;
      var navProperty = {};
      var capsule = wx.getMenuButtonBoundingClientRect();//胶囊位置属性
      wx.getSystemInfo({
        success (res) {
          navProperty.width = res.windowWidth;
          navProperty.top = capsule.top;
          navProperty.height = res.statusBarHeight + capsule.height + (capsule.top-res.statusBarHeight)*2 +2;
          navProperty.left = res.windowWidth - capsule.right;
          that.setData({
            navProperty:navProperty
          })
        }
      })
     }
  },

  /**
   * 组件的方法列表
   */
  methods: {
    switchTab: function(e){
      var currentTarget = e.currentTarget;  
      this.setData({
        tabid: currentTarget.dataset.id
      })

      this.triggerEvent('getTabId',{tabid:currentTarget.dataset.id})
    }
  }
})

<!--pages/ucenter/order/order.wxml-->
<navbar bindgetTabId="getTabId"></navbar>
// pages/ucenter/order/order.js
Page({

  data: {
    tabid:1
  },

  getTabId: function(e){
    console.log(e.detail.tabid)
    this.setData({
      tabid:e.detail.tabid
    })
  }

})

# 关于组件

# 1. 父组件调用子组件的方法

获取组件示例

可在父组件里调用 this.selectComponent ,获取子组件的实例对象。

调用时需要传入一个匹配选择器 selector,如:this.selectComponent(".my-component")。

// 父组件
Page({
  data: {},
  getChildComponent: function () {
    const child = this.selectComponent('.my-component');
  }
})

在上例中,父组件将会获取 class 为 my-component 的子组件实例对象,即子组件的 this 。

注意 :默认情况下,小程序与插件之间、不同插件之间的组件将无法通过 selectComponent 得到组件实例(将返回 null)。如果想让一个组件在上述条件下依然能被 selectComponent 返回,可以自定义其返回结果(见下)。

自定义的组件实例获取结果

// 自定义组件 my-component 内部
Component({
  behaviors: ['wx://component-export'],
  export() {
    return { myField: 'myValue' }
  }
})
/*-- 使用自定义组件时 */
<my-component id="the-id" />
// 父组件调用
const child = this.selectComponent('#the-id') // 等于 { myField: 'myValue' }

# 2. 子组件调用父组件的方法

this.triggerEvent('myevent', myEventDetail, myEventOption)

参数:引用组件绑定的事件名,子组件的数据,事件对象冒泡捕获

<component-tag-name bindmyevent="onMyEvent" />
//或者
<component-tag-name bind:myevent="onMyEvent" />

Page({
  onMyEvent: function(e){
    e.detail // 自定义组件触发事件时提供的detail对象
  }
})
//子组件中
<button bindtap="onTap">点击这个按钮将触发“myevent”事件</button>

Component({
  properties: {},
  methods: {
    onTap: function(){
      var myEventDetail = {} // detail对象,提供给事件监听函数
      var myEventOption = {} // 触发事件的选项
      this.triggerEvent('myevent', myEventDetail, myEventOption)
    }
  }
})