背景
由于公司为合作伙伴推出定制小程序服务,小程序都是一套代码实现,而每个小程序都有自己的导航栏主题色,自己的tabBar。
实现过程
查看官方文档,发现可以通过api来更改导航栏颜色,tabBar颜色,图标(下面称为主题)。
导航栏
js
wx.setNavigationBarColor({
frontColor: '#ffffff',
backgroundColor: '#ff0000'
})
tabBar
js
wx.setTabBarStyle({
color: '#FF0000',
selectedColor: '#00FF00',
backgroundColor: '#0000FF',
borderStyle: 'white'
})
开始实现
想法与实现1
是在app初始化的时候根据appId调用以上api设置不同的主题,调式后发现只能更改当前页面主题,跳转到另一个页面还是保留了app.json的主题设置。只能抽离设置主题方法,每个页面都调用一次。
但是这种方式有个体验问题,进入小程序是会先展示app.json里面的配置主题,再变回需要设置的主题,中间存在闪烁过程,从一个页面跳转到另一个页面也存在这个闪烁过程。体验非常不好。
想法与实现2
通过自定义导航栏和tabBar实现;一顿倒腾时候发现也是存在闪烁问题,小程序从加载到读取到自定义配置需要时间。
社区
查看社区,发现已经有非常多开发者提出了(全局修改主题和闪烁问题),但从19年到现在,依然没用合适的解决方法,官方也没有解决。
建议setNavigationBarColor加一个参数,使其能全局生效?
官方来看看,提个需求,希望wx.setNavigationBarColor增加设置全局导航栏颜色?
wx.setNavigationBarColor为什么不能全局生效
转换实现思路
看起来在小程序运行时更改配置的实现方式都体验不佳(闪烁);既然小程序读取的是先读取的是app.json的配置,那么可以考虑先更改小程序的app.json再进行打包上传预览;把修改主题的时机从小程序加载提前到打包环节。
下面的实现以我前几天的文章为基础进行修改,可先阅读这个:
微信小程序自动化部署miniprogram-ci,一套代码一键上传多个小程序
主要目录结构
- 新建appConfig目录,存放各个小程序的主题(app.json里的window和tabBar)
- 新建setAppConfig.js文件, 用于打包前更改app.json文件。
- ci.js文件:循环执行所有app的打包预览,上传脚本
appConfig下的json文件结构
取自app.json里的部分配置,根据自己的定制需求增减。
setAppConfig.js脚本
作用为更改app.json里的部分配置,打包上传前执行。
- 获取所有小程序配置文件
- 根据传入的appId找到当前的配置文件
- 读取app.json文件和当前app的配置文件,将配置文件主题写入到当前app.json
js
const fs = require('fs');
const path = require('path')
const projectPath = path.resolve(__dirname, '..')
// app.json路径
const appJsonFile = `${projectPath}/app.json`
// 获取所有小程序上传密钥文件
const appConfigList = fs.readdirSync(`${projectPath}/ci/appConfig`)
// setAppConfig 将app.json更改成当前app的主题配置
const setAppConfig = (appId) => {
let err = null
try {
// 根据appId找到当前的配置文件
let jsonFileName = appConfigList.find(item => item.includes(appId))
const appConfigFile = `${projectPath}/ci/appConfig/${jsonFileName}`
// 读取app.json文件和当前app的主题配置文件,将主题写入到当前app.json
let appJsonData = JSON.parse(fs.readFileSync(appJsonFile, {encoding: 'utf-8'}))
const {window, tabBar} = JSON.parse(fs.readFileSync(appConfigFile, {encoding: 'utf-8'}))
appJsonData.window = window
appJsonData.tabBar = tabBar
fs.writeFileSync(appJsonFile, JSON.stringify(appJsonData, null, '\t'))
} catch (err) {
err = err
console.log(err)
}
return err
}
module.exports = setAppConfig
调整ci.js 上传与预览脚本
文件由前面的批量预览和上传脚本更改而来;批量预览和上传参考:微信小程序自动化部署miniprogram-ci,一套代码一键上传多个小程序
- 获取所有小程序上传密钥文件
- 根据上传密钥文件列表,获取appId列表
- app.json先更改为第一个app的配置,根据命令进行预览/上传
- 待执行完成后,再执行appId列表下一个app,直到最后一个
js
// 使用ci脚本上传,需在小程序后台:开发管理 =》 小程序代码上传,生成小程序代码密钥放到privateKey文件夹;配置上传机器的IP白名单;上传前先预览再上传 npm run preview => npm run upload
const fs = require('fs');
const ci = require('miniprogram-ci')
const path = require('path')
const projectPath = path.resolve(__dirname, '..')
// 更改app.json js
const setAppConfig = require(`${projectPath}/ci/setAppConfig.js`)
// 获取所有小程序上传密钥文件
const privateList = fs.readdirSync(`${projectPath}/ci/privateKey`)
// 处理命令
const command = process.argv.slice(2)[0]
// 当前处理的第几个小程序
let appIndex = 0
// appId列表
let appIdList = privateList.map(item => {
return item.split('.')[1] // item: private.appId.key
})
const uploadInfo = {
version: '5.0.9',
desc: '功能优化与修复bug'
}
// 处理上传和预览
let commandHandler = async () => {
let appId = appIdList[appIndex]
// 创建项目对象
const project = new ci.Project({
appid: appId, // 小程序appid
type: 'miniProgram', // 类型,小程序或小游戏
projectPath: projectPath, // 项目路径
privateKeyPath: `${projectPath}/ci/privateKey/${privateList[appIndex]}`, // 密钥路径
ignores: ['node_modules/**/*'] // 忽略的文件
})
// 预览和上传前设置app json文件
setAppConfig(appIdList[appIndex])
if (command === 'upload') {
await ci.upload({
project,
...uploadInfo,
setting: {
es6: true, // 对应小程序开发者工具的 "es6 转 es5"
es7: true, // 对应小程序开发者工具的 "增强编译"
minify: true // 是否压缩代码
},
onProgressUpdate: getstate,
})
} else if (command === 'preview') {
await ci.preview({
project,
desc: '功能优化', // 此备注将显示在"小程序助手"开发版列表中
setting: {
es6: true, // 对应小程序开发者工具的 "es6 转 es5"
es7: true, // 对应小程序开发者工具的 "增强编译"
},
qrcodeFormat: 'image',
qrcodeOutputDest: `${projectPath}/ci/qrcode/${appId}_qrcode.jpg`,
onProgressUpdate: getstate,
})
}
// 监听上传过程,如果上传完成延迟一下再上传下一个,避免配置串了
function getstate(e) {
if (e._status == "done" && e._msg == "upload") {
console.log(`${appIdList[appIndex]}--上传完成`)
// 继续下一个,直到最后一个
if (appIndex < appIdList.length - 1) {
setTimeout(() => {
appIndex += 1
commandHandler()
}, 1000)
}
}
}
}
commandHandler()