一、前言
最近无意中打开“某品会”的小程序端,发现他们的头部布局为啥和公司开发的小程序不一样,自己的只能文字居中,改变背景色。对方的竟然可以设置2行文字,字体也有大有小,感觉非常的高大上。
某品会小程序首页:
接下来小编带着问题去晚上查相关资料,发现微信7.0.0新增了解决不同屏幕头部问题的终极办法:
wx.getMenuButtonBoundingClientRect()
有了这个神器支持获取胶囊按钮的高度,轻松解决“留海屏” 的适配问题。
二、开发
废话不多说,直接撸代码......
1、代码目录结构
│
├─components
│ └─navBar
│ navBar.js
│ navBar.json
│ navBar.wxml
│ navBar.wxss
├─pages
│ └─index
│ index.js
│ index.json
│ index.wxml
│ index.wxss
2、代码片段
components/navBar/navBar.js部分
Component({
options: {
multipleSlots: true,
addGlobalClass: true
},
data: {},
pageLifetimes: {
show: function() {
if (getApp().globalSystemInfo.ios) {
this.getSystemInfo();
this.setStyle(); //设置样式1
}
},
hide: function() {}
},
methods: {
setStyle: function(life) {
const {
statusBarHeight,
navBarHeight,
capsulePosition,
navBarExtendHeight,
ios,
windowWidth
} = getApp().globalSystemInfo;
const { back, home, title } = this.data;
let rightDistance = windowWidth - capsulePosition.right; //胶囊按钮右侧到屏幕右侧的边距
let leftWidth = windowWidth - capsulePosition.left; //胶囊按钮左侧到屏幕右侧的边距
let navigationbarinnerStyle = [
`color: ${this.data.color}`,
`background: ${this.data.background}`,
`height:${navBarHeight + navBarExtendHeight}px`,
`padding-top:${statusBarHeight}px`,
`padding-right:${leftWidth}px`,
`padding-bottom:${navBarExtendHeight}px`
].join(';');
let navBarLeft = [];
if ((back && !home) || (!back && home)) {
navBarLeft = [`width:${capsulePosition.width}px`, `height:${capsulePosition.height}px`].join(';');
} else if ((back && home) || title) {
navBarLeft = [
`width:${capsulePosition.width}px`,
`height:${capsulePosition.height}px`,
`margin-left:${rightDistance}px`
].join(';');
} else {
navBarLeft = [`width:auto`, `margin-left:0px`].join(';');
}
if (life === 'created') {
this.data = {
navigationbarinnerStyle,
navBarLeft,
navBarHeight,
capsulePosition,
navBarExtendHeight,
ios
};
} else {
this.setData({
navigationbarinnerStyle,
navBarLeft,
navBarHeight,
capsulePosition,
navBarExtendHeight,
ios
});
}
},
_showChange: function(value) {
this.setStyle();
},
// 返回事件
back: function() {
this.triggerEvent('back', { delta: this.data.delta });
},
home: function() {
this.triggerEvent('home', {});
},
search: function() {
this.triggerEvent('search', {});
},
getSystemInfo() {
var app = getApp();
if (app.globalSystemInfo && !app.globalSystemInfo.ios) {
return app.globalSystemInfo;
} else {
let systemInfo = wx.getSystemInfoSync();
let ios = !!(systemInfo.system.toLowerCase().search('ios') + 1);
let rect;
try {
rect = wx.getMenuButtonBoundingClientRect ? wx.getMenuButtonBoundingClientRect() : null;
if (rect === null) {
throw 'getMenuButtonBoundingClientRect error';
}
//取值为0的情况 有可能width不为0 top为0的情况
if (!rect.width || !rect.top || !rect.left || !rect.height) {
throw 'getMenuButtonBoundingClientRect error';
}
} catch (error) {
let gap = ''; //胶囊按钮上下间距 使导航内容居中
let width = 96; //胶囊的宽度
if (systemInfo.platform === 'android') {
gap = 8;
width = 96;
} else if (systemInfo.platform === 'devtools') {
if (ios) {
gap = 5.5; //开发工具中ios手机
} else {
gap = 7.5; //开发工具中android和其他手机
}
} else {
gap = 4;
width = 88;
}
if (!systemInfo.statusBarHeight) {
//开启wifi的情况下修复statusBarHeight值获取不到
systemInfo.statusBarHeight = systemInfo.screenHeight - systemInfo.windowHeight - 20;
}
rect = {
//获取不到胶囊信息就自定义重置一个
bottom: systemInfo.statusBarHeight + gap + 32,
height: 32,
left: systemInfo.windowWidth - width - 10,
right: systemInfo.windowWidth - 10,
top: systemInfo.statusBarHeight + gap,
width: width
};
console.log('error', error);
console.log('rect', rect);
}
let navBarHeight = '';
if (!systemInfo.statusBarHeight) {
systemInfo.statusBarHeight = systemInfo.screenHeight - systemInfo.windowHeight - 20;
navBarHeight = (function() {
let gap = rect.top - systemInfo.statusBarHeight;
return 2 * gap + rect.height;
})();
systemInfo.statusBarHeight = 0;
systemInfo.navBarExtendHeight = 0; //下方扩展4像素高度 防止下方边距太小
} else {
navBarHeight = (function() {
let gap = rect.top - systemInfo.statusBarHeight;
return systemInfo.statusBarHeight + 2 * gap + rect.height;
})();
if (ios) {
systemInfo.navBarExtendHeight = 4; //下方扩展4像素高度 防止下方边距太小
} else {
systemInfo.navBarExtendHeight = 0;
}
}
systemInfo.navBarHeight = navBarHeight; //导航栏高度不包括statusBarHeight
systemInfo.capsulePosition = rect; //右上角胶囊按钮信息bottom: 58 height: 32 left: 317 right: 404 top: 26 width: 87 目前发现在大多机型都是固定值 为防止不一样所以会使用动态值来计算nav元素大小
systemInfo.ios = ios; //是否ios
app.globalSystemInfo = systemInfo; //将信息保存到全局变量中,后边再用就不用重新异步获取了
//console.log('systemInfo', systemInfo);
return systemInfo;
}
}
}
});
components/navBar/navBar.wxml部分
<view class="lxy-nav-bar {
{extClass}}" style="background: {
{backgroundColorTop}};height: {
{navBarHeight+ navBarExtendHeight}}px;">
<view class="lxy-nav-bar__placeholder {
{ios ? 'ios' : 'android'}}" style="padding-top: {
{navBarHeight+ navBarExtendHeight}}px;visibility: hidden;"></view>
<view class="lxy-nav-bar__inner {
{ios ? 'ios' : 'android'}}" style="{
{navigationbarinnerStyle}}{
{displayStyle}}">
<view class='lxy-nav-bar__left' style="{
{navBarLeft}}">
<block wx:if="{
{back&&!home}}">
<view bindtap="back" class="lxy-nav-bar__button lxy-nav-bar__btn_goback {
{iconTheme}}"></view>
</block>
<block wx:if="{
{!back&&home}}">
<view bindtap="home" class="lxy-nav-bar__button lxy-nav-bar__btn_gohome {
{iconTheme}}"></view>
</block>
<block wx:elif="{
{back&&home}}">
<view class="lxy-nav-bar__buttons {
{ios ? 'ios' : 'android'}}" wx:if="{
{home}}">
<view bindtap="back" class="lxy-nav-bar__button lxy-nav-bar__btn_goback {
{iconTheme}}" wx:if="{
{back}}"></view>
<view bindtap="home" class="lxy-nav-bar__button lxy-nav-bar__btn_gohome {
{iconTheme}}"></view>
</view>
</block>
<block wx:else>
<slot name="left"></slot>
</block>
</view>
<view class='lxy-nav-bar__right'>
<slot name="right"></slot>
</view>
</view>
</view>
pages/index/index.wxml部分
<view class="custom_head" style="height:{
{navHeight}}px;">
<view class="flex-row j_b" style="height:{
{navObj}}px;padding-top:{
{navTop}}px;padding-right:{
{navObjWid+5}}px;">
<view class="head_store text_title">
{
{store_name}}
</view>
</view>
</view>
pages/index/index.js部分
const app = getApp();
Page({
/**
* 页面的初始数据
*/
data: {
navHeight: app.globalData.navHeight, //导航栏高度
navTop: app.globalData.navTop, //导航栏距顶部距离
navObj: app.globalData.navObj, //胶囊的高度
navObjWid: app.globalData.navObjWid, //胶囊宽度+距右距离
storeList: [{
name: '品牌特卖 100%正品'
}],
}
}
此处省略样式部分代码块......
三、结果
总结:
- 通过微信官方API: getMenuButtonBoundingClientRect(),可以解决各类手机屏幕的适配问题。
- 将算好的参数存储在全局变量中,只需一次计算就可以全局使用。