- 小程序登录、用户信息相关接口调整说明
公告更新时间:2021年04月15日考虑到近期开发者对小程序登录、用户信息相关接口调整的相关反馈,为优化开发者调整接口的体验,回收wx.getUserInfo接口可获取用户授权的个人信息能力的截止时间由2021年4月13日调整至2021年4月28日24时。为优化用户的使用体验,平台将进行以下调整: 2021年2月23日起,若小程序已在微信开放平台进行绑定,则通过wx.login接口获取的登录凭证可直接换取unionID2021年4月28日24时后发布的小程序新版本,无法通过wx.getUserInfo与<button open-type="getUserInfo"/>获取用户个人信息(头像、昵称、性别与地区),将直接获取匿名数据(包括userInfo与encryptedData中的用户个人信息),获取加密后的openID与unionID数据的能力不做调整。此前发布的小程序版本不受影响,但如果要进行版本更新则需要进行适配。新增getUserProfile接口(基础库2.10.4版本开始支持),可获取用户头像、昵称、性别及地区信息,开发者每次通过该接口获取用户个人信息均需用户确认。具体接口文档:《getUserProfile接口文档》由于getUserProfile接口从2.10.4版本基础库开始支持(覆盖微信7.0.9以上版本),考虑到开发者在低版本中有获取用户头像昵称的诉求,对于未支持getUserProfile的情况下,开发者可继续使用getUserInfo能力。开发者可参考getUserProfile接口文档中的示例代码进行适配。请使用了wx.getUserInfo接口或<button open-type="getUserInfo"/>的开发者尽快适配。开发者工具1.05.2103022版本开始支持getUserProfile接口调试,开发者可下载该版本进行改造。 小游戏不受本次调整影响。 一、调整背景很多开发者在打开小程序时就通过组件方式唤起getUserInfo弹窗,如果用户点击拒绝,无法使用小程序,这种做法打断了用户正常使用小程序的流程,同时也不利于小程序获取新用户。 二、调整说明通过wx.login接口获取的登录凭证可直接换取unionID 若小程序已在微信开放平台进行绑定,原wx.login接口获取的登录凭证若需换取unionID需满足以下条件: 如果开发者帐号下存在同主体的公众号,并且该用户已经关注了该公众号如果开发者帐号下存在同主体的公众号或移动应用,并且该用户已经授权登录过该公众号或移动应用2月23日后,开发者调用wx.login获取的登录凭证可以直接换取unionID,无需满足以上条件。 回收wx.getUserInfo接口可获取用户个人信息能力 4月28日24时后发布的新版本小程序,开发者调用wx.getUserInfo或<button open-type="getUserInfo"/>将不再弹出弹窗,直接返回匿名的用户个人信息,获取加密后的openID、unionID数据的能力不做调整。 具体变化如下表: [图片] 即wx.getUserInfo接口的返回参数不变,但开发者获取的userInfo为匿名信息。 [图片] 此外,针对scope.userInfo将做如下调整: 若开发者调用wx.authorize接口请求scope.userInfo授权,用户侧不会触发授权弹框,直接返回授权成功若开发者调用wx.getSetting接口请求用户的授权状态,会直接读取到scope.userInfo为true新增getUserProfile接口 若开发者需要获取用户的个人信息(头像、昵称、性别与地区),可以通过wx.getUserProfile接口进行获取,该接口从基础库2.10.4版本开始支持,该接口只返回用户个人信息,不包含用户身份标识符。该接口中desc属性(声明获取用户个人信息后的用途)后续会展示在弹窗中,请开发者谨慎填写。开发者每次通过该接口获取用户个人信息均需用户确认,请开发者妥善保管用户快速填写的头像昵称,避免重复弹窗。 插件用户信息功能页 插件申请获取用户头像昵称与用户身份标识符仍保留功能页的形式,不作调整。用户在用户信息功能页中授权之后,插件就可以直接调用 wx.login 和 wx.getUserInfo 。 三、最佳实践调整后,开发者如需获取用户身份标识符只需要调用wx.login接口即可。 开发者若需要在界面中展示用户的头像昵称信息,可以通过<open-data>组件进行渲染,该组件无需用户确认,可以在界面中直接展示。 在部分场景(如社交类小程序)中,开发者需要在获取用户的头像昵称信息,可调用wx.getUserProfile接口,开发者每次通过该接口均需用户确认,请开发者妥善处理调用接口的时机,避免过度弹出弹窗骚扰用户。 微信团队 2021年4月15日
2021-04-15 - 小程序开发小技巧--webview
小程序开发小技巧 --webview 记录下webview 开发调试相关问题,包括常见的小tip,社区相关问题以及本地调试等基本操作。前一段打算写总结,写着发现没有什么干货,今天看见社区朋友提问 webview调试 难道搞个测试还需要去办理后台配置业务不成吗?是的一开始我就是配业务域名,不停的往服务器传包。。。历历在目所以还是梳理记录一下,希望能对社区小伙伴开发有帮助。 常见的 Bug & Tip 常见的小问题 tip:个人类型的小程序暂不支持使用。 tip: navigationStyle: custom 对 web-view 组件无效,也就是自定义导航栏。 tip: src 指向,可打开关联的公众号的文章,其它网页需登录小程序管理后台配置业务域名。 tip: 不希望webview缓存,配置NG或者src后面加随机数。 tip:保持登陆状态传递cookie、token等,简单的可以拼接URL完成。 tip:webview无法进行分享或者支付,常规操作是触发状态后,传递相关信息跳转回小程序进行下一步分享或者支付。 tip:动态改变web-view的标题,直接[代码]document.title[代码]。 tip:需要刷新webview,简单暴力点[代码]windows.onload[代码]。复杂点操作history。 tip:监听web-view返回。一般场景:分享给朋友后,朋友打开进入webview活动页,如果是直接进入的wenview需要点击返回调转至首页。 tip:先调用[代码]wx.miniProgram.navigateBack[代码]在调用[代码]wx.miniProgram.postMessage[代码]。 tip:src中带有中文字符或者特殊字符的,在 iOS 中会有打开白屏的问题,需要转码,建议加一下 encodeURIComponent。 tip: 玄学问题,引入了[代码]weixin-js-sdk[代码],但是怎么也找不到,我后面用npm安装后就ok了。 tip:网页内 iframe 的域名也需要配置到域名白名单。 tip:开发者工具上,可以在 web-view 组件上通过右键 - 调试,打开 web-view 组件的调试。 tip:每个页面只能有一个 web-view,web-view 会自动铺满整个页面,并覆盖其他组件。 tip:web-view 网页与小程序之间不支持除 JSSDK 提供的接口之外的通信。 tip:在 iOS 中,若存在JSSDK接口调用无响应的情况,可在 web-view 的 src 后面加个#wechat_redirect解决。 tip: web-view 官方文档 webview 本地调试 难道搞个测试还需要去办理后台配置业务不成吗?配业务确实特别麻烦,为什么我最初一直自己往服务器传,,,纯属装X。。。其实本地起个web服务器美滋滋。 快速的起个本地web服务。 下面是常用的几种方法、具体用法操作可以百度。 http-server 编辑器或者浏览器中的插件、例如vscode 中的 [代码]live Server[代码]。等等 动手写一个。。 我自己用的是http-server和live Server,用了很久了,能满足需求,就没有关注其它的方法了。 vue开发单页面。 本地开发完成后在打包、进入dist文件、启动http-server、浏览器打开ok、把链接写死在webview的src,像这样 [代码] let url = 'http://127.0.0.1:8080'; // let url = options.url ? options.url : wx.getStorageSync('bargainURL') [代码] 正常的话我们可以先在chrome中调试,基本完成后在进行真机调试。在chrome中可能会涉及到跨域问题,可以开启一个chrome跨域浏览器进行调试,像这样 我是mac上这样,先创建/Users/jinxm/Documents/ChromeData 目录,然后命令行跑一下下面这个命令就OK了。window自行百度就好了。 [代码]open -n /Applications/Google\ Chrome.app/ --args --disable-web-security --user-data-dir=/Users/jinxm/Documents/ChromeData[代码] 这个跨域用的的还蛮多的,于是我配了个输入法快捷输入,像这样👇,方便了很多。 [图片] 真机测试 上面基本ok后,webview 路径写死,手机上看效果。这个时候会不停的改动,然后就会发现不停的npm run build 、 cd dist 、http-server 也变得很繁琐了,那就简单的配置下cli,像这样👇,修改完点一下server就ok了。 [图片] 具体cil配置也就一段话搞定,像这样 ,修改package.json. 配置有点简单,这个cli主要是做单页面使用,可以忽略。使用vue-cli的自己添加个配置文件就好了 [图片] 完结 简单的问题可以私信下。有关webview相关问题欢迎大家一起讨论👏👏👏
2019-10-21 - 微信小程序自定义导航栏组件(完美适配所有手机),可自定义实现任何你想要的功能
背景 在做小程序时,关于默认导航栏,我们遇到了以下的问题: Android、IOS手机对于页面title的展示不一致,安卓title的显示不居中 页面的title只支持纯文本级别的样式控制,不能够做更丰富的title效果 左上角的事件无法监听、定制 路由导航单一,只能够返回上一页,深层级页面的返回不够友好 探索 小程序自定义导航栏已开放许久>>了解一下,相信不少小伙伴已使用过这个功能,同时不少小伙伴也会发现一些坑: 机型多如牛毛:自定义导航栏高度在不同机型始终无法达到视觉上的统一 调皮的胶囊按钮:导航栏元素(文字,图标等)怎么也对不齐那该死的胶囊按钮 各种尺寸的全面屏,奇怪的刘海屏,简直要抓狂 一探究竟 为了搞明白原理,我先去翻了官方文档,>>飞机,点过去是不是很惊喜,很意外,通篇大文尽然只有最下方的一张图片与这个问题有关,并且啥也看不清,汗汗汗… 我特意找了一张图片来 [图片] 分析上图,我得到如下信息: Android跟iOS有差异,表现在顶部到胶囊按钮之间的距离差了6pt 胶囊按钮高度为32pt, iOS和Android一致 动手分析 我们写一个状态栏,通过wx.getSystemInfoSync().statusBarHeight设置高度 Android: [图片] iOS:[图片] 可以看出,iOS胶囊按钮与状态栏之间距离为:4px, Android为8px,是不是所有手机都是这种情况呢? 答案是:苹果手机确实都是4px,安卓大部分都是7和8 也会有其他的情况(可以自己打印getSystemInfo验证)如何快速便捷算出这个高度,请接着往下看 如何计算 导航栏分为状态栏和标题栏,只要能算出每台手机的导航栏高度问题就迎刃而解 导航栏高度 = 胶囊按钮高度 + 状态栏到胶囊按钮间距 * 2 + 状态栏高度 注:由于胶囊按钮是原生组件,为表现一致,其单位在各种手机中都为px,所以我们自定义导航栏的单位都必需是px(切记不能用rpx),才能完美适配。 解决问题 现在我们明白了原理,可以利用胶囊按钮的位置信息和statusBarHeight高度动态计算导航栏的高度,贴一个实现此功能最重要的方法 [代码]let systemInfo = wx.getSystemInfoSync(); let rect = wx.getMenuButtonBoundingClientRect ? wx.getMenuButtonBoundingClientRect() : null; //胶囊按钮位置信息 wx.getMenuButtonBoundingClientRect(); let navBarHeight = (function() { //导航栏高度 let gap = rect.top - systemInfo.statusBarHeight; //动态计算每台手机状态栏到胶囊按钮间距 return 2 * gap + rect.height; })(); [代码] gap信息就是不同的手机其状态栏到胶囊按钮间距,具体更多代码实现和使用demo请移步下方代码仓库,代码中还会有输入框文字跳动解决办法,安卓手机输入框文字飞出解决办法,左侧按钮边框太粗解决办法等等 胶囊信息报错和获取不到 问题就在于 getMenuButtonBoundingClientRect 这个方法,在某些机子和环境下会报错或者获取不到,对于此种情况完美可以模拟一个胶囊位置出来 [代码]try { rect = Taro.getMenuButtonBoundingClientRect ? Taro.getMenuButtonBoundingClientRect() : null; if (rect === null) { throw 'getMenuButtonBoundingClientRect error'; } //取值为0的情况 if (!rect.width) { throw 'getMenuButtonBoundingClientRect error'; } } catch (error) { let gap = ''; //胶囊按钮上下间距 使导航内容居中 let width = 96; //胶囊的宽度,android大部分96,ios为88 if (systemInfo.platform === 'android') { gap = 8; width = 96; } else if (systemInfo.platform === 'devtools') { if (ios) { gap = 5.5; //开发工具中ios手机 } else { gap = 7.5; //开发工具中android和其他手机 } } else { gap = 4; width = 88; } if (!systemInfo.statusBarHeight) { //开启wifi的情况下修复statusBarHeight值获取不到 systemInfo.statusBarHeight = systemInfo.screenHeight - systemInfo.windowHeight - 20; } rect = { //获取不到胶囊信息就自定义重置一个 bottom: systemInfo.statusBarHeight + gap + 32, height: 32, left: systemInfo.windowWidth - width - 10, right: systemInfo.windowWidth - 10, top: systemInfo.statusBarHeight + gap, width: width }; console.log('error', error); console.log('rect', rect); } [代码] 以上代码主要是借鉴了拼多多的默认值写法,android 机子中 gap 值大部分为 8,ios 都为 4,开发工具中 ios 为 5.5,android 为 7.5,这样处理之后自己模拟一个胶囊按钮的位置,这样在获取不到胶囊信息的情况下,可保证绝大多数机子完美显示导航头 吐槽 这么重要的问题,官方尽然没有提供解决方案…竟然提供了一张看不清的图片??? 网上有很多ios设置44,android设置48,还有根据不同的手机型号设置不同高度,通过长时间的开发和尝试,本人发现以上方案并不完美,并且bug很多 代码库 Taro组件gitHub地址详细用法请参考README 原生组件npm构建版本gitHub地址详细用法请参考README 原生组件简易版gitHub地址详细用法请参考README 由于本人精力有限,目前只计划发布维护好这2种组件,其他组件请自行修改代码,有问题请联系 备注 上方2种组件在最下方30多款手机测试情况表现良好 iPhone手机打电话和开热点导致导航栏样式错乱,问题已经解决啦,请去demo里测试,这里特别感谢moments网友提出的问题 本文章并无任何商业性质,如有侵权请联系本人修改或删除 文章少量部分内容是本人查询搜集而来 如有问题可以下方留言讨论,微信zhijunxh 比较 斗鱼: [图片] 虎牙: [图片] 微博: [图片] 酷狗: [图片] 知乎: [图片] [图片] 知乎是这里边做的最好的,但是我个人认为有几个可以优化的小问题 打电话或者开启热点导致样式错落,这也是大部门小程序的问题 导航栏下边距太小,看起来不舒服 搜索框距离2侧按钮组距离不对等 自定义返回和home按钮中的竖线颜色重了,并且感觉太粗 如果您看到了此篇文章,请赶快修改自己的代码,并运用在实践中吧 扫码体验我的小程序: [图片] 创作不易,如果对你有帮助,请移步Taro组件gitHub原生组件gitHub给个星星 star✨✨ 谢谢 测试信息 手机型号 胶囊位置信息 statusBarHeight 测试情况 iPhoneX 80 32 281 369 48 88 44 通过 iPhone8 plus 56 32 320 408 24 88 20 通过 iphone7 56 32 281 368 24 87 20 通过 iPhone6 plus 56 32 320 408 24 88 20 通过 iPhone6 56 32 281 368 24 87 20 通过 HUAWEI SLA-AL00 64 32 254 350 32 96 24 通过 HUAWEI VTR-AL00 64 32 254 350 32 96 24 通过 HUAWEI EVA-AL00 64 32 254 350 32 96 24 通过 HUAWEI EML-AL00 68 32 254 350 36 96 29 通过 HUAWEI VOG-AL00 65 32 254 350 33 96 25 通过 HUAWEI ATU-TL10 64 32 254 350 32 96 24 通过 HUAWEI SMARTISAN OS105 64 32 326 422 32 96 24 通过 XIAOMI MI6 59 28 265 352 31 87 23 通过 XIAOMI MI4LTE 60 32 254 350 28 96 20 通过 XIAOMI MIX3 74 32 287 383 42 96 35 通过 REDMI NOTE3 64 32 254 350 32 96 24 通过 REDMI NOTE4 64 32 254 350 32 96 24 通过 REDMI NOTE3 55 28 255 351 27 96 20 通过 REDMI 5plus 67 32 287 383 35 96 28 通过 MEIZU M571C 65 32 254 350 33 96 25 通过 MEIZU M6 NOTE 62 32 254 350 30 96 22 通过 MEIZU MX4 PRO 62 32 278 374 30 96 22 通过 OPPO A33 65 32 254 350 33 96 26 通过 OPPO R11 58 32 254 350 26 96 18 通过 VIVO Y55 64 32 254 350 32 96 24 通过 HONOR BLN-AL20 64 32 254 350 32 96 24 通过 HONOR NEM-AL10 59 28 265 352 31 87 24 通过 HONOR BND-AL10 64 32 254 350 32 96 24 通过 HONOR duk-al20 64 32 254 350 32 96 24 通过 SAMSUNG SM-G9550 64 32 305 401 32 96 24 通过 360 1801-A01 64 32 254 350 32 96 24 通过
2019-11-17 - 微信小程序setData源码分析
背景 setData 是小程序开发中使用最频繁的接口,也是最容易引发性能问题的接口。详见官网描述 常见的 setData 操作错误 频繁的去 setData 每次 setData 都传递大量新数据 后台态页面进行 setData 针对第二点官网给出意见是,其中 key 可以以数据路径的形式给出,支持改变数组中的某一项或对象的某个属性,如 array[2].message,a.b.c.d,并且不需要在 this.data 中预先定义 下面通过源码深入分析的方式了解小程序是怎么针对数据路径进行组装和构造数据 小程序逻辑层框架源码 微信小程序运行在三端:iOS(iPhone/iPad)、Android 和 用于调试的开发者工具。在开发工具上,小程序逻辑层的 javascript 代码是运行在 NW.js 中,视图层是由 Chromium 60 Webview 来渲染的。这里简单点就直接通过开发者工具来查找源码。 在微信开发者工具中,编译运行你的小程序项目,然后打开控制台,输入 document 并回车,就可以看到小程序运行时,WebView 加载的完整的 WAPageFrame.html,如下图: [图片] 可以看到[代码]./__dev__/WAService.js[代码]这个库就小程序逻辑层基础库,提供逻辑层基础的 API 能力 查找WAService.js源码 在微信小程序 IDE 控制台输入 openVendor 命令,可以打开微信小程序开发工具的资源目录 [图片] 我们可以看到小程序各版本的运行时包 .wxvpkg。.wxvpkg 文件可以使用 wechat-app-unpack 解开,解开后里面就是[代码]WAService.js[代码] 和 [代码]WAWebView.js[代码] 等代码 [图片] 另外也可以只直接通过开发者工具的Sources面板查找到WAService.js的源码 [图片] 分析setData源码 在WAService.js中全局查找setData方法,找到定义此方法的地方,如下 [图片] 源代码使用了大量的逗号运算符,逗号运算符的优先级是最低的,比条件选择符还低 大量使用void 0 表示undefined setData函数定义中添加了关键的注释如下: [代码]function(c, e) { // 保存闭包内的this对象,即常用的that var u = this; // 官网定义 Page.prototype.setData(Object data, Function callback), // 即 c: Object对象,e: Function界面更新渲染完毕后的回调函数 try { // 返回 [object Object] 中的Object var t = v(c); if ("Object" !== t) return void E("类型错误", "setData accepts an Object rather than some " + t); Object.keys(c).forEach(function(e) { // e: 可枚举属性的键值, void 0 表示undefined (https://github.com/lessfish/underscore-analysis/issues/1) void 0 === c[e] && E("Page setData warning", 'Setting data field "' + e + '" to undefined is invalid.'); // t为包含子对象属性名的属性数组, u.data和u.__viewData__都是page.data的深拷贝副本 var t = N(e) , n = j(u.data, t) , r = n.obj , o = n.key; if (r && (r[o] = y(c[e])), void 0 !== c[e]) { var i = j(u.__viewData__, t) , a = i.obj , s = i.key; a && (a[s] = y(c[e])) } }), __appServiceSDK__.traceBeginEvent("Framework", "DataEmitter::emit"), this.__wxComponentInst__.setData(JSON.parse(JSON.stringify(c)), e), __appServiceSDK__.traceEndEvent() } catch (e) { k(e) } } [代码] 关键函数N(e),解析属性名(包含.和[]等数据路径符号),返回相应的层级数组,如 [代码]{abc: 1}中abc属性名 => [abc], {a.b.c: 1}中'a.b.c'属性 => [a,b,c], {"array[0].text": 1} => [array, 0, text][代码] 关键的注释如下 [代码]function N(e) { // 如果属性名不是String字符串就抛出异常 if ("String" !== v(e)) throw E("数据路径错误", "Path must be a string"), new M("Path must be a string"); for (var t = e.length, n = [], r = "", o = 0, i = !1, a = !1, s = 0; s < t; s++) { var c = e[s]; if ("\\" === c) // 如果属性名中包含\\. \\[ \\] 三个转义属性字符就将. [ ]三个字符单独拼接到字符串r中保存,否则就拼接\\ s + 1 < t && ("." === e[s + 1] || "[" === e[s + 1] || "]" === e[s + 1]) ? (r += e[s + 1], s++) : r += "\\"; else if ("." === c) // 遇到.字符并且r字符串非空时,就将r保存到n数组中并清空r; 目的是将{ a.b.c.d: 1 }中的链式属性名分开,保存到数组n中,如[a,b,c,] r && (n.push(r), r = ""); else if ("[" === c) { // 遇到[字符并且r字符串非空时,就将r保存到n数组中并清空r;目的是将{ array[11]: 1 }中的数组属性名保存到数组n中,如[array,] // 如果此时[为属性名的第一个字符就报错,也就是说属性名不能直接为访问器, 如{ [11]: 1} if (r && (n.push(r), r = ""), 0 === n.length) throw E("数据路径错误", "Path can not start with []: " + e), new M("Path can not start with []: " + e); // a赋值为true, i赋值为false i = !(a = !0) } else if ("]" === c) { if (!i) throw E("数据路径错误", "Must have number in []: " + e), new M("Must have number in []: " + e); // 遍历到{ array[11]: 1 }中的']'的时候,就将a赋值为false, 并将o保存到数组n中,如[array,11,] a = !1, n.push(o), o = 0 } else if (a) { if (c < "0" || "9" < c) throw E("数据路径错误", "Only number 0-9 could inside []: " + e), new M("Only number 0-9 could inside []: " + e); // 遍历到{ array[11]: 1 }中的'11'的时候,就将i赋值为true, 并将string类型的数字计算成Number类型保存到o中 i = !0, o = 10 * o + c.charCodeAt(0) - 48 } else r += c // 普通类型的字符就直接拼接到r中 } // 将普通的字符串属性名,.和]后面剩余的字符串保存到数组n中,如{abc: 1} => [abc], {a.b.c: 1} => [a,b,c], {array[0].text: 1} => [array, 0, text] if (r && n.push(r),0 === n.length) throw E("数据路径错误", "Path can not be empty"), new M("Path can not be empty"); return n } [代码] 关键函数j(e, t),解析出属性最终对应的子对象的属性名,以及对应的子对象 [代码]var x = Object.prototype.toString; function _(e) { return "[object Object]" === x.call(e) } function j(e, t) { // e: page.data的深拷贝副本, t为包含子对象属性名的属性数组 /* - 遍历属性数组[a,b], e={a: {b: 1}} 1. i=0, 此时o为Object类型时, n = a, r = {a: {b: 1}}, o = {b: 1}; 2. i=1, 此时o为Object类型时, n = b, r = {b: 1}, o = 1; retrun { obj: {b: 1}, key: b} - 遍历属性数组[a,0,b], e={a: [{b: 1}]} 1. i=0, 此时t[i]=a, o为Object类型时, n = a, r = {a: [{b: 1}]}, o = [{b: 1}]; 2. i=1, 此时t[i]=0, o为Array类型时, n = 0, r = [{b: 1}], o = {b: 1}; 3. i=2, 此时t[i]=b, o为Object类型时, n = b, r = {b: 1}, o = 1; retrun { obj: {b: 1}, key: b} */ for (var n, r = {}, o = e, i = 0; i < t.length; i++) Number(t[i]) === t[i] && t[i] % 1 == 0 ? // t[i]是否为有效的Number Array.isArray(o) || (r[n] = [], o = r[n]) : _(o) || (r[n] = {}, o = r[n]), n = t[i], o = (r = o)[t[i]]; //注意由于逗号分隔符的优先级是最低的,所以这一行会在前面的条件运算符执行完,再执行 return { obj: r, key: n } } [代码] 最后通过[代码]r && (r[o] = y(c[e]))[代码]的方式将新的值赋给匹配出的子对象的属性,这里j(e,t)函数内部是通过引用的方式向外传递出[代码]r[代码],所以这里改变[代码]r[o][代码]的值也会将[代码]u.data[代码]内部的值相应修改,完成局部刷新 由于不同的版本解包后,里面压缩之后的方法名称可能跟上面的对不上,但是大体的结构都是一样的 总结 官方提供的array[2].message,a.b.c.d方式就是通过解析成[array,2,message]和[a,b,c,d],找到相应的子结构进行复制操作,到达减少数据量的目的; 分页加载的时候,为了避免将整个list数据重新传输,就可以利用数据路径的方式只追加新的数据 [代码]假设原数组长度 length 为 10,新数组 newList 长度为 3 this.setData{ 'list[10]': newList[0], 'list[11]': newList[1], 'list[12]': newList[2], } [代码] 参考资料 微信小程序技术原理分析 小程序开发指南
2019-08-24