- 云开发环境静态H5页面,跳转到不同小程序不同页面的实现
客户有需求,要短信或者其它场景中的链接静态H5页面,触发打开自家的小程序,官方也提供了 静态网站 H5 跳小程序技术文档(https://developers.weixin.qq.com/miniprogram/dev/wxcloud/guide/staticstorage/jump-miniprogram.html ),不过里面只描述跳转到小程序本身绑定的云开发环境,那么是多个小程序共享的云开发环境如何实现跳转呢,该文档并没有说。 为每个小程序购买一个云开发环境当然是可以,然而,成本似乎似乎太高,不合算,为了给客户节省成本,就给一个小程序买了云开发环境,按照跨账号环境共享设置,实现共享给同主体下的不同小程序(参考:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/guide/resource-sharing/)。 接下来我把最终结果和解决方案,贴出来共享。 场景:首先同公司名下有4个小程序:A、B、C、D,只为A小程序购买了最基础的云开发环境19块,开通静态网站,添加跨账号共享功能,实现访问同一个静态H5页面携带不同参数,打开B、C、D不同小程序的指定页面,无论是微信里还是在手机浏览器均可以跳转。 实现代码: 1、云函数public编写(参考并改进 https://developers.weixin.qq.com/miniprogram/dev/wxcloud/guide/staticstorage/jump-miniprogram.html ) // 云函数入口文件 const cloud = require('wx-server-sdk') cloud.init() // 云函数入口函数 exports.main = async (event, context) => { const wxContext = cloud.getWXContext() switch (event) { case 'getUrlScheme': { return getUrlScheme(event) } } return 'action not found' } async function getUrlScheme(event) { if(event.appid) { var clb = cloud.openapi({ appid: event.appid }); } else{ var clb = cloud.openapi; } return clb.urlscheme.generate({ jumpWxa: { path: event.path, query: event.query, }, // 如果想不过期则置为 false,并可以存到数据库 isExpire: false, // 一分钟有效期 expireTime: parseInt(Date.now() / 1000 + 60), }) } 2、静态H5页面:jump.html <html> <head> <title>H5打开小程序</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <script> window.onerror = e => { console.error(e);alert('发生错误:' + e);} </script> <!-- 调试用的移动端 console --> <!-- <script src="https://cdn.bootcss.com/eruda/1.2.4/eruda.min.js"></script> --> <!-- <script>eruda.init();</script> --> <script> function getQueryParam(key) { const reg = new RegExp('(^|&)' + key + '=([^&]*)(&|$)', 'i'); const r = window.location.search.substr(1).match(reg); if (r != null) { return decodeURI(r[2]); } return null; } //设置 资源环境ID以及绑定的appid var resAppId = '环境宿主Appid';// <!-- replace --> var resEnv = '资源环境ID'; // <!-- replace --> //资源方其它小程序组【AppID,原始id,名称,缺省打开路径】 var appIDs = [ ['wxe6ddf673521da8f0','gh_e4025e37c422','小程序A','pages/webview'], // <!-- replace --> ['wxb1abf1b1fe25f8c6','gh_a4cbe6b9f17f','小程序B',''], // <!-- replace --> ['wx24911b4d9b6971c9','gh_e544c578a3ef','小程序C',''], // <!-- replace --> ['wx6fecac42503a957b','gh_81a6106a84ce','小程序D',''] // <!-- replace --> ]; ////////////////////////////// var launchIdx = getQueryParam('id') || 0; var pagepath = launchIdx== 0 ? appIDs[launchIdx][3] : ""; pagepath = pagepath ? pagepath+(getQueryParam('url') ? "?url="+encodeURIComponent(getQueryParam('url')):"") : ""; pagepath = pagepath ? pagepath : (getQueryParam('page') ? getQueryParam('page'):""); </script> <!-- weui 样式 --> <link rel="stylesheet" href="https://res.wx.qq.com/open/libs/weui/2.4.1/weui.min.css" /> <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script> <script src="https://res.wx.qq.com/open/js/cloudbase/1.1.0/cloud.js"></script> <style>.hidden{display:none}.full{position:absolute;top:0;bottom:0;left:0;right:0}.public-web-container{display:flex;flex-direction:column;align-items:center}.public-web-container p{position:absolute;top:25%}.public-web-container a{position:absolute;bottom:40%}.wechat-web-container{display:flex;flex-direction:column;align-items:center}.wechat-web-container p{position:absolute;top:40%}.wechat-web-container wx-open-launch-weapp{position:absolute;bottom:40%;left:0;right:0;display:flex;flex-direction:column;align-items:center}.desktop-web-container{display:flex;flex-direction:column;align-items:center}.desktop-web-container p{position:absolute;top:40%} </style> </head> <body> <div class="page full"> <div id="public-web-container" class="hidden"> <p>正在唤起微信小程序...</p> <a id="public-web-jump-button" href="javascript:" class="weui-btn weui-btn_primary weui-btn_loading" onclick="openWeapp()"> <span id="public-web-jump-button-loading" class="weui-primary-loading weui-primary-loading_transparent"><i class="weui-primary-loading__dot"></i></span>点击唤起小程序</a> </div> <div id="wechat-web-container" class="hidden"> <script> document.write('<p>请点击下方按钮</p>'); document.write('<wx-open-launch-weapp id="launch-btn" username="'+appIDs[launchIdx][1]+'" path="'+pagepath+'">'); document.write(' <template><button style="width: 240px; height: 45px; text-align: center; font-size: 17px; display: block; margin: 0 auto; padding: 8px 24px; border: none; border-radius: 4px; background-color: #07c160; color:#fff;">打开微信小程序</button></template>'); document.write('</wx-open-launch-weapp>'); </script> </div> <div id="desktop-web-container" class="hidden"><p class="font-size:26px;">请在手机上打开本链接</p></div> </div> <script> function docReady(fn) { if (document.readyState === 'complete' || document.readyState === 'interactive') { fn();} else {document.addEventListener('DOMContentLoaded', fn);} } docReady(async function() { var ua = navigator.userAgent.toLowerCase() var isWXWork = ua.match(/wxwork/i) == 'wxwork'; var isWeixin = !isWXWork && ua.match(/MicroMessenger/i) == 'micromessenger'; var isMobile = isDesktop = false; if (navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|IEMobile)/i)) { isMobile = true } else { isDesktop = true } var isAndroid = ua.indexOf('android') > -1 || ua.indexOf('Adr') > -1; var isOS = ua.indexOf('iPhone') > -1 || ua.indexOf('iPad') > -1 || ua.indexOf('Mac') > -1; if (isWeixin) { var containerEl = document.getElementById('wechat-web-container'); containerEl.classList.remove('hidden'); containerEl.classList.add('full', 'wechat-web-container'); var launchBtn = document.getElementById('launch-btn'); launchBtn.addEventListener('ready', function (e) { console.log('开放标签 ready'); }); launchBtn.addEventListener('launch', function (e) { console.log('开放标签 success'); }); launchBtn.addEventListener('error', function (e) { console.log('开放标签 fail', e.detail);}); wx.config({ debug: false, appId: appIDs[launchIdx][0], // <!-- replace --> timestamp: 0, // 必填,填任意数字即可 nonceStr: 'nonceStr', // 必填,填任意非空字符串即可 signature: 'signature', // 必填,填任意非空字符串即可 jsApiList: ['chooseImage'], // 必填,随意一个接口即可 openTagList:['wx-open-launch-weapp'], // 填入打开小程序的开放标签名 }) } else if (isDesktop) { // 在 pc 上则给提示引导到手机端打开 var containerEl = document.getElementById('desktop-web-container') containerEl.classList.remove('hidden') containerEl.classList.add('full', 'desktop-web-container') } else { //腾讯云开发的免鉴权调用 var containerEl = document.getElementById('public-web-container') containerEl.classList.remove('hidden') containerEl.classList.add('full', 'public-web-container') var c = new cloud.Cloud({ identityless: true, resourceAppid: resAppId, // 资源方宿主 小程序的AppID resourceEnv: resEnv, // 资源方环境ID }) await c.init(); window.c = c; var buttonEl = document.getElementById('public-web-jump-button') var buttonLoadingEl = document.getElementById('public-web-jump-button-loading') try { await openWeapp(() => { buttonEl.classList.remove('weui-btn_loading'); buttonLoadingEl.classList.add('hidden'); }) } catch (e) { console.log('error',e) buttonEl.classList.remove('weui-btn_loading') buttonLoadingEl.classList.add('hidden'); throw e } } } ) async function openWeapp(onBeforeJump) { var c = window.c const res = await c.callFunction({ name: 'public', // 宿主环境中的云函数,注意开启权限 data: { action: 'getUrlScheme', appid: appIDs[launchIdx][0], path : pagepath }, }) if (onBeforeJump) { onBeforeJump(); } location.href = res.result.openlink; } </script> </body> </html> 调用方式:https://xxxx.xxx.xxx/jump.html?id=1&path=my/xwt-apply/xwt-apply (修改成你云环境静态网页的域名) id=1 表示jump.html页面中小程序B,path 表示小程序B中的具体页面。 你可以尝试修改成自己的,实现传参跳转到不同小程序页面。希望对你有帮助!
2023-07-10 - Skyline|长列表也可以丝滑~
[图片] [图片] 对于长列表出现的白屏、卡顿、界面跳动等问题,小程序提供了新 scroll-view 来解决这一系列问题。我们先来看看效果~ 快速滚动效果对比我们通过一组长列表来展示新旧 scroll-view 在快速滚动下的效果对比。 当长列表快速滚动时,旧 scroll-view 容易出现白屏的情况,新 scroll-view 则不会出现白屏。 左:旧 scroll-view、右:新 scroll-view [视频] 在安卓机器快速滚动过程中,旧 scroll-view 反应卡顿,容易出现手指离开操作时,滚动动画还在进行。 而新 scroll-view 则可以保持界面滚动效果跟随手指,停止滚动则缓慢结束动画效果。 左:旧 scroll-view、右:新 scroll-view ,测试机型:Xiaomi MIX 3 [视频] 反向滚动效果对比在对话等场景下,反向滚动是常见的功能,旧 scroll-view 并没有提供反向滚动的能力,我们来看看旧 scroll-view 下是怎么完成反向滚动的~ 在对话数据在加载的时候,对话列表需要在更新完列表数据之后,再使用 scroll-into-view 或者 scroll-top 来保持当前滚动位置,因为设置滚动位置会有延迟,所以容易出现 界面跳动 的情况。 // .js // scroll-view 滚动到顶部时触发 bindscrolltoupper() { // 先更新列表数据 this.setData({ recycleList: getnewList() }, () => { // 更新完数据后再设置滚动位置 this.setData({ scrollintoview: scrollintoview }) }) } 为了解决界面跳动的问题,社区上也有通过翻转的方法来解决,将 scroll-view 与 scroll-view 的子元素进行翻转。 // .wxss .reserve { transform: rotateX(180deg); } // .wxml 然而进行翻转之后,会遇到手指滚动方向与列表滚动方向相反、scroll-into-view 属性无效等问题。 为了帮开发者们解决反向滚动类列表的一系列问题,新 scroll-view 直接提供了 reverse 属性支持反向滚动的能力,滚动效果更加顺滑。 左:旧 scroll-view、右:新 scroll-view(图片加载期间,GIF 渲染较慢) [视频] 怎么接入新 scroll-view ?新的 scroll-view 使用起来很简单,主要有以下两个步骤: 修改小程序配置scroll-view 增加 type="list"// app.json // "renderer": "skyline" 开启之后所有页面会变成自定义导航,可参考 https://developers.weixin.qq.com/s/Y5Y8rrm37qEY 实现自定义导航 // 也可在 page.json 中配置 "renderer": "skyline" 逐个页面开启 { ... "lazyCodeLoading": "requiredComponents", "renderer": "skyline" } // page.json { ... "disableScroll": true, "navigationStyle": "custom" } // page.wxml ... // 反向滚动 新的 scroll-view 从安卓 8.0.28 / iOS 8.0.30 开始支持,如需兼容低版本需要进行兼容处理。 wx.getSkylineInfo({ success(res) { if (res.isSupported) { // 使用新版 scroll-view } else { // 使用旧版 scroll-view } } }) 如需体验长列表效果,可在微信开发者工具导入该代码片段即可体验:https://developers.weixin.qq.com/s/Y5Y8rrm37qEY 更多接入详情请参考文档 怎么做到的?大家肯定好奇为什么新 scroll-view 可以解决这个头疼的问题呢? 我们来对比一下新旧 scroll-view 有什么区别就可以知道答案啦~ 旧 scroll-view 逻辑层与渲染层的通信需要通过 JSBridge 进行转换,需要一定的时间开销渲染采用异步分块光栅化,当渲染赶不上滚动的速度,来不及渲染则会出现白屏渲染大量节点内存占用高,需要开发者自行优化只渲染在屏节点,开发成本高新 scroll-view 逻辑层与渲染层的通信无需通过 JSBridge 进行转换,减少了大量通信时间开销渲染采用同步光栅化,滚动与渲染在同一线程,不会出现白屏针对长列表进行优化,只渲染在屏节点,内存占用低,减少了一些渲染耗时,且开发接入成本低[图片] 除此之外,新 scroll-view 后续将提供 type="custom" 支持 sticky 吸顶效果、网格布局、瀑布流布局等能力便于开发者接入使用~
2023-08-03 - Skyline|小程序吸顶、网格、瀑布流布局都拿下~
在之前的文章中,我们知道了新 scroll-view 可以让小程序的长列表做到丝滑滚动~ 也提到了新 scroll-view 提供了很多新能力 sticky、网格布局、瀑布流布局等,这一篇,我们就来看看这些新能力是怎么使用的~ 新 scroll-view 在原来列表模式(type="list")的基础上,新增了自定义模式(type="custom") 在自定义模式下,新增了以下新组件供开发者调用 list-view:列表布局容器sticky-section / sticky-header:吸顶布局容器grid-view:网格布局容器,可实现网格布局、瀑布流布局等sticky布局sticky 布局即在应用中常见的吸顶布局,与 CSS 中的 position: sticky 实现的效果一致,当组件在屏幕范围内时,会按照正常的布局排列,当组件滚出屏幕范围时,始终会固定在屏幕顶部。 常见的使用场景有:通讯录、账单列表、菜单列表等等。 与 position: sticky 不同的是,position: sticky 很难实现列表滚动需要的交错吸顶效果,而 sticky 组件则可以帮忙开发者轻松实现交错吸顶的效果。 sticky 的使用非常简单: 将 scroll-view 切换到 custom 模式采用 sticky-section 作为 scroll-view 的子元素sticky-header 放置吸顶内容list-view 放置列表内容 {{item.name}} ... 我们来看下采用 sticky 布局做出来的通讯录效果~ [视频] sticky 布局也可以通过给 sticky-section 配置 push-pinned-header 来声明吸顶元素重叠时是否继续上推 像下图输入框和标签列表这种类型,标签列表吸顶时还是希望保留输入框吸顶。 [视频] 网格布局网格布局即将列表切割成格子,每一行的高度固定,常见的视频列表、照片列表等通常都采用网格布局。 在此之前,实现网格布局需要开发者自行实现网格切割,再嵌入到 scroll-view 中。 新 scroll-view 直接提供了 grid-view 组件供开发者使用~ 将 scroll-view 切换到 custom 模式采用 grid-view 类型为 aligned 做为直接子节点grid-view 中直接编写列表 ... 下面是使用网格布局实现的图片列表效果~ [视频] 瀑布流布局瀑布流布局与网格布局类似,不同的是瀑布流布局中每个格子的高度都可以是不一致的,所以在小程序中实现瀑布流布局就比较复杂了。 开发者需要通过计算格子高度,然后再进行瀑布流拼接,当滚动内容过多时还需要处理节点过多导致内存不足等问题。 grid-view 组件直接支持了瀑布流模式供开发者直接使用,grid-view 组件会根据子元素高度自动布局: 将 scroll-view 切换到 custom 模式采用 grid-view 类型为 masonry 做为直接子节点grid-view 中直接编写列表 ... 下面是使用瀑布流布局实现的图片列表效果~ [视频] 想要立即体验?现在通过微信开发者工具导入 代码片段,即可体验新版 scroll-view 组件能力~
2023-08-03 - 如何实现动态生成好友分享图
本文章采用官方最新的 Canvas.createImage() 来实现下动态生成好友分享图,可以拿来即用。展示效果如下(其中蓝框中文案和红框头像为插入的文本、图像。背景图也支持动态更换): [图片] 小程序demo案例:https://developers.weixin.qq.com/s/nJtr4QmL7RD3 一、市面案例缺陷:翻阅了目前市面上的小程序动态生成好友分享图,大部分还是使用已废弃的『wx.createSelectorQuer』接口来实现。目前小程序已无法很好支持。 二、主要有以下几个关键点需要注意下: 做好友分享图要考虑5:4的比例使用 wx.getImageInfo 一定要考虑图片失败的场景,然后采用兜底图片。相同的逻辑在complete中执行。要区分 wx.createImage ,这个是小游戏用来创建图片对象的。小程序要用Canvas.createImage()。也不是使用 new Image!!!使用的时候一定要在 canvas 类型中注明 type 是 2d 的 canvas[图片] 三、优化知识点: 如何用 async in image loading:https://stackoverflow.com/questions/46399223/async-await-in-image-loading ----- 采用await img.decode() 或者 img.onload = () => resolve() 如何隐藏Canvas:https://developers.weixin.qq.com/community/develop/doc/1aadfacdd9f38584881e0c50db2bcda1 ----- position:fixed;left:100%;
2023-06-19 - 小程序用户头像昵称获取规则调整公告
更新时间:2022年11月9日由于 PC/macOS 平台「头像昵称填写能力」存在兼容性问题,对于来自低于2.27.1版本的访问,小程序通过 wx.getUserProfile 接口将正常返回用户头像昵称,插件通过 wx.getUserInfo 接口将正常返回用户头像昵称。 更新时间:2022年9月28日考虑到近期开发者对小程序用户头像昵称获取规则调整的相关反馈,平台将接口回收的截止时间由2022年10月25日延期至2022年11月8日24时。 调整背景在小程序内,开发者可以通过 wx.login 接口直接获取用户的 openId 与 unionId 信息,实现微信身份登录,支持开发者在多个小程序或其它应用间匿名关联同一用户。 同时,为了满足部分小程序业务中需要创建用户的昵称与头像的诉求,平台提供了 wx.getUserProfile 接口,支持在用户授权的前提下,快速使用自己的微信昵称头像。 但实践中发现有部分小程序,在用户刚打开小程序时就要求收集用户的微信昵称头像,或者在支付前等不合理路径上要求授权。如果用户拒绝授权,则无法使用小程序或相关功能。在已经获取用户的 openId 与 unionId 信息情况下,用户的微信昵称与头像并不是用户使用小程序的必要条件。为减少此类不合理的强迫授权情况,作出如下调整。 调整说明自 2022 年 10 月 25 日 24 时后(以下统称 “生效期” ),用户头像昵称获取规则将进行如下调整: 自生效期起,小程序 wx.getUserProfile 接口将被收回:生效期后发布的小程序新版本,通过 wx.getUserProfile 接口获取用户头像将统一返回默认灰色头像,昵称将统一返回 “微信用户”。生效期前发布的小程序版本不受影响,但如果要进行版本更新则需要进行适配。自生效期起,插件通过 wx.getUserInfo 接口获取用户昵称头像将被收回:生效期后发布的插件新版本,通过 wx.getUserInfo 接口获取用户头像将统一返回默认灰色头像,昵称将统一返回 “微信用户”。生效期前发布的插件版本不受影响,但如果要进行版本更新则需要进行适配。通过 wx.login 与 wx.getUserInfo 接口获取 openId、unionId 能力不受影响。「头像昵称填写能力」支持获取用户头像昵称:如业务需获取用户头像昵称,可以使用「头像昵称填写能力」(基础库 2.21.2 版本开始支持,覆盖iOS与安卓微信 8.0.16 以上版本),具体实践可见下方《最佳实践》。小程序 wx.getUserProfile 与插件 wx.getUserInfo 接口兼容基础库 2.27.1 以下版本的头像昵称获取需求:对于来自低版本的基础库与微信客户端的访问,小程序通过 wx.getUserProfile 接口将正常返回用户头像昵称,插件通过 wx.getUserInfo 接口将正常返回用户头像昵称,开发者可继续使用以上能力做向下兼容。对于上述 3,wx.getUserProfile 接口、wx.getUserInfo 接口、头像昵称填写能力的基础库版本支持能力详细对比见下表: [图片] *针对低版本基础库,兼容处理可参考 兼容文档 请已使用 wx.getUserProfile 接口的小程序开发者和已使用 wx.getUserInfo 接口的插件开发者尽快适配。小游戏不受本次调整影响。 最佳实践小程序可在个人中心或设置等页面使用头像昵称填写能力让用户完善个人资料: [图片] 微信团队 2022年5月9日
2023-09-26 - 小程序链接生成与使用规则调整公告
各位开发者: 为确保小程序链接合理使用,自 2022 年 4 月 11 日起,URL Scheme 和 URL Link (以下统称为 “链接” )接口能力规则将进行以下调整: 每个 URL Scheme 或 URL Link 有效期最长 30 天,均不再支持永久有效的链接、不再区分短期有效链接与长期有效链接;链接生成后,若在微信外打开,用户可以在浏览器页面点击进入小程序。每个独立的链接被用户访问后,仅此用户可以再次访问并打开对应小程序,其他用户无法再次通过相同链接打开该小程序;单个小程序每天生成链接数(URL Scheme 和 URL Link 总数)上限为 50 万条。 对于上述 1,在开发层面,相应的服务端接口 urlscheme.generate 和 urllink.generate 将进行以下调整: is_expire 值固定为 true,可不再传该值,若传值为 false 也与 true 一样会生成到期失效链接;若 expire_type 传值为 0,需注意 expire_time 传值的时间戳不超过 30 天,即该参数最长传值有效期为 30 天;若 expire_type 传值为 1,需注意 expire_interval 传值范围为 [1, 30],即该参数最长传值间隔天数为 30。详细对比见下表: [图片] 已使用该后端接口的开发者可以不进行任何修改,不会出现返回异常。若传值超过新规则合法值,或声明使用永久有效的链接,则均会被赋最长有效期值(30天);需注意以上新规则生效后的有效期和访问规则变化。 在本次规则调整生效前已经生成的链接,也将自动生效以下规则: 如果有效期超过30天或长期会被降级为30天有效,开始时间从调整日期开始计算;在调整生效后,只能被1个用户访问。 当前已使用微信云开发 静态网站H5跳小程序 与 短信跳小程序、微信服务平台短信服务为用户提供链接的功能不受影响,但同样适用以上规则。 微信团队 2022年3月9日 相关QAQ1:每天下发的短信量级超过50万条,不够用怎么办? A1:可将生成 scheme 的时机改为在用户打开 H5 时再生成: [图片]
2023-09-26 - 解锁小程序中使用SVG新姿势
SVG 的优势 清晰度: 可以进行放大,而不失真 更小的文件体积 可扩展性,可以动态颜色 动效 可以添加动效 在小程序中使用 目前小程序 的image标签已经支持了 svg 的显示 [代码] <image src="./xx.svg"/> [代码] 如何动态的改变 svg 属性呢? 大体思路:把svg转成 base64 然后通过 image标签 src设置图片,再动态赋值svg颜色 把svg转成base64 如下一个svg 代码文件 [代码]<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="24 24 48 48"><animateTransform attributeName="transform" type="rotate" repeatCount="indefinite" from="0" to="360" dur="1400ms"></animateTransform><circle cx="48" cy="48" r="20" fill="none" stroke="#eeeeee" stroke-width="2" transform="translate\(0,0\)"><animate attributeName="stroke-dasharray" values="1px, 200px;100px, 200px;100px, 200px" dur="1400ms" repeatCount="indefinite"></animate><animate attributeName="stroke-dashoffset" values="0px;-15px;-125px" dur="1400ms" repeatCount="indefinite"></animate></circle></svg> [代码] 转成base64,其实就是 对这个svg进行 encodeURIComponent 得到 如下代码 [代码]%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%2224%2024%2048%2048%22%3E%3CanimateTransform%20attributeName%3D%22transform%22%20type%3D%22rotate%22%20repeatCount%3D%22indefinite%22%20from%3D%220%22%20to%3D%22360%22%20dur%3D%221400ms%22%3E%3C%2FanimateTransform%3E%3Ccircle%20cx%3D%2248%22%20cy%3D%2248%22%20r%3D%2220%22%20fill%3D%22none%22%20stroke%3D%22%23eeeeee%22%20stroke-width%3D%222%22%20transform%3D%22translate%5C(0%2C0%5C)%22%3E%3Canimate%20attributeName%3D%22stroke-dasharray%22%20values%3D%221px%2C%20200px%3B100px%2C%20200px%3B100px%2C%20200px%22%20dur%3D%221400ms%22%20repeatCount%3D%22indefinite%22%3E%3C%2Fanimate%3E%3Canimate%20attributeName%3D%22stroke-dashoffset%22%20values%3D%220px%3B-15px%3B-125px%22%20dur%3D%221400ms%22%20repeatCount%3D%22indefinite%22%3E%3C%2Fanimate%3E%3C%2Fcircle%3E%3C%2Fsvg%3E [代码] 拼接base64 [代码] data:image/svg+xml;charset=utf-8,encodeURIComponent后的代码 [代码] 在对应svg属性上动态设置颜色,比如这里用到的是填充颜色 在js文件 data中定义 color 状态 在wxml中动态渲染 [代码] <image src="data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20viewBox%3D%2224%2024%2048%2048%22%3E%3CanimateTransform%20attributeName%3D%22transform%22%20type%3D%22rotate%22%20repeatCount%3D%22indefinite%22%20from%3D%220%22%20to%3D%22360%22%20dur%3D%221400ms%22%3E%3C%2FanimateTransform%3E%3Ccircle%20cx%3D%2248%22%20cy%3D%2248%22%20r%3D%2220%22%20fill%3D%22none%22%20stroke%3D%22%23{{color}}%22%20stroke-width%3D%222%22%20transform%3D%22translate%5C(0%2C0%5C)%22%3E%3Canimate%20attributeName%3D%22stroke-dasharray%22%20values%3D%221px%2C%20200px%3B100px%2C%20200px%3B100px%2C%20200px%22%20dur%3D%221400ms%22%20repeatCount%3D%22indefinite%22%3E%3C%2Fanimate%3E%3Canimate%20attributeName%3D%22stroke-dashoffset%22%20values%3D%220px%3B-15px%3B-125px%22%20dur%3D%221400ms%22%20repeatCount%3D%22indefinite%22%3E%3C%2Fanimate%3E%3C%2Fcircle%3E%3C%2Fsvg%3E" /> [代码] [代码]注意:这里的颜色 由于是已经被编码了,所以# 已经被转义了 %23, 直接写颜色数字即可[代码] 当然你也可以 去掉%23 自己实现一个内部方法 [代码] if (color && color.startsWith('#')) { return `%23${color.slice(1)}`; } [代码] 这样其实就实现了 svg的动态渲染,可是这种写法,写在wxml中 不是特别的优雅,那么如何重构下让我们的代码看起来更优雅呢? 把 svg 单独存放 支持动态返回 动态赋值 image src 属性 svg 动态函数 loading.svg.js 文件 [代码]export const loadingSvg = (color='#ddd') =>{ const svgXml = `<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="24 24 48 48"><animateTransform attributeName="transform" type="rotate" repeatCount="indefinite" from="0" to="360" dur="1400ms"></animateTransform><circle cx="48" cy="48" r="20" fill="none" stroke="${color}" stroke-width="2" transform="translate\(0,0\)"><animate attributeName="stroke-dasharray" values="1px, 200px;100px, 200px;100px, 200px" dur="1400ms" repeatCount="indefinite"></animate><animate attributeName="stroke-dashoffset" values="0px;-15px;-125px" dur="1400ms" repeatCount="indefinite"></animate></circle></svg>` return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}` } [代码] 逻辑层引入,setData [代码] onLoad(){ const { loadingSvg } = require('./loading.svg.js') const svgImg = loadingSvg('#eee') this.setData({svgImg}) }, [代码] 渲染层使用 [代码] <image src="{{svgImg}}"/> [代码] github 使用案例 demoFormpSvg
2022-04-30 - 小程序性能优化指南
开发者可通过开发者工具中的性能扫描工具提前发现代码中的可优化项: 1. 代码包不包含插件大小超过 1.5 M 【建议】小程序代码包单个包大小限制为2M。因此我们建议开发者在开发时,如果遇到单包体积大于1.5M的情况,可以采取分包的方式,把部分代码拆分到分包去,降低单个包的体积,提升小程序的加载速度。具体可以查看文档《使用分包》。 2. 引用插件大小超过 200 K 【知会】小程序插件的大小是会算进小程序代码包2M体积限制中的。因此当我们发现开发者引用的插件体积大于200K时,会对开发者予以提示,避免出现上传阶段提示代码包体积超限,但是不知道为何超限的问题。 3. 图片和音频资源大小超过 200 K 【建议】小程序代码包里可以存放一些必要的静态资源(如tabbar的icon等);但其他非必要的静态资源体积过大会影响小程序代码包加载速度。因此我们建议图片、音频等静态资源体积大小超过200K时,将它们上传到CDN,用URL引入会是个更好的选择。 4. 主包存在仅被其他分包依赖的JS 【建议】当主包里存在一些JS文件只会被分包使用(而主包自己不使用)时,我们建议把这些JS文件从主包中拆分出去,放到对应的分包里,从而优化主包的加载速度。 5. 主包存在仅被其他分包依赖的组件 【建议】当主包里存在一些组件只会被分包使用(而主包自己不使用)时,我们建议把这些组件从主包拆分出去,并且可以使用 分包异步化 这个特性加载这些组件,从而优化主包的加载速度。 6. 存在无使用的插件 【必须】如果有无使用的插件,请将其从 app.json 中去除。不然它会占用代码包体积,也会延迟代码包加载的时间。 7. 存在无使用的组件 【必须】如果在对应页面JSON的 `usingComponents` 里声明的组件但是没有使用,请将其从 `usingComponents` 里去除。 8. 未开启JS压缩 【必须】在工具「详情」-「本地设置」中开启「上传代码时自动压缩脚本文件」的设置 [图片] 9. 未开启WXML压缩 【必须】在工具「详情」-「本地设置」中开启「上传代码时自动压缩wxml文件」的设置 [图片] 10. 未开启WXSS压缩 【必须】在工具「详情」-「本地设置」中开启「上传代码时自动压缩样式文件」的设置 [图片] 11. 存在无依赖文件 【必须】在「代码质量」面板,点击「建议去除」后,可以打开代码依赖分析面板的「无依赖文件」页面,这里可以看到代码包里没有被用到的文件。请在代码包中去除这部分文件,减小体积并优化加载速度。 在本地开发的过程中,会自动过滤无依赖的文件,如果出现误过滤的情况,可以在 project.config.json 的 setting 字段中添加 ignoreDevUnusedFiles 为 false,也可以在 packOptions 的 include 字段中手动将被忽略的文件引入,同时欢迎发帖反馈误报的情况提交代码片段帮助我们完善此功能 注意:页面若为配置在 app.json 中,将被识别为无依赖文件 [图片] 12. 未开启组件懒注入(按需注入) 【必须】在 app.json 中加入 `"lazyCodeLoading": "requiredComponents"` 可以开启小程序组件按需注入特性。 其他优化内容,请点击学习《小程序性能优化实践》课程 [图片]
2023-02-17 - 2020小程序云开发技术峰会——重新定义开发
[图片] [图片]
2020-11-18 - 小程序多级分销知多少
微信小程序开发者对于小程序生态内的多级分销存在疑惑,今天小编就跟大家一起来梳理下关于多级分销的几个关键点,帮助大家了解哪些在平台内是违规分销行为。 什么是违规分销?三级或三级以上的分销模式就属于违规分销。微信生态拒绝违规分销行为。 二级分销模式:A(厂家)→B(代理) 三级分销模式:A(厂家)→B(代理)→C(代理) 对违规分销行为有初步的了解后,我们来看看微信小程序中常见的具体违规分销案例: l以电商小程序为载体,通过培养用户粉丝,制定分级佣金的形式进行多级分销的行为 [图片] l以“无实物商品”、“虚拟币”多层级分销盈利的庞氏骗局 [图片] l通过购买实物商品获得会员资格发展下线,并以直接或间接发展人员数量和销售业绩作为计酬依据。 [图片] l打着“国家扶持”“民族资产解冻”“民族大业”等旗号的“国家工程” [图片] l以共享经济、物联网、中国梦等名义,大肆发展下线会员牟取暴利 [图片] l免费旅游”“边旅游边赚钱”的旅游骗局,以巨额回报为噱头的金融诈骗 [图片] l以少量资金投入,通过不断的拆分裂变,获得高额盈利吸引用户参与。 [图片]
2020-03-18