正文
分析小程序文档提供代码
在上一期的结尾我们发现, 微信小程序文档提供了实现tab选中态代码, 那我们就首先来看一看这段样例代码, 分享一些我自己的理解
index.wxss 部分
.tab-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 48px;
background: white;
display: flex;
padding-bottom: env(safe-area-inset-bottom);
}
.tab-bar-border {
background-color: rgba(0, 0, 0, 0.33);
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 1px;
transform: scaleY(0.5);
}
.tab-bar-item {
flex: 1;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.tab-bar-item cover-image {
width: 27px;
height: 27px;
}
.tab-bar-item cover-view {
font-size: 10px;
}
-
使用固定定位
position: fixed;将整个tabbar栏固定在手机小程序视窗底部 -
使用
env(safe-area-inset-bottom)适配 iphoneX 的底部小黑条 -
使用
transform: scaleY(0.5);将tabbar栏上边框缩放为原来的一半(这个使用没太看懂...) -
使用
flex布局布置tabbar栏子项和各子项中的内容但感觉
tab-bar-item中text-align: center;属性的使用不是太有必要, 因为该盒子内部的两个子盒cover-image和cover-view已经被justify-content: center;,align-items: center;和flex-direction: column;控制好了 -
对
cover-image标签和cover-view标签的选择原本是使用了元素嵌套的写法.tab-bar-item cover-image: 选中嵌套在类tab-bar-item内部的cover-image标签但实际上在微信开发者工具中却发现
...
关于这个问题, 微信小程序的组件模板和样式中提到
组件和引用组件的页面不能使用id选择器(
#a)、属性选择器([a])和标签名选择器,请改用class选择器。可见在组件中不仅是不能单独使用标签名选择器, 嵌套写法也不能使用. 将嵌套写法改为单独的类写法就可以了
index.wxml 部分
<!--miniprogram/custom-tab-bar/index.wxml-->
<cover-view class="tab-bar">
<cover-view class="tab-bar-border"></cover-view>
<cover-view
wx:for="{{list}}"
wx:key="index"
class="tab-bar-item"
data-path="{{item.pagePath}}"
data-index="{{index}}"
bindtap="switchTab"
>
<cover-image
src="{{selected === index ? item.selectedIconPath : item.iconPath}}"
>
</cover-image>
<cover-view
style="color: {{selected === index ? selectedColor : color}}"
>
{{item.text}}
</cover-view>
</cover-view>
</cover-view>
- 使用
wx:for循环来渲染各个tabbar子项 - 在
tabbar项节点的点击事件处, 使用dataset附加了自定义数据: 路径path和项编号index - 使用
selected变量来控制tabbar项节点的选中高亮
index.js 部分
Component({
data: {
selected: 0,
color: "#7A7E83",
selectedColor: "#3cc51f",
list: [{
pagePath: "/index/index",
iconPath: "/image/icon_component.png",
selectedIconPath: "/image/icon_component_HL.png",
text: "组件"
}, {
pagePath: "/index/index2",
iconPath: "/image/icon_API.png",
selectedIconPath: "/image/icon_API_HL.png",
text: "接口"
}]
},
attached() {
},
methods: {
switchTab(e) {
const data = e.currentTarget.dataset
const url = data.path
wx.switchTab({url})
// 此处的 setData 其实是可以删去的
// 因为在跳转的目标页面中会进行设置
this.setData({
selected: data.index
})
}
}
})
-
将
tabbar子项需要的跳转路径pagePath, 图标路径iconPath等封装到组件内部数据data中 -
实现
tabbar栏跳转和高亮功能:-
将组件的生命周期函数
attached置空 -
将所有
tabbar跳转页面都设置为组件Component -
将使当前页面对应
tabbar子项高亮相关操作置于被视为组件的页面的pageLifetimes字段中Component({ pageLifetimes: { show() { if (typeof this.getTabBar === 'function' && this.getTabBar()) { // 在此处设置 this.getTabBar().setData({ selected: 0 }) } } } })
-
小程序样例实现 tabbar 栏跳转高亮的思路
我们来进一步分析样例为实现 tabbar 栏跳转高亮功能进行的处理:
-
将组件的生命周期函数
attached置空我对于这一步的理解是这样的:
组件的这一生命周期在小程序文档组件部分中是这样描述的:
在组件完全初始化完毕、进入页面节点树后,
attached生命周期被触发。此时,this.data已被初始化为组件的当前值。这个生命周期很有用,绝大多数初始化工作可以在这个时机进行。组件的这一生命周期看上去似乎可以用于使当前页面对应的
tabbar子项高亮, 但由于tabbar栏是在app.json中注册,custom-tab-bar下相应文件接管渲染的, 而不是编写于对应的页面, 无法用父元素来向该子组件进行通信, 我们只能放弃在这一生命周期进行高亮设置的想法 -
将所有
tabbar跳转页面都设置为组件Component -
将使当前页面对应
tabbar子项高亮相关操作置于被视为组件的页面的pageLifetimes字段中当我首先看到第二步的时候, 我其实并不是十分迷惑的, 因为在小程序文档组件构造器部分中, 专门提到了可以用
Component构造器构造页面, 但是看到第三步中pageLifetimes字段中的show()的时候, 我确实是有些困惑了, 这一生命周期的含义是:组件所在的页面被展示时执行
结合代码的含义是: 被视为组件的页面将在该组件所在页面被展示时, 执行使
tabbar对应子项高亮的相关操作...这就产生了一个问题, 被视为组件的页面的所在页面被展示的时刻究竟是什么时候?
对此, 我的初步猜测是: 在使用
Component构造器构造页面之前, 微信会使用一个空的Page构造器来构造一个空的Page页面, 然后再用Component构造器构造页面中的内容, 若页面内容中使用到了别的组件, 微信将依次调用对应的Component构造器.但在测试中发现: 若是将用于构造页面的
Component构造器注释掉, 开发者工具将会报错:可见, 用于构造页面的
Component构造器将会直接替代之前的Page构造器如果不存在一个先创造的空页面来为
Component构造器构造的页面传递页面被展示信息, 那么我的第二个猜测是: 此处的pageLifetimes中的show字段就相当于原来Page中的onShow字段但在测试中却发现:
pageLifetimes中的show字段和Page中的onShow字段可以同时使用, 甚至Page和Component的生命周期字段都是可以同时使用, 且彼此之间存在一定的顺序Component({ lifetimes: { attached: function() { // 在组件实例进入页面节点树时执行 console.log("This is attached in lifetimes"); } }, pageLifetimes: { show() { if (typeof this.getTabBar === 'function' && this.getTabBar()) { this.getTabBar().setData({ selected: 0 }) } console.log("This is show in pageLifetimes"); } }, methods: { onLoad: function () { console.log("This is onLoad in Page"); }, onShow: function () { console.log("This is onShow in Page"); } } })
预告
小程序中具有生命周期的对象
既然我们发现了用于构造页面的 Component 构造器中, 组件的生命周期和页面的生命周期是可以同时使用的, 那么, 他们之间的顺序是怎样的呢? 而 tabbar 栏组件又是在其中的哪一生命周期被加入的呢? 这些问题我们只能下次再聊了:)