使用 weui wxss 小程序如何适配暗夜模式
原创
©著作权归作者所有:来自51CTO博客作者HullQin的原创作品,请联系作者获取转载授权,否则将追究法律责任
背景
之前做过小程序适配暗夜模式的需求,分享一下经验。
因为是微信小程序(不是抖音小程序、支付宝小程序等等),产品要求我们使用微信的样式,所以我们项目采用了weui-wxss。
weui的坑
但是这个weui wxss比较坑,它里面虽然有暗夜模式的样式,但是必须在根结点增加属性 data-weui-theme="dark"
,才能生效。例如:
<view data-weui-theme="dark">
</view>
为什么说它坑?
因为我们都习惯了使用@media (prefers-color-scheme:dark) {}
来判断暗夜模式/白天模式。这是原生的方法,非常方便。
但是weui wxss没用这个写法,都是以data-weui-theme
属性为准。而这个属性的值,需要开发者赋值。需要专门弄一个变量作为页面的data,使用API获取当前系统主题后,动态赋值。
因为暗黑模式的实现还不得不耦合JS,就比较恶心了,暗夜模式的JS逻辑侵入了我们业务代码。
具体做法
在app.json配置darkmode
{
"darkmode": true,
"themeLocation": "theme.json"
}
还需要增加文件theme.json
,可以参考官方文档:DarkMode 适配指南。
每个页面中声明一个theme的变量
Page({
data: {
theme: 'light',
},
});
默认值用白天模式light
。另一个取值是drak
。
每个页面中声明一个themeChangeCallback回调函数
Page({
themeChangeCallback({ theme }) {
this.setData({ theme });
// 这里还需要调用wx.setNavigationBarColor和wx.setBackgroundColor,设置导航栏颜色和背景色
onLoad时注册事件,监听主题色变化
Page({
onLoad(options) {
wx.onThemeChange(this.themeChangeCallback);
},
});
onUnload时取消注册事件,关闭监听主题色变化
Page({
onUnload() {
wx.offThemeChange(this.themeChangeCallback);
},
});
onShow时执行themeChangeCallback回调函数
Page({
onShow() {
this.themeChangeCallback();
},
});
在wxml中根元素设置属性
<view data-weui-theme="{{theme}}">
</view>
怎么样,上面的方案是不是要吐了?关键是:每个页面都需要写这么多重复的逻辑!可维护性极差,代码重复率极高。
我们急需一种解决方案,请往下看。
更优雅的方案
建议你先阅读下文章:《如何全局重写小程序 Page函数 wx对象?》,学会这种方法,我们再来看下方的代码。
function onLoadProxy(onLoad) {
return function (options) {
wx.onThemeChange(this.themeChangeCallback);
if (onLoad) {
return onLoad.call(this, options);
}
};
}
function onUnloadProxy(onUnload) {
return function () {
wx.offThemeChange(this.themeChangeCallback);
if (onUnload) {
return onUnload.call(this);
}
};
}
function onShowProxy(onShow) {
return function () {
this.themeChangeCallback();
if (onShow) {
return onShow.call(this);
}
};
}
const PageProxy = (Page) => function (options) {
const newOptions = {
...options,
data: { ...options.data, theme: 'light' },
themeChangeCallback({ theme }) {
this.setData({ theme });
// 这里还需要调用wx.setNavigationBarColor和wx.setBackgroundColor,设置导航栏颜色和背景色
},
onLoad: onLoadProxy(options.onLoad),
onUnload: onUnloadProxy(),
onShow: onShowProxy(),
};
Page(newOptions);
};
Page = PageProxy(Page);
我们通过全局改写Page对象,一次性改造了所有页面的onLoad
、onShow
、onUnload
。之后,我们的页面的代码中,完全不用管暗夜模式相关逻辑。
这避免了暗夜模式JS对业务代码的入侵,同时实现了暗夜模式这一功能,真是太方便了~