某天使用橙心优选小程序,咦这个选项卡还可以放到这里的吗??
噢对了,之前用ColorUI (opens new window)的时候见过类似的组件,如果不想用框架,那就自己来写一个吧(^▽^)!
# 1.页面配置
.json文件,全局配置就修改app.json
{
"navigationStyle": "custom"
}
修改之后,只保留了右上角的胶囊按钮悬浮在上方并且导航失去高度,页面内容会直接顶到最上方,并且与手机状态栏的时间、wifi、电量重叠。
# 2.计算位置
不同的手机状态栏高度肯定不一样,所以适配需要计算以下值:
- 整个导航栏的高度;
- 胶囊距离顶部的距离;
- 胶囊按钮与右侧的距离;
- 胶囊按钮与底部的距离;
- 整个导航栏的宽度;
通过 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
所以:
- 整个导航栏高度 = statusBarHeight + height + (top-statusBarHeight)*2
- 胶囊距离顶部的距离 = top
- 胶囊按钮与右侧的距离 = windowWidth - right
- 胶囊按钮与底部的距离 = top - statusBarHeight
- 整个导航栏的宽度 = 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)
}
}
})