- 微信小游戏的启动性能优化之首屏渲染
前言 微信小游戏云测试服务的开放之后,越来越多的开发者使用该功能测试自己的小游戏的性能。但是大部分小游戏的测试结果显示,启动性能得分很低,远远达不到80分的标准线,甚至难以达到60分。 [图片] 根据微信小游戏文档中的启动优化最佳实践,优化思路一共有6种: 精简首包资源 分包加载 引擎插件 预下载能力 降低首屏渲染资源 尽快渲染。 常规的优化思路往往是两步: 拆分代码包,精简首包资源,使得首包只存首屏图片和一个加载进度条及相关代码; 使用分包加载。 根据小游戏的启动时序,会发现,降低代码包资源会减少了代码包下载,以及在某种程度下降低JS注入耗时。 [图片] 然而,即使启动优化到这一步,很多小游戏依旧得不到理想的分数。因为使用引擎开发的小游戏,即便只留首包必要资源,也会保留引擎代码,这无非会增加很长时间的JS注入耗时,以及首屏渲染耗时也未得到优化。此时很多开发者已经非常苦恼:我该如何优化呐? 自然而然,解决思路无非是,1. 降低注入代码的大小来减少JS注入耗时; 2. 简化首屏渲染逻辑,比如不依赖第三方引擎进行轻量渲染。但是,怎么做呐? 本文,将结合上面的两个解决思路,提供一套不依赖引擎(WebGL/Canvas2D直接渲染首屏)的小游戏首包加载套路,即减少了引擎代码注入耗时,又避免了第三方引擎的重度渲染。该方式可以直接套用,使用后的小游戏的启动性能在云测试报告下的启动性能得分能达到90及以上。 背景 目前微信官方文档、微信小游戏社区和各个引擎社区已经有很多篇关于启动优化的文章。除了微信官方文档,在微信小游戏社区和cocos 社区下有两篇非常优秀的使用WebGL渲染首屏的文章: 小游戏首屏启动优化 Cocos Creator 微信小游戏平台启动与包体优化(首屏渲染耗时降低 50%) 尤其是第二篇,很多开发者都查资料时查到这一篇文章,按照这篇文章的逻辑来优化小游戏能够达到很理想的效果,本文的思路也是基于该文章之上进一步优化。这两篇文章均是直接使用WebGl渲染首屏,能够达到很理想的效果。强烈先去看一眼这两篇文章及下面的评论,基本上遇到的所有问题都有解答。 但是二者有着各自的缺陷: 第一篇文章简练地介绍了优化思路,但是直接使用的话需要理解WebGL的逻辑并进行改造,存在难度; 第二篇文章是一片很优秀的文章,大家可以先学习一下。该文章中的代码虽然可以直接使用套用,但是代码逻辑和gl渲染的使用方式存在一定的错误,比如重复创建图片,未使用rAF渲染等,这些错误会导致微信客户端统计启动耗时出现异常。然而,因为对gl改写的难度比较大,所以,本文基于第二篇文章中的WebGL渲染首屏的代码进行了改造,附上了正确的使用方式,并额外新增了一份使用Canvas2D渲染首屏的代码。 代码片段 话不多说,附上代码片段: 1. WebGL渲染 webGL代码理解起来还是有难度的,所以代码中的 [代码]webgl_first_render.js[代码]可以直接使用,使用方式可以参考[代码]game.js[代码]。这段代码解决了文章二中的云测启动耗时统计错误、启动黑屏、横屏渲染错误、内存泄漏、屏幕闪烁等异常情况。 代码片段如下: https://developers.weixin.qq.com/s/tknkPjmr7Glg 2. Canvas2D渲染 Canvas2D渲染使用CanvasRenderingContext2D对象 直接渲染。实现上很简单,改造起来也很容易。其实现逻辑是和webgl是一样的。 代码片段如下: https://developers.weixin.qq.com/s/QWno6jmW7Ylx
2020-10-23 - 小程序app.onLaunch与page.onLoad异步问题的最佳实践
场景: 在小程序中大家应该都有这样的场景,在onLaunch里用wx.login静默登录拿到code,再用code去发送请求获取token、用户信息等,整个过程都是异步的,然后我们在业务页面里onLoad去用的时候异步请求还没回来,导致没拿到想要的数据,以往要么监听是否拿到,要么自己封装一套回调,总之都挺麻烦,每个页面都要写一堆无关当前页面的逻辑。 直接上终极解决方案,公司内部已接入两年很稳定: 1.可完美解决异步问题 2.不污染原生生命周期,与onLoad等钩子共存 3.使用方便 4.可灵活定制异步钩子 5.采用监听模式实现,接入无需修改以前相关逻辑 6.支持各种小程序和vue架构 。。。 //为了简洁明了的展示使用场景,以下有部分是伪代码,请勿直接粘贴使用,具体使用代码看Github文档 //app.js //globalData提出来声明 let globalData = { // 是否已拿到token token: '', // 用户信息 userInfo: { userId: '', head: '' } } //注册自定义钩子 import CustomHook from 'spa-custom-hooks'; CustomHook.install({ 'Login':{ name:'Login', watchKey: 'token', onUpdate(token){ //有token则触发此钩子 return !!token; } }, 'User':{ name:'User', watchKey: 'userInfo', onUpdate(user){ //获取到userinfo里的userId则触发此钩子 return !!user.userId; } } }, globalData) // 正常走初始化逻辑 App({ globalData, onLaunch() { //发起异步登录拿token login((token)=>{ this.globalData.token = token //使用token拿用户信息 getUser((user)=>{ this.globalData.user = user }) }) } }) //关键点来了 //Page.js,业务页面使用 Page({ onLoadLogin() { //拿到token啦,可以使用token发起请求了 const token = getApp().globalData.token }, onLoadUser() { //拿到用户信息啦 const userInfo = getApp().globalData.userInfo }, onReadyUser() { //页面初次渲染完毕 && 拿到用户信息,可以把头像渲染在canvas上面啦 const userInfo = getApp().globalData.userInfo // 获取canvas上下文 const ctx = getCanvasContext2d() ctx.drawImage(userInfo.head,0,0,100,100) }, onShowUser() { //页面每次显示 && 拿到用户信息,我要在页面每次显示的时候根据userInfo走不同的逻辑 const userInfo = getApp().globalData.userInfo switch(userInfo.sex){ case 0: // 走女生逻辑 break case 1: // 走男生逻辑 break } } }) 具体文档和Demo见↓ Github:https://github.com/1977474741/spa-custom-hooks 祝大家用的愉快,记得star哦
2023-04-23 - setData 学问多
为什么不能频繁 setData 先科普下 setData 做的事情: 在数据传输时,逻辑层会执行一次 JSON.stringify 来去除掉 setData 数据中不可传输的部分,之后将数据发送给视图层。同时,逻辑层还会将 setData 所设置的数据字段与 data 合并,使开发者可以用 this.data 读取到变更后的数据。 因此频繁调用,视图会一直更新,阻塞用户交互,引发性能问题。 但频繁调用是常见开发场景,能不能频繁调用的同时,视图延迟更新呢? 参考 Vue,我们能知道,Vue 每次赋值操作并不会直接更新视图,而是缓存到一个数据更新队列中,异步更新,再触发渲染,此时多次赋值,也只会渲染一次。 [代码]let newState = null; let timeout = null; const asyncSetData = ({ vm, newData, }) => { newState = { ...newState, ...newData, }; clearTimeout(timeout); timeout = setTimeout(() => { vm.setData({ ...newState, }); newState = null }, 0); }; [代码] 由于异步代码会在同步代码之后执行,因此,当你多次使用 asyncSetData 设置 newState 时,newState 都会被缓存起来,并异步 setData 一次 但同时,这个方案也会带来一个新的问题,同步代码会阻塞页面的渲染。 同步代码会阻塞页面的渲染的问题其实在浏览器中也存在,但在小程序中,由于是逻辑、视图双线程架构,因此逻辑并不会阻塞视图渲染,这是小程序的优点,但在这套方案将会丢失这个优点。 鱼与熊掌不可兼得也! 对于信息流页面,数据过多怎么办 单次设置的数据不能超过 1024kB,请尽量避免一次设置过多的数据 通常,我们拉取到分页的数据 newList,添加到数组里,一般是这么写: [代码]this.setData({ list: this.data.list.concat(newList) }) [代码] 随着分页次数的增加,list 会逐渐增大,当超过 1024 kb 时,程序会报 [代码]exceed max data size[代码] 错误。 为了避免这个问题,我们可以直接修改 list 的某项数据,而不是对整个 list 重新赋值: [代码]let length = this.data.list.length; let newData = newList.reduce((acc, v, i)=>{ acc[`list[${length+i}]`] = v; return acc; }, {}); this.setData(newData); [代码] 这看着似乎还有点繁琐,为了简化操作,我们可以把 list 的数据结构从一维数组改为二维数组:[代码]list = [newList, newList][代码], 每次分页,可以直接将整个 newList 赋值到 list 作为一个子数组,此时赋值方式为: [代码]let length = this.data.list.length; this.setData({ [`list[${length}]`]: newList }); [代码] 同时,模板也需要相应改成二重循环: [代码]<block wx:for="{{list}}" wx:for-item="listItem" wx:key="{{listItem}}"> <child wx:for="{{listItem}}" wx:key="{{item}}"></child> </block> [代码] 下拉加载,让我们一夜回到解放前 信息流产品,总避免不了要做下拉加载。 下拉加载的数据,需要插到 list 的最前面,所以我们应该这样做: [代码]this.setData({ `list[-1]`: newList }) [代码] 哦不,对不起,上面是错的,应该是下面这样: [代码]this.setData({ list: this.data.list.unshift(newList) }); [代码] 这下好,又是一次性修改整个数组,一夜回到解放前… 为了解决这个问题,这里需要一点奇淫巧技: 为下拉加载维护一个单独的二维数组 pullDownList 在渲染时,用 wxs 将 pullDownList reverse 一下 此时,当下拉加载时,便可以只修改数组的某个子项: [代码]let length = this.data.pullDownList.length; this.setData({ [`pullDownList[${length}]`]: newList }); [代码] 关键在于渲染时候的反向渲染: [代码]<wxs module="utils"> function reverseArr(arr) { return arr.reverse() } module.exports = { reverseArr: reverseArr } </wxs> <block wx:for="{{utils.reverseArr(pullDownList)}}" wx:for-item="listItem" wx:key="{{listItem}}"> <child wx:for="{{listItem}}" wx:key="{{item}}"></child> </block> [代码] 问题解决! 参考资料 终极蛇皮上帝视角之微信小程序之告别 setData, 佯真愚, 2018年08月12日
2019-04-11 - canvas的scale设为负数,在ios上没有效果
canvas的scales(-1,1)无法实现左右翻转,在真机Android和开发工具上都是没问题的。在ios上没反应,请问有什么解决办法吗,还是说只能给后端解决了 let scale = -1; canvas.translate((screenWidth - screenWidth * scale) / 2, 0); canvas.scale(scale, 1);
2018-11-05 - wx.getSystemInfoSync() 提供假信息?
简单描述就是:wx.getSystemInfoSync()接口返回的windowHeight与真机调试返回的不符。windowHeight被注释为可使用高度,在开发者工具中减去了tabbar的高度,但真机并没有减去,导致我真机和开发者工具不一样!熬了好几天呢😁😁😁🥴 [图片] [图片] 小程序wx.getSystemInfoSync()返回虚假的windowHeight,这个问题我之前在另一个项目中也遇到过,但是当时以为是别的框架的问题,而这次换回了原生后还出现了这样的问题,我使用自定义tabbar(上次没有使用!)的时候有时候windowHeight是正常计算tabbar的但有时候又不能计算! 具体的情况在小程序开发者工具中和真机调试中出现,还有开发者版本预览。以下是代码截图 这是小程序开发者工具下的样式,计算的高度符合预期,与tabbar的灰色区域能证明,找不到看鼠标指针! [图片] 这是真机调试下的样式,最后一个元素已经超过了预期范围 [图片] 此外!在真机中减去tabbar的高度后显示的效果就是开发者工具的效果,我因为这个判断了wx.getSystemInfoSync()接口没有在真机下减去tabbar的高度 很抱歉由于工作有点忙没有办法提供demo给你们,但是!这个问题复现起来很简单。此外建议升级一下开发者社区的代码块功能,为什么是乱码的?!
2023-07-24 - 获取图片exif元数据信息
官方api并没有关于图片exif信息提取的api,搜索各种资料无果 不过发现了一个js版本的exif.js 直接拿到小程序上并不能使用,经过修改现在可以使用。并没有太多的测试,如果有发现bug希望共同维护一下 直到官方出了可以获取exif的api 使用方法: 1,引入js var myexif = require('../../libs/myexif.js'); 2,调用handleBinaryFile()方法(方法参数是bufferArray) wx.chooseImage({//选择图片 sizeType: ['compressed'],//图片不能经过压缩处理 success(res) { var array = wx.getFileSystemManager().readFileSync(res.tempFilePaths[0] );; var r =myexif.handleBinaryFile(array); console.log(r); } }); 百度网盘(myexif.js): 链接: https://pan.baidu.com/s/1Z84kyPHowXlgyg1czKyu7A 提取码: we9d
2018-11-26 - 微信小程序UI组件库合集
UI组件库合集,大家有遇到好的组件库,欢迎留言评论然后加入到文档里。 第一款: 官方WeUI组件库,地址 https://developers.weixin.qq.com/miniprogram/dev/extended/weui/ 预览码: [图片] 第二款: ColorUI:地址 https://github.com/weilanwl/ColorUI 预览码: [图片] 第三款: vantUI(又名:ZanUI):地址 https://youzan.github.io/vant-weapp/#/intro 预览码: [图片] 第四款: MinUI: 地址 https://meili.github.io/min/docs/minui/index.html 预览码: [图片] 第五款: iview-weapp:地址 https://weapp.iviewui.com/docs/guide/start 预览码: [图片] 第六款: WXRUI:暂无地址 预览码: [图片] 第七款: WuxUI:地址https://www.wuxui.com/#/introduce 预览码: [图片] 第八款: WussUI:地址 https://phonycode.github.io/wuss-weapp/quickstart.html 预览码: [图片] 第九款: TouchUI:地址 https://github.com/uileader/touchwx 预览码: [图片] 第十款: Hello UniApp: 地址 https://m3w.cn/uniapp 预览码: [图片] 第十一款: TaroUI:地址 https://taro-ui.jd.com/#/docs/introduction 预览码: [图片] 第十二款: Thor UI: 地址 https://thorui.cn/doc/ 预览码: [图片] 第十三款: GUI:https://github.com/Gensp/GUI 预览码: [图片] 第十四款: QyUI:暂无地址 预览码: [图片] 第十五款: WxaUI:暂无地址 预览码: [图片] 第十六款: kaiUI: github地址 https://github.com/Chaunjie/kai-ui 组件库文档:https://chaunjie.github.io/kui/dist/#/start 预览码: [图片] 第十七款: YsUI:暂无地址 预览码: [图片] 第十八款: BeeUI:git地址 http://ued.local.17173.com/gitlab/wxc/beeui.git 预览码: [图片] 第十九款: AntUI: 暂无地址 预览码: [图片] 第二十款: BleuUI:暂无地址 预览码: [图片] 第二十一款: uniydUI:暂无地址 预览码: [图片] 第二十二款: RovingUI:暂无地址 预览码: [图片] 第二十三款: DojayUI:暂无地址 预览码: [图片] 第二十四款: SkyUI:暂无地址 预览码: [图片] 第二十五款: YuUI:暂无地址 预览码: [图片] 第二十六款: wePyUI:暂无地址 预览码: [图片] 第二十七款: WXDUI:暂无地址 预览码: [图片] 第二十八款: XviewUI:暂无地址 预览码: [图片] 第二十九款: MinaUI:暂无地址 预览码: [图片] 第三十款: InyUI:暂无地址 预览码: [图片] 第三十一款: easyUI:地址 https://github.com/qq865738120/easyUI 预览码: [图片] 第三十二款 Kbone-UI: 地址 https://wechat-miniprogram.github.io/kboneui/ui/#/ 暂无预览码 第三十三款 VtuUi: 地址 https://github.com/jisida/VtuWeapp 预览码: [图片] 第三十四款 Lin-UI 地址:http://doc.mini.talelin.com/ 预览码: [图片] 第三十五款 GraceUI 地址: http://grace.hcoder.net/ 这个是收费的哦~ 预览码: [图片] 第三十六款 anna-remax-ui npm:https://www.npmjs.com/package/anna-remax-ui/v/1.0.12 anna-remax-ui 地址: https://annasearl.github.io/anna-remax-ui/components/general/button 预览码 [图片] 第三十七款 Olympus UI 地址:暂无 网易严选出品。 预览码 [图片] 第三十八款 AiYunXiaoUI 地址暂无 预览码 [图片] 第三十九款 visionUI npm:https://www.npmjs.com/package/vision-ui 预览码: [图片] 第四十款 AnimaUI(灵动UI) 地址:https://github.com/AnimaUI/wechat-miniprogram 预览码: [图片] 第四十一款 uView 地址:http://uviewui.com/components/quickstart.html 预览码: [图片] 第四十二款 firstUI 地址:https://www.firstui.cn/ 预览码: [图片]
2023-01-10 - Skyline | 快速搞定复杂的分享海报
在小程序中生成海报是一种非常有效的推广方式 用户可以使用小程序的过程中生成小程序海报并分享给他人 通过海报的形式,用户可以直观地了解产品或服务的特点和优势 [图片] 常见绘制海报方式 目前,小程序海报有两种常见的实现方式: · canvas 绘制海报 · 服务端绘制海报 这两种方式各有千秋 canvas 绘制海报使用 canvas 绘制海报主要有以下几个步骤 1、创建 [代码]canvasContext[代码] 2、获取网络图片的本地路径 3、绘制图片、文字等到 [代码]canvas[代码] 4、调用 [代码]wx.canvasToTempFilePath[代码] 导出图片 尽管 canvas 绘制功能强大,但实际使用中,这些操作看似简单,但调试起来却比较麻烦 而且面对一些复杂的排版时,使用 canvas 绘制相较于使用 CSS 绘制来说困难许多 除此之外,canvas 的宽高有最大限制,超出限制则会绘制空白 服务端绘制 小程序也可以通过调用服务端接口,将需要生成海报的数据传递给服务端, 由服务端使用 Canvas API 等第三方库来生成图片。 然而,这种绘制方式需要走网络请求,如果量大会给服务器带来一定的成本压力。 此外,对于复杂排版的实现,使用 Canvas 绘制也有一定的难度。 尽管小程序海报虽然好用,但是当遇到要求比较高的设计稿需要还原海报时,对小程序开发者来说是一个十分让人头疼的问题 考虑到海报在小程序中使用的广泛性,我们把开发者的烦恼交给官方来处理~ 小程序官方推出了 [代码]snapshot[代码] 组件,可以直接将小程序 wxml 导出图片。 snapshot 生成海报 当使用 canvas 或 服务端绘制海报遇到复杂排版时,如 圆角、百分比、自定义字体 等等,实现比较困难。 但是使用 wxml 实现却很简单 👇 下面的例子我们使用 wxml 实现海报 <view class="snapshot-box"> <view class="poster-container"> <view class="poster-header"> <image /> ... </view> <view class="description"> ... </view> <view class="footer"> ... </view> </view> </view> [图片] 接着,我们就可以导出海报啦,使用非常简单: 1、用 [代码]snapshot[代码] 组件包裹海报的 wxml 2、调用 [代码]takeSnapshot[代码] 获取图片数据 3、调用 [代码]fs.writeFileSync[代码] 将海报数据写入本地文件 4、调用 [代码]wx.saveImageToPhotosAlbum[代码] 将海报保存到本地 <snapshot id="view"> <!-- 这里是要海报的 wxml --> </snapshot> <button bindtap="tap">保存海报</button> tap() { this.createSelectorQuery().select("#view") .node().exec(res => { const node = res[0].node // 保存海报 node.takeSnapshot({ type: 'arraybuffer', format: 'png', success: (res) => { const f = `${wx.env.USER_DATA_PATH}/hello.png` const fs = wx.getFileSystemManager(); // 将海报数据写入本地文件 fs.writeFileSync(f, res.data, 'binary') this.setData({ img: f }) // 把海报图片保存到本地 wx.saveImageToPhotosAlbum({ filePath: f }) } }) }) } 最后我们来看看使用 [代码]snapshot[代码] 组件生成海报的效果吧~ [图片] 除了普通尺寸分享海报之外,对于 canvas 无法搞定的超长海报,[代码]snapshot[代码] 后续也会支持超长海报的导出~ [图片] 你的小程序也有海报生成需求吗? 赶紧 mark 下这个 代码片段 来接入使用吧~
2023-09-06 - 小程序的Canvas组件在3.0.0之后,drawImage无法使用离屏画布
您好,我是LeaferJS的创始人,我们正在开发一款可以支持微信小程序的轻量化Canvas 2D图形渲染引擎,比较依赖Canvas组件与离屏画布的交互能力,3.0.0之前的几个版本,我们的用户使用基本都没问题,3.0.0之后Canvas组件drawImage就突然不能绘制离屏画布了。用户通过我们提供的API能够很方便的绘制海报、开发图形编辑工具,在一定程度上可以增强小程序的画布能力,希望官方能够开启这个支持,谢谢~ 在index.wxml中创建Canvas组件,然后在index.js文件中通过drawImage将离屏画布绘制到Canvas中会报错~ 代码片段: https://developers.weixin.qq.com/s/jgljvxmB7CLH 报错内容: [图片]
2023-10-12 - canvas 2d 报错 toTempFilePath:fail invalid viewid?
模拟器没问题,真机一直报 toTempFilePath:fail invalid viewid? 业务是当前页面 需要点击进入别的页面填写内容,然后带参数返回 然后画海报保存 当前页面画直接画海报没问题,返回一直报 toTempFilePath:fail invalid viewid? onReady() { this.drawImage() }, drawImage: function () { let that = this const query = wx.createSelectorQuery() query.select('#myCanvas') .fields({ node: true, size: true }) .exec((res) => { const canvas = res[0].node const canvasRes = res[0] const ctx = canvas.getContext('2d') const dpr = wx.getSystemInfoSync().pixelRatio that.setData({ canvas , canvasRes, ctx, dpr }) }) }, drawImageDetail() { try { let userInfo = this.data.userInfo let canvasRes = this.data.canvasRes let canvas = this.data.canvas let dpr = this.data.dpr let ctx = this.data.ctx let that = this canvas.width = canvasRes.width * dpr canvas.height = canvasRes.height * dpr ctx.scale(dpr, dpr) ctx.fillStyle = 'white' ctx.fillRect(0, 0, canvas.width, canvas.height) ctx.font = '14px DINCondensed-Bold' ctx.fillStyle = '#BEC5CC' ctx.fillText(`生成海报`, 0, 0); setTimeout(() => { wx.canvasToTempFilePath({ canvas: canvas, success(res) { console.log(res.tempFilePath) }, fail(res){ console.log(res) } }) }, 400) } catch (error) { console.log(error) } },
2021-01-20 - 小程序更改checkbox和radio默认样式
1、checkbox checkbox .wx-checkbox-input{ border-radius:50%; width:20px;height:20px; } checkbox .wx-checkbox-input.wx-checkbox-input-checked{ border-color:#F0302F !important; background:#F0302F !important; } checkbox .wx-checkbox-input.wx-checkbox-input-checked::before{ border-radius:50%; width:20px; height:20px; line-height:20px; text-align:center; font-size:15px; color:#fff; background:transparent; transform:translate(-50%, -50%) scale(1); -webkit-transform:translate(-50%, -50%) scale(1); } 2、radio radio .wx-radio-input{ border-radius:50%; width:20px;height:20px; } radio .wx-radio-input.wx-radio-input-checked{ border-color:#F0302F !important; background:#F0302F !important; } radio .wx-radio-input.wx-radio-input-checked::before{ border-radius:50%; width:20px; height:20px; line-height:20px; text-align:center; font-size:15px; color:#fff; background:transparent; transform:translate(-50%, -50%) scale(1); -webkit-transform:translate(-50%, -50%) scale(1); } 如果上面的代码对您有帮助,麻烦抖一抖小手点下赞,谢谢
2018-06-29 - 表格table示例
目的 实现允许编辑的【课程表】。 效果图[图片][图片] wxml代码<view class="mainPage"> <view class="hearderView"> <van-icon class="arrow" bindtap="goHome" name="notes-o" size="20" /> <text class="tipText" style="font-size: 12px;width: 85%;">滑动查看完整课表,长按可以编辑保存。</text> </view> <scroll-view scroll-x="true" scroll-y="true" style="height: {{validHeight-50}}px;"> <view class="table"> <view class="tr h"> <view class="th h1"></view> <view class="th" wx:for="{{[0,1,2,3,4,5,6]}}" wx:key="weekIndex" wx:for-item="weekItem">{{m1.getWeekday(weekItem)}}</view> </view> <block wx:for="{{kebiao.detail}}" wx:key="index" wx:for-item="item"> <view class="tr"> <view class="td c1"> <text>第</text><text>{{item.no+1}}</text><text>节</text> </view> <view class="td c" wx:for="{{item.ke}}" wx:key="index2" wx:for-item="item2" bindlongpress="longpress" data-no="{{item.no}}" data-day="{{index}}"> <text>{{item2.name}}</text> <text>{{item2.time}}</text> <text>{{item2.classroom}}</text> <text>{{item2.teacher}}</text> </view> </view> </block> </view> </scroll-view> <view class="botView" style="width: 100%;height: {{botHeight}}px;"></view> </view> <van-popup show="{{ show }}" position="bottom" custom-style="height: 230px;" bind:close="onClose"> <view class="popView"> <view class="popHeader"> <van-icon class="arrow" bindtap="onClose" name="close" size="20" color="Red" /> <text class="tipText">{{m1.getWeekday(currentKe.day)}} 第{{currentKe.no+1}}节</text> <van-icon class="arrow" bindtap="confirmEdit" name="passed" size="20" color="#1989fa" /> </view> <view class="kebiaoLine"> <text class="label"><text class="kebiaoNo" space="ensp">{{item.no}} </text>课程名</text> <input bindinput="inputText" id="name" value="{{currentKe.ke.name}}"></input> </view> <view class="kebiaoLine"> <text class="label">时间</text> <input bindinput="inputText" id="time" value="{{currentKe.ke.time}}"></input> </view> <view class="kebiaoLine"> <text class="label">教室</text> <input bindinput="inputText" id="classroom" value="{{currentKe.ke.classroom}}"></input> </view> <view class="kebiaoLine"> <text class="label">老师</text> <input bindinput="inputText" id="teacher" value="{{currentKe.ke.teacher}}"></input> </view> </view> </van-popup> <wxs module="m1"> function getWeekday(index) { switch (index) { case 0: return "周一" case 1: return "周二" case 2: return "周三" case 3: return "周四" case 4: return "周五" case 5: return "周六" case 6: return "周日" default: return "" } } module.exports.getWeekday = getWeekday </wxs> js代码data: { kebiao: { totalWeek: 16, currentWeek: 11, currentKe:{day:-1,no:-1,ke:{name:'',time:'',classroom:'',teacher:''}}, detail: [ { no:0, ke:[{name:"计算机组成与结构",time:"1-16周",classroom:"信工楼E536",teacher:"徐苏"}, {name:"",time:"",classroom:"",teacher:""}, {name:"计算机组成与结构",time:"1-16周",classroom:"信工楼E536",teacher:"徐苏"}, {name:"",time:"",classroom:"",teacher:""}, {name:"嵌入式系统",time:"1-16单周",classroom:"信工楼E536",teacher:"周聪"}, {name:"",time:"",classroom:"",teacher:""}, {name:"党课",time:"1-13单周",classroom:"党校B302",teacher:"张三"}] }, }, }, 使用Vant组件 van-popup、van-icon 体验小程序 主页-->小玩艺-->课表日历 [图片]
2021-11-25 - 分享功能调整背后的故事
有时候我们使用一个小程序会遇到以下情形: 我们打开一个小程序,就看见提示“分享到5个群,可以获得一张20元的优惠券”,吸引我们去无脑分享到不同的群里; 打开某个小游戏,提示我“一定要分享到xx个群,才能继续玩游戏”; …… 而我们在群里打开这类小程序,仍然是提示我分享的信息,这类功能无疑打断了我们对小程序/小游戏正常的功能使用。 我们收到了很多用户对这类小程序/小游戏的抱怨。这类分享并非是用户主动自发的,而是受到了某类利益的诱惑,或是被迫分享。这样的内容充斥在群里、小程序里,对用户造成了骚扰,是对分享功能的滥用。 在原来的分享接口中,用户发起分享动作之后,可以通过 success 、fail、complete等回调来判断用户是否完成了最后的分享动作。通过这个能力,开发者是可以将产品交互在分享这个能力上做得比较自然和顺畅。但却被上述情形的小程序滥用。在我们权衡了分享功能带来的利弊后,我们打算回收这个能力。调整为:我们将不再支持分享回调参数 success 、fail 、complete 。即开发者无法判断用户最终是否完成了分享动作,也无法获取到分享成功后的回调参数shareTicket 。 接下来将与大家介绍此次分享功能调整后,小程序的调整建议。 对应小程序调整建议 此次调整可能影响到两种分享功能的用法。 第一种:通过判断用户最终是否有分享来做分支逻辑的小程序。 例如,通过判断 success 回调触发,来判断用户是否分享出去了,进而给奖励,如果用户没有分享出去则不给奖励。这类功能是我们平台不倡导的,后续将没有办法实现。 如果是需要在分享完成后变更当前页面的状态,可以适当调整交互方案。例如过去赠送代金券后显示“等待领取”等应用场景,可以改成在分享后继续保留“赠送”按钮,但提示用户一个代金券只能被一人领取,重复赠送无效。 第二种:获取用户分享之后的 shareTicket ,换取群唯一标识 openGId ,进而显示对应群的相关信息的小程序。 例如,部分小程序实现了群内的排行信息,通过分享小程序到某个群里,可以查看该群内成员的排行榜。 此次调整后,用户分享完成后无法立刻显示该群的排行榜信息,但仍可在用户从群消息点击进入小程序时显示该群的排行榜信息。 因此建议适当修改产品流程,在用户分享小程序之时,提示用户可进入群内查看群排行等信息。避免调整策略生效之后带来的交互不完整影响。 调整覆盖范围提示 近期新提交的版本中将会受到此策略的影响。 除此之外,调整策略在即将发布的基础库版本 2.3.0 生效,该基础库版本对应本月即将发布的微信客户端版本(暂定版本号 6.7.2)。即:近期提交审核的小程序版本,在基础库版本 2.3.0 以下的环境中仍不受此策略影响,仅在基础库版本 2.3.0 以上的环境受影响。 开发者需要注意,近期提交审核的版本都需要考虑兼容上述调整带来的影响,请各位开发者及时调整分享能力。
2018-09-25