- 关于微信background-image在真机展示不出来的解决方案
假设文件目录结构为如下形式,我们需要在index这个page中引用main_bg.png这个文件 [图片] 平时我们的做法都是在wxss中或者元素的style中指定background-image: url("/images/main_bg.png")。 但是这种做法在开发工具上可以展示,在真机上却展示不出来,这个应该是个bug。 解决方案如下: [图片] 只能在wxml中的style中指定background-image,并且url中最前面的/需要去掉。(在wxss中指定无效,加上'/'也会无效) 但是这个方案在开发工具中无法正常预览,所以大家可以先通过在wxml中指定background-image: url('/images/main_bg.png'),待开发完成要在真机预览时,再把最前面的'/'去掉即可 当然最好是希望微信团队能够早点解决这个小bug
2017-01-08 - 省钱有道之 云开发环境共享小结
#前言 最近为了节省一点小程序的运营成本,一些没啥流量的小程序如果每个月也要19块略微有些肉疼(主要还是穷),研究了一下云环境共享,在这里简单做一下总结。 [图片] 这里有官方的小程序环境共享文档需提前了解一下,具体共享步骤按官方文档操作即可。 https://developers.weixin.qq.com/miniprogram/dev/wxcloud/guide/resource-sharing/introduce.html #注意点 共享环境有几个注意点大致如下: 1、必须是相同主体 2、开通了云开发环境的小程序可以共享给同主体的小程序、公众号,被共享方无需开通云开发环境 3、一个云开发环境最多可以共享给10个小程序/公众号 4、共享后双发均可主动解除 5、按官方文档要求,资源方需有云函数cloudbase_auth,测试时发现没有这个云函数其实也能正常运行,可能我验证的场景还不够多 6、云能力初始化的方式不同,资源方按传统的云环境初始化方式即可,也就是 wx.cloud.init({ env: env.activeEnv, traceUser: true }); 而调用方的初始化方式有所不同 const cloud = new wx.cloud.Cloud({ //资源方AppID resourceAppid, //资源方环境ID resourceEnv, }) // 跨账号调用,必须等待 init 完成 // init 过程中,资源方小程序对应环境下的 cloudbase_auth 函数会被调用,并需返回协议字段(见下)来确认允许访问、并可自定义安全规则 const initRes = await cloud.init(); 后续调用资源方的云函数就用这个cloud就行了:cloud.callFunction({...}); 7、调用方有操作到云存储文件的api也需要用6步骤中的cloud 8、云存储fileId需要用cloud.getTempFileURL转换成临时/永久链接,否则在调用方无法展示 9、一些api的云调用方式也有变化,需指明具体的appid。比如A小程序授权给了B小程序,想给B小程序推送客服消息需要写成 await cloud.openapi({appid:B小程序appid}).customerServiceMessage.send({...}); 10、获取调用方的appid/openid/unionid也有所不同 // 跨账号调用时,由此拿到来源方小程序/公众号 AppID console.log(wxContext.FROM_APPID) // 跨账号调用时,由此拿到来源方小程序/公众号的用户 OpenID console.log(wxContext.FROM_OPENID) // 跨账号调用、且满足 unionid 获取条件时,由此拿到同主体下的用户 UnionID console.log(wxContext.FROM_UNIONID) #适配 基于以上注意点,开始进行适配,由于我是一套代码部署N个小程序,然后一个云环境共享给其他小程序,希望通过配置决定哪个小程序作为资源方,哪些作为调用方 首先是云开发环境的初始化: 1、env.js 环境配置: //云开发环境 const cloudBase = { //使用共享云环境资源,资源方=false,调用方=true useShareResource: false, //资源方AppID resourceAppid: "wx9d2xxxxxxxx0088", //资源方环境ID resourceEnv: "prod-9gxqvi3qb3c257ef", //云环境ID prod: "prod-9gxqvi3qb3c257ef" } 2、api.js 操作模块 const env = require('../env.js'); let cloud; /** * 初始化云能力 * @returns {Promise} */ const wxCloudInit = async function () { const {cloudBase} = env; if (!wx.cloud) { console.error('请使用 2.2.3 或以上的基础库以使用云能力') } else if (cloudBase.useShareResource) { const {resourceAppid, resourceEnv} = cloudBase; // 声明新的 cloud 实例 cloud = new wx.cloud.Cloud({ //资源方AppID resourceAppid, //资源方环境ID resourceEnv, }) // 跨账号调用,必须等待 init 完成 // init 过程中,资源方小程序对应环境下的 cloudbase_auth 函数会被调用,并需返回协议字段(见下)来确认允许访问、并可自定义安全规则 const initRes = await cloud.init(); console.log("初始化云能力完毕:", initRes, "资源方appid:", resourceAppid, "资源方环境ID:", resourceEnv); } else { wx.cloud.init({ env: env.activeEnv, traceUser: true }); console.log("初始化云能力完毕,当前环境:", env.activeEnv); cloud = wx.cloud; } this.cloud = cloud; } /** * 云函数调用 * @param name * @param data * @param success * @param fail * @param complete */ const callCloudFunction = function (name, data, success, fail, complete) { //执行云函数 cloud.callFunction({ // 云函数名称 name: name, // 传给云函数的参数 data: Object.assign({}, data, {env: env.activeEnv}) }).then(res => { typeof success == 'function' && success(res); }).catch(res => { typeof fail == 'function' && fail(res); }).then(res => { typeof complete == 'function' && complete(res); }); }; 3、在app.js中初始化云环境,后续有用到wx.cloud的都需要改成api.cloud const api = require('utils/api.js'); App({ onLaunch: async function (options) { await api.wxCloudInit(); } }); 其次是资源方的获取用户信息调整 每次都要判断wxContext.FROM_OPENID是否为空,不为空则是调用方的用户信息,为空则是资源方的用户信息,略微繁琐,干脆封装了一个npm包wx-server-inherit-sdk,改造了一下getWxContext函数,源码如下,引入这个包后也就可以不用引入官方的wx-server-sdk const cloud = require('wx-server-sdk'); // 保存原始getWXContext方法到另一个变量 const originalGetWXContext = cloud.getWXContext; cloud.getWXContext = function () { //调用原始getWXContext方法 const wxContext = originalGetWXContext.call(this); const {FROM_APPID, FROM_OPENID} = wxContext; //云开发环境共享时获取到的APPID会替换成源方APPID if (FROM_APPID) { Object.assign(wxContext, {APPID: FROM_APPID}); } //云开发环境共享时获取到的OPENID会替换成源方OPENID if (FROM_OPENID) { Object.assign(wxContext, {OPENID: FROM_OPENID}); } return wxContext; } module.exports = cloud; 到此也就大功告成。为了省钱也是够折腾的[哭笑]
2023-08-28 - 知识竞赛答题小程序
通过长期的答题小程序开发,不断完善答题小程序的各种功能,整理出知识竞赛答题活小程序活动玩法。 今天我讲解一下知识竞赛答题小程序的规则 一、知识竞赛答题小程序规则一 个人排行榜 根据分数排名,分数相同则答题时间短的排前面。共有三种计分规则,详见下面描述 活动周期内最高得分 例如:活动周期内可以多次答题,取最好的一次成绩参与排名。 累计每天最高得分 例如:每天可以多次答题。第一天最好成绩为90分,第二天最好成绩为80分,两天答题最高得分为90分。 累计每次答题得分 例如:每天可以多次答题,累计每次答题成绩。每人每天最多可以答5次。 单位排行榜 可以根据参赛人数、平均分、总分进行排名。 学习模块 例如:每天不限次数练习答题,不断学习 答题记录 例如:答题的记录都可以随时查看,查看错题,查看答案,还可以生成海报等。 [图片] [图片] 二、知识竞赛答题小程序规则二 本知识竞赛答题小程序活动主要有以下规则: 1.答题活动开始后才可以答题 2.答题活动结束后不能答题 3.每答对一题得10分,答题以每次累计最高分数为主要分数。类似于微信小游戏跳一跳计分规则 4.每天不限制答题的次数,可多次答题,以最高分数为主,破纪录后将统计最高分数 5.每次答题将有3张错题卡,答错3次后需重新开始答题 6.每次答题记录统计答题分数或次数,通过累计分数显示答题段位 7.答题可设置答题段位,答题次数越多积分越高,段位越高 8.答题排行榜分为积分榜和段位榜 9.结束答题后根据积分榜选出一等奖,二等奖,三等奖。或根据段位榜选出一等奖,二等奖,三等奖或参与奖 [图片] [图片] 如果搭建过程中遇到问题可到程序员锤哥公众号提问。
2022-04-26 - 如何实现快速生成朋友圈海报分享图
由于我们无法将小程序直接分享到朋友圈,但分享到朋友圈的需求又很多,业界目前的做法是利用小程序的 Canvas 功能生成一张带有小程序码的图片,然后引导用户下载图片到本地后再分享到朋友圈。相信大家在绘制分享图中应该踩到 Canvas 的各种(坑)彩dan了吧~ 这里首先推荐一个开源的组件:painter(通过该组件目前我们已经成功在支付宝小程序上也应用上了分享图功能) 咱们不多说,直接上手就是干。 [图片] 首先我们新增一个自定义组件,在该组件的json中引入painter [代码]{ "component": true, "usingComponents": { "painter": "/painter/painter" } } [代码] 然后组件的WXML (代码片段在最后) [代码]// 将该组件定位在屏幕之外,用户查看不到。 <painter style="position: absolute; top: -9999rpx;" palette="{{imgDraw}}" bind:imgOK="onImgOK" /> [代码] 重点来了 JS (代码片段在最后) [代码]Component({ properties: { // 是否开始绘图 isCanDraw: { type: Boolean, value: false, observer(newVal) { newVal && this.handleStartDrawImg() } }, // 用户头像昵称信息 userInfo: { type: Object, value: { avatarUrl: '', nickName: '' } } }, data: { imgDraw: {}, // 绘制图片的大对象 sharePath: '' // 生成的分享图 }, methods: { handleStartDrawImg() { wx.showLoading({ title: '生成中' }) this.setData({ imgDraw: { width: '750rpx', height: '1334rpx', background: 'https://qiniu-image.qtshe.com/20190506share-bg.png', views: [ { type: 'image', url: 'https://qiniu-image.qtshe.com/1560248372315_467.jpg', css: { top: '32rpx', left: '30rpx', right: '32rpx', width: '688rpx', height: '420rpx', borderRadius: '16rpx' }, }, { type: 'image', url: this.data.userInfo.avatarUrl || 'https://qiniu-image.qtshe.com/default-avatar20170707.png', css: { top: '404rpx', left: '328rpx', width: '96rpx', height: '96rpx', borderWidth: '6rpx', borderColor: '#FFF', borderRadius: '96rpx' } }, { type: 'text', text: this.data.userInfo.nickName || '青团子', css: { top: '532rpx', fontSize: '28rpx', left: '375rpx', align: 'center', color: '#3c3c3c' } }, { type: 'text', text: `邀请您参与助力活动`, css: { top: '576rpx', left: '375rpx', align: 'center', fontSize: '28rpx', color: '#3c3c3c' } }, { type: 'text', text: `宇宙最萌蓝牙耳机测评员`, css: { top: '644rpx', left: '375rpx', maxLines: 1, align: 'center', fontWeight: 'bold', fontSize: '44rpx', color: '#3c3c3c' } }, { type: 'image', url: 'https://qiniu-image.qtshe.com/20190605index.jpg', css: { top: '834rpx', left: '470rpx', width: '200rpx', height: '200rpx' } } ] } }) }, onImgErr(e) { wx.hideLoading() wx.showToast({ title: '生成分享图失败,请刷新页面重试' }) //通知外部绘制完成,重置isCanDraw为false this.triggerEvent('initData') }, onImgOK(e) { wx.hideLoading() // 展示分享图 wx.showShareImageMenu({ path: e.detail.path, fail: err => { console.log(err) } }) //通知外部绘制完成,重置isCanDraw为false this.triggerEvent('initData') } } }) [代码] 那么我们该如何引用呢? 首先json里引用我们封装好的组件share-box [代码]{ "usingComponents": { "share-box": "/components/shareBox/index" } } [代码] 以下示例为获取用户头像昵称后再生成图。 [代码]<button class="intro" bindtap="getUserInfo">点我生成分享图</button> <share-box isCanDraw="{{isCanDraw}}" userInfo="{{userInfo}}" bind:initData="handleClose" /> [代码] 调用的地方: [代码]const app = getApp() Page({ data: { isCanDraw: false }, // 组件内部关掉或者绘制完成需重置状态 handleClose() { this.setData({ isCanDraw: !this.data.isCanDraw }) }, getUserInfo(e) { wx.getUserProfile({ desc: "获取您的头像昵称信息", success: res => { const { userInfo = {} } = res this.setData({ userInfo, isCanDraw: true // 开始绘制海报图 }) }, fail: err => { console.log(err) } }) } }) [代码] 最后绘制分享图的自定义组件就完成啦~效果图如下: [图片] tips: 文字居中实现可以看下代码片段 文字换行实现(maxLines)只需要设置宽度,maxLines如果设置为1,那么超出一行将会展示为省略号 代码片段:https://developers.weixin.qq.com/s/J38pKsmK7Qw5 附上painter可视化编辑代码工具:点我直达,因为涉及网络图片,代码片段设置不了downloadFile合法域名,建议真机开启调试模式,开发者工具 详情里开启不校验合法域名进行代码片段的运行查看。 最后看下面大家评论问的较多的问题:downLoadFile合法域名在小程序后台 开发>开发设置里配置,域名为你图片的域名前缀 比如我文章里的图https://qiniu-image.qtshe.com/20190605index.jpg。配置域名时填写https://qiniu-image.qtshe.com即可。如果你图片cdn地址为https://aaa.com/xxx.png, 那你就配置https://aaa.com即可。
2022-01-20 - 现在小程序还可以抓包吗?
请问各位大佬,现在小程序还可以抓包吗,如果抓包的话,大家都使用的什么工具 [图片]
2021-04-07 - 知识竞赛答题小程序系列-关于成绩排行榜的设计与反思
接了不少的知识竞赛答题小程序系列,在做的过程中,作为开发者,我常常思考关于排行榜的设计与逻辑,如何把它做得更好,譬如提高用户体验、譬如发挥它的价值...... 什么是排行榜? 排行榜是对某一相关同类事物的客观实力的反映,带有相互之间的比较性质。比如,个人得分排行榜、单位平均分排行榜等等。 [图片] 排行榜的内在逻辑和价值是什么? 对于在线答题小程序来说,特别是对于主题知识答题活动小程序而言,成绩排行榜的设计是这个阶段核心要考虑的问题,也就是细节。在我的这个微信答题小程序中,做了多个维度的统计排行榜,按照对象的维度划分,其中包括个人排行榜、单位排行榜等,按照时间的维度划分,其中包括今日排行榜、累计排行榜等。 [图片] 个人排行榜 个人排行榜根据两个指标进行排名,分数和答题用时。首先根据分数由高到低进行排名,如果分数相同,则答题用时越短的排在前面。 根据我以往做了不少答题活动小程序的经验,回顾总结一下,常见的几种计分规则有哪些? 活动周期内最高得分:活动周期内每人每天可以答题多次,取最好的一次成绩参与排名。每日答题得分:活动周期内可以每人每天答题一次,取该次得分排名。累计每次答题得分:活动周期内可以每人每天答题一次,第一天成绩为100分,第二天成绩为95分,两天累计最高得分为195分,以此类推累计。[图片] 单位排行榜 单位排行榜可以根据总分、参与人数、平均分、平均用时等指标进行统计排名。举一反三,规则同理。 [图片] 总结 最后按照我的老习惯还是要对这类产品的设计进行一些反思。排行榜的普适性和稳定性。 根据我做过的那些答题活动小程序,应用场景都有哪些?党建知识竞赛、安全生产知识竞赛、消防知识竞赛、网络安全知识竞赛、禁毒知识竞赛、科普知识竞赛、食品安全知识竞赛、法律知识竞赛等。关于排行榜设计的另外一点,就是怎样保持排行榜的稳定性。
2021-07-13 - 知识竞赛答题小程序
前几天恰逢五四青年节,帮我们党支部开发了一套知识竞赛类答题小程序,文章末尾有小程序码可以体验 该小程序目前已完成 用户授权,授权后答题、答题完成展示排名,完整支持知识竞赛答题活动的需求, 答题目前已支持单选、多选、判断三种题型 不详细介绍了,具体先上截图吧 [图片] 1 [图片] 2 [图片] 3 [图片] 4 [图片] 5 [图片] [图片] 6 大家不妨扫码体验下,有问题的可以反馈给我 [图片]
2020-11-24