- 2019-02-26
- 新能力解读:页面间通信接口
在 2019 年 7 月 2 日的小程序基础库版本更新 v2.7.3 中,小程序新增了一个页面间通讯的接口,帮助我们的小程序完成不同页面间数据同步的功能。 页面间通信接口能干嘛? 在 v2.7.3 之前,小程序不同页面间的大批量数据传递主要有两种: 借助诸如 Mobx 、Redux 等工具,来实现不同页面间的数据传递。 借助小程序提供的 storage ,来完成在不同页面间数据的同步。 前者需要引入一些第三方工具库,从而提升了整个应用的大小,同时,引入的工具也带来了学习生本。而后者则是基于小程序提供的存储,先将数据存入存储,再到另外一个页面去读取,如果数据涉及到了多个页面,则可能会导致数据的紊乱。 新的页面间通信接口则直接解决了上述的两个问题,你可以直接使用 API 在两个页面之间传递数据,再也无需担心数据的紊乱。 新增的页面间通信接口应当如何使用? 关于页面间通信接口的使用非常简单。 这里,我们假设存在 A 和 B 两个页面,其中 A 是首页,B是详情页。 A 向 B 传递数据 如果你需要从首页向详情页传递数据,则可以这样操作。 在页面 A 执行代码 [代码]wx.navigateTo({ url: 'test?id=1' success: function(res) { // 通过eventChannel向被打开页面传送数据 res.eventChannel.emit('acceptDataFromOpenerPage', { data: 'test' }) } }) [代码] 这样,当 A 跳转到 B 时,就会出发 B 当中定义的 acceptDataFromOpenerPage,并将后续的数据传递过去。 在 B 中,你可以在 onLoad 去定义 eventChannel 的相关方法 [代码]Page({ onLoad: function(option){ // 监听acceptDataFromOpenerPage事件,获取上一页面通过eventChannel传送到当前页面的数据 let eventChannel = this.getOpenerEventChannel(); eventChannel.on('acceptDataFromOpenerPage', function(data) { console.log(data) }) } }) [代码] B 向 A 传递数据 如果需要被打开的页面向打开的页面传递数据,则可以使用如下代码: 在 A 中的跳转时,加入 events 的定义,定义你自己的函数,以及对应的处理函数。 [代码]wx.navigateTo({ url: 'test?id=1', events: { someEvent: function(data) { console.log(data) } }, }) [代码] 然后在 B 中,调用如下代码来发信息 [代码]Page({ onLoad: function(option){ const eventChannel = this.getOpenerEventChannel() eventChannel.emit('someEvent', {data: 'test'}); } }) [代码] 这样,就可以在 B 页面将数据传回到 A 页面了。 页面间通信接口使用注意事项? 在使用页面间通信接口时需要注意两点: 该功能从基础库 2.7.3 开始支持,低版本需做兼容处理。
2019-09-21 - 底部输入框获取焦点上推页面
1.首先在wxml的输入框里面添加adjust-position="{{false}}" 2.监听focus事件,通过获取e.detail.height(即弹出的软键盘的高度), 把input的输入框的bottom=e.detail.height * 2 + 'rpx';还须把content 的内容高度减去键盘的高度(值须setData下)。 3.监听失焦(blur)事件,在该方法里,把input输入框的bottom重置为0; 且内容高度为原本的内容高度即可(值须setData下)。 以上三步可完美解决
2018-08-07 - 音频文件在小程序中一直等到完全加载完才会播放
30M的音频文件,在开发工具和通过网页访问的时候都可以很快开始播放,在小程序中 会加载很久, 一直到完全加载完后才会开始播放 音频:http://116.85.23.247/drdfs/M00/00/00/Cv8Bult9KCqAdJkMAnSx3ApHvEU688.MP3 请问这是什么问题,改怎么解决?
2018-08-22 - this.selectComponent is not a function
[图片] 请问这个怎么解决?
2018-06-27 - 小程序与小游戏获取用户信息接口调整,请开发者注意升级。
为优化用户体验,使用 wx.getUserInfo 接口直接弹出授权框的开发方式将逐步不再支持。从2018年4月30日开始,小程序与小游戏的体验版、开发版调用 wx.getUserInfo 接口,将无法弹出授权询问框,默认调用失败。正式版暂不受影响。开发者可使用以下方式获取或展示用户信息: 一、小程序: 1、使用 button 组件,并将 open-type 指定为 getUserInfo 类型,获取用户基本信息。 详情参考文档: https://developers.weixin.qq.com/miniprogram/dev/component/button.html 2、使用 open-data 展示用户基本信息。 详情参考文档: https://developers.weixin.qq.com/miniprogram/dev/component/open-data.html 二、小游戏: 1、使用用户信息按钮 UserInfoButton。 详情参考文档: https://developers.weixin.qq.com/minigame/dev/document/open-api/user-info/wx.createUserInfoButton.html 2、开放数据域下的展示用户信息。 详细参考文档: https://developers.weixin.qq.com/minigame/dev/document/open-api/data/wx.getUserInfo.html 请各位开发者注意及时调整接口。
2018-04-16 - 2019-03-25
- 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