- Skyline 渲染引擎常见问题
Skyline 一定需要应用到整个小程序吗? 不需要,Skyline 支持按页面粒度开启,建议开发者逐个页面适配 在 Skyline 模式下,为什么使用真机调试会显示空白并且工具报错? 目前 Skyline 模式下暂不支持真机调试,建议使用真机预览完成调试,平台在尽快支持真机调试能力。 在 Skyline 模式下,为什么微信开发者工具热重载无响应? Skyline 模式暂不支持热重载,建议先关闭热重载,重新编译来预览渲染结果。后续平台将支持热重载能力。 开启 Skyline 后布局错乱 大多是由于没有全局滚动而导致挤压,以及 flex-direction 默认为 column 造成。前者只需要加上 scroll-view,后者可以在声明了display:flex 但又没指定 flex-direction的地方显示指定flex-direction:row。推荐开发者开启默认 Block 布局。 切换 Skyline后,为什么顶部原生导航栏消失? 不支持原生导航栏,需自行实现,或使用 weui 组件库 伪类及伪元素部分支持 对于伪类,目前只支持常用的 :first-child 和 :last-child 。其它伪类可通过按需添加 class 替代,如 :active 则手动给点击状态下的节点加个.active class 对于伪元素,目前只支持 ::before 和:after。其它伪元素建议用真实 WXML 节点实现。 全局固定元素失效 因不支持 fixed 导致,但由于没有全局滚动,在页面根节点下使用 absolute 即可达到 fixed 的效果,倘若封装原因无法移至页面根节点,可使用 root-portal 组件包裹 切换 Skyline 后,为什么 position: absolute 相对坐标不准确? 在 Skyline 模式下,所有节点默认是 relative,可能导致 absolute 相对坐标不准。建议开发者修改节点 position 或者修改相对坐标。 多段文本无法内联 因不支持 inline 布局导致,需改成 flex 布局实现,或者使用 text 组件包裹多段文本,而不是用 view 组件包裹,也可以使用 span 组件包裹 text 和 image 混合内联。如 、<span><image /></span>,<span><view style="width: 50px;"/></span> 多行文本的省略样式失效 在单行文本省略的基础上,通过 text 组件的 max-lines 属性设置最长行数,即 <text max-lines="{{2}}"></text> z-index 表现异常 这是由于 Skyline 不支持 web 标准的层叠上下文所致,只有在同层级的节点之前应用 z-index才有效,可根据实际情况调整取值 weui 扩展库无法使用 平台正在支持扩展库,预计近期上线。建议开发者使用 npm 安装 weui 组件库 后,将 node_ modules/weui-miniprogram 下的miniprogram_ dist 替换为 链接 中的 miniprogram_dist,然后在微信开发中工具中构建 npm 即可。 不支持组件 animate 动画接口 暂不支持组件 animate 动画接口。如需实现相关效果,可使用 worklet 动画机制 实现 svg 渲染不正确 Skyline 上的 SVG 不支持 <style> 选择器匹配,可自行转成内联的方式;不支持 rgba 格式,可使用 fill-opacity 替代;建议用 SVGO 在线工具优化 scroll-view 横向滚动不生效 横向滚动需打开 enable-flex 以兼容 WebView,同时 scroll-view 添加样式 display: flex; flex-direction: row;,scroll-view 子节点添加样式 flex-shrink: 0; icon-font 图标不显示 最新版本已支持伪元素,低版本可参考 代码片段 实现图标
2023-10-18 - 2024年微信小程序优化神器:Donut-产品体验分析
写在前面 自古深情留不住,唯有套路得人心! 小程序We分析大家肯定都很熟悉,里边有很多指标,今天只讲其中的两个指标,用户留存率,用户使用时长。要想留住用户,首先需要站在用户的角度去思考,理解他们的痛点和需求。只有深入了解用户的需求,才能为他们提供贴合实际、解决问题的产品和服务。 除非跟用户有很好的互动和良好的反馈(比如开放社区),很多情况我们并不能真正站在用户的角度去考虑,基本是根据以往经验来想象用户的需求。 之前做H5开发,为了统计了解用户的操作情况,都需要自己做一些数据埋点,例如百X统计。这种方式不仅繁琐,且不够直观。 Donut开发平台:产品体验分析 微信Donut开发平台有4大模块:多端框架、安全网关、多端身份登录、产品体验分析。之前对Donut的印象一直停留在前两个模块上面(这里要甩个锅给官方,因为官方一直大力推广这两个模块,看看多端框架和安全网关有多少文章 -.-) 前阵子才发现产品体验分析这个模块,花费5分钟了解,接入功能后3分钟就能看到详细数据分析,感觉相见恨晚。目前这个模块还是公测期间,基本免费使用!不需要一行代码,就能快速发现产品优化的方向! 重点功能推荐 可视化日志 可视化日志可以精准还原用户在小程序内的全部操作过程,就像上帝视角一样。 可视化日志是单个用户完整的一次体验为一条记录,可以通过几十个维度种条件筛选日志。 举个例子:筛选活跃时长小于10S的用户,查看此类用户操作过程来分析用户是对首页功能的不了解还是页面太繁杂找不到自己想要的功能,着重优化首页布局或增加新手引导等设计,优化用户体验时长以及提升留存率! [图片] [图片] 热力图 热力图功能可以非常直观的看到用户高频点击的页面元素和页面滚动的深度,也可以多维度筛选某些条件下的热力图情景,一目了然。 我们可以根据热力详情优化页面的功能、布局等 [图片] 自动生成体验分析报告 用户体验数据有了,自己懒得分析或者刚开始用不知道如何下手,可以看体验分析报告。 体验分析报告会从8个大的维度进行总结分析结果。 例如记录出未访问过的页面,页面最低访问时长 首屏加载速度处于同行业什么水平、什么场景加载速度最慢 用户在什么页面或者什么操作下容易流失 单个页面加载、浏览等数据详情、访问时长分布 重点数据分析: 浏览不足3s的访问、异常事件的出现次数,无效点击的次数 等等等等… [图片] 总结 通过近期对产品体验功能的体验,还是非常推荐这个功能,奇怪的是这么好用的功能平台竟然没有大力推广 不懂技术无所谓,项目所有角色成员基本都能看懂! 目前产品还是在公测中,功能页面可能有一些小BUG,主要功能模块是不影响使用的,目前基本处于免费状态,不需要代码就能体验热力图可视化日志功能,非常赞!希望这个产品继续丰富完善下去。 相关链接 产品体验分析 · 官方文档 功能控制台
08-22 - 微信开放平台更换服务器证书通知
微信开发者: 微信开放平台使用 HTTPS 协议来确保通信的安全性。在开发者调用微信开放平台 API 的过程中,会通过服务器证书来验证微信服务器及其域名的真实性。 由于 Mozilla 信任库更新了其根证书信任策略,微信开放平台计划于 2024 年 10 月 22 日 0:00 开始,逐步更换我们的服务器证书。新的证书将由 DigiCert Global Root G2 签发,替代现有的 DigiCert Global Root CA (G1)。 为确保此次服务器证书更换不会影响到你的正常服务,我们强烈建议你通知贵司技术开发人员仔细阅读我们提供的《微信开放平台新服务器证书兼容性验证指引》,请确保在 2024 年 10 月 22 日 0:00 前完成对微信开放平台新服务器证书的验证。 服务器证书验证仅涉及技术层面的工作,感谢你的理解和配合。 微信团队 2024年7月22日
07-23 - 【微信小程序年审认证】微信小程序一次性认证转变为年审制度?关于小程序年审你想知道的都在这里!
这两年关于小程序,官方进行了大量的改革和变化!如小程序需要备案、手机号快速验证开始收费等,现在小程序认证,也将从一次性认证,转变为年审制度了!微信官方,在这段时间针对小程序年审,也开启了灰度测试,部分来一间商家,也收到来自微信公众平台的小程序年审通知。那关于小程序年审的内容,我们总结在这篇文章,希望能够帮助到来一间商家,提前准备资料,避免错过年审时间,导致小程序无法使用! 小程序年审需要准备哪些材料 营业执照 对公账户信息 认证联系人信息 小程序年审流程 1、登录小程序后台 登录小程序后台(https://mp.weixin.qq.com),收到年审通知的来一间商家,登录以后,会直接在首页显示年审通知,通过“去年审”按钮,可进入微信认证界面! 登录小程序后台-设置-基本设置-微信认证,可以查看到当前小程序认证状态,目前是否需要年审! [图片] 2、同意协议 点击去年审后,第一步为勾选同意《微信公众平台认证服务协议》 [图片] 3、填写资料 选择认证主体类型,根据提示,提交相应的认证材料(营业执照、对公账户、法人信息)可自主选择主体验证方式(对公账户打款、法人扫脸、电子营业执照验证) (个体工商户和企业类型准备材料大体一致,个体工商户无需准备对公账户、验证方式仅为法人扫脸) [图片] 4、确认名称 来一间商家,如有修改小程序名称需求,可在这步进行名称修改,如果名称检查名称不合规,可上传商标进行认证,可能会有原有小程序名,认证不通过的可能,需要注意! (命名规则:账号名不得侵犯注册商标专用权,小程序名称具有唯一性) [图片] 5、发票填写 输入发票基本信息,如发票类型、发票抬头、税号、备注等信息 [图片] 6、费用支付 支付审核费用,目前仅支持微信支付,企业主体需缴纳300元认证费,个人主体目前需缴纳30元认证费;审核时长大概在支付完费用后的1到3天内完成 认证状态查看路径:设置-微信认证-查看,也可以拨打第三方审核公司客服电话进行查询。 提示: 由于认证需要审核过程,建议预留一些时间,避免认证中断,影响小程序正常使用! 小程序年审注意事项 1、之前通过服务商接口进行小程序认证的商家,如有收到年审通知,也需要进行年审 2、因为官方目前对小程序年审制度属于灰度测试,所以暂未收到年审通知的商家,可不用进行年审操作 3、小程序不能通过公众号资质复用进行认证了,选择资质复用,仅会保留认证信息,还需另外缴纳费用! 4、认证审核通过后,有效期为“t+365天”。(注:t 为原认证到期时间) 5、平台将在认证到期前的3个月、2个月、1个月、7天提醒用户进行年审,如未在规定时间内完成年审,将会影响账号功能正常使用。
01-22 - 微信认证年审相关说明
1、微信认证年审的费用需要多少? 微信认证年审费用,跟首次微信认证一样,都是300元/次,是支付给第三方专业审核机构的审核服务费用。 2、微信认证年审时,主体(企业/组织)全称为什么不能修改? 由于认证主体变更,可能出现相关商业收入被盗取到其他企业/组织的情况;同时他人关注公众号是因为它是A企业,如果突然变成B企业,也会降低平台和帐号对用户的公信力。因此,微信认证年审时,认证主体(企业/组织)全称不支持修改。 温馨提示:若同一家企业,只是名称发生变更的情况,可提交工商变更证明材料,审核公司核实属实之后可变更名称。 3、之前已经通过微信认证名称为“A123”年审是否还能用“A123”微信认证帐号命名原则? 只要符合微信认证命名规则,年审时还是可以继续使用“A123”作为帐号名称。 温馨提示: 若同一家企业,只是名称发生变更的情况,可提交变更证明材料,审核公司核实属实之后可变更名称; 保护注册商标原则:帐号名称不得侵犯注册商标专用权,否则、可能不通过帐号名称审核,或被权利人进行侵权投诉; 认证命名唯一原则:帐号名称不得与认证成功时间在先的帐号名称重复,否则将不能通过帐号名称审核。
2020-04-23 - 「体验」通过小程序助手提交小程序审核和发布
前言 在开发小程序的时候,一直困扰的问题就是审核发布每次都需要登陆电脑进行操作,最开始的时候通过手机保存二维码可以直接登陆后台进行操作,后来官方限制了识别二维码无效,所以遇到紧急需要审核发布的时候需要使用2个手机才能进行登陆后台,操作起来十分不方便,现在官方终于支持手机管理小程序了,这个功能还是很好用的。 体验 通过开发者工具中上传代码 [图片] [图片] 打开小程序助手选择“审核管理” [图片] 在审核管理中能看到 线上版、审核版、开发版 信息 [图片] 点开“体验版”可以对体验版进行简单设置,如修改页面路径、取消体验版、获取体验版二维码、删除等。 [图片] 进入提交审核时出现如下2个页面 [图片] [图片] 然后需要输入小程序的基本信息,和PC端基本一致,但是这里会多出一个小程序视频的上传入口,只有版本描述是必填的,其它可以选填,根据自己实际情况输入即可。 [图片] 确认是否需要加急 [图片] 提交审核完成 [图片] 回到审核管理页面可以查看审核进度,也可以选择撤回审核。 [图片] [图片] 审核通过后可直接发布 [图片] [图片] 附: 如果是首次通过小程序助手发布的话,会提示需要验证身份,会通过人脸识别、读数等方式授权(第一次没有截图,第二次后就不会出现了)。 总结 整个提交审核流程体验下来还是很简单方便的,不用再每次登陆mp后台去操作了。
2020-04-04 - 30多个小程序一键发布——miniprogram-ci
概述 miniprogram-ci 是从微信开发者工具中抽离的关于小程序/小游戏项目代码的编译模块。 开发者可不打开小程序开发者工具,独立使用 miniprogram-ci 进行小程序代码的上传、预览等操作。 miniprogram-ci 从 1.0.28 开始支持第三方平台开发的上传和预览,调用方式与普通开发模式无异。查看详情 密钥及 IP 白名单配置 使用 miniprogram-ci 前应访问"微信公众平台-开发-开发设置"后下载代码上传密钥,并配置 IP 白名单 开发者可选择打开 IP 白名单,打开后只有白名单中的 IP 才能调用相关接口。我们建议所有开发者默认开启这个选项,降低风险 代码上传密钥拥有预览、上传代码的权限,密钥不会明文存储在微信公众平台上,一旦遗失必须重置,请开发者妥善保管 [图片] 功能 miniprogram-ci 目前提供以下能力: 上传代码,对应小程序开发者工具的上传 预览代码,对应小程序开发者工具的预览 构建 npm,对应小程序开发者工具的: 菜单-工具-构建npm 上传云开发云函数代码,对应小程序开发者工具的上传云函数能力 上传云托管代码,对应小程序开发者工具的上传云托管能力 上传云存储/静态托管文件,对应小程序开发者工具-云开发-云存储和静态托管文件管理 代理,配置 miniprogram-ci 的网络请求代理方式 支持获取最近上传版本的 sourceMap 支持 node 脚本调用方式和 命令行 调用方式 脚本调用 [代码]npm install miniprogram-ci --save [代码] 代码 preview.js [代码]const ci = require('miniprogram-ci'); const fs = require('fs'); const path = require('path'); let config = { xcxKey: [], //需要上传的小程序列表 version: "", //版本号 desc: "", //备注 appindex: 0 //当前执行到第几个 } exports.start = async () => { //先拿到需要上传的列表,也就是小程序的appid和名称等相关信息,还有上传的版本和备注 fs.readFile( path.join(__dirname, '../xcxkey/xcxkey.json'), 'utf-8', (err, data) => { const fileJson = JSON.parse(data) config.xcxKey = fileJson.xcxKey; config.version = fileJson.version; config.desc = fileJson.desc; config.env = fileJson.env; config.appindex = 0; console.log(`本次提交--${config.xcxKey.map(item=> config.env + item.desc + config.desc)}`); console.log(`版本--${config.version}`); previewStart(); } ); } const previewStart = async () => { if (!config.xcxKey[config.appindex]) { console.log('上传完成') return; } //开始上传,首先修改文件信息 await setProjectConfig(); await setMain(); console.log(`${config.xcxKey[config.appindex].desc}--${config.env}开始`); const project = new ci.Project({ appid: config.xcxKey[config.appindex].appid, type: 'miniProgram', projectPath: path.resolve(__dirname, '../unpackage/dist/dev/mp-weixin'), privateKeyPath: path.resolve(__dirname, `../xcxkey/private.${config.xcxKey[config.appindex].appid}.key`), ignores: ['node_modules/**/*'], }); // 预览 const uploadResult = await ci.preview({ project, version: config.xcxKey[config.appindex].version, desc: `${config.env}——${config.desc}`, setting: { es6: true, minifyJS: true, minifyWXML: true, minifyWXSS: true, minify: true }, qrcodeFormat: 'image', qrcodeOutputDest: path.resolve(__dirname, `../ci/preview-images/${config.xcxKey[config.appindex].title}.jpg`), onProgressUpdate: getstate, pagePath: 'pages/home/index', // 预览页面 searchQuery: '' // 预览参数 [注意!]这里的`&`字符在命令行中应写成转义字符`\&` }); //监听上传过程,如果上传完成延迟10秒再上传下一个 function getstate(e) { console.log('eeee', e); if (e._status === "done" && e._msg === "upload") { console.log(`${config.xcxKey[config.appindex].desc}--${config.env}上传完成`) setTimeout(() => { config.appindex += 1; previewStart(); }, 1000) } } } //修改 project.config.json 内容 const setProjectConfig = async () => { // 要读取和替换的文件路径 const project_config = '../unpackage/dist/dev/mp-weixin/project.config.json'; const promise = new Promise((resolve, reject) => { // 读取 project.config.json fs.readFile( path.join(__dirname, project_config), 'utf8', (err, data) => { if (err) throw err; let json = JSON.parse(data); // 替换 appid 和 projectname json.appid = config.xcxKey[config.appindex].appid; json.projectname = config.xcxKey[config.appindex].name; // 改写 project.config.json 中 appid 和 projectname fs.writeFile( path.join(__dirname, project_config), JSON.stringify(json, null, 4), (err) => { if (err) throw err; resolve(); } ); } ); }); return promise; } //修改 main.js 内容 const setMain = async () => { // 要读取和替换的文件路径 const app_main_file = '../unpackage/dist/dev/mp-weixin/common/main.js'; const promise = new Promise((resolve, reject) => { // 读取 unpackage/dist/dev/mp-weixin/common/main.js fs.readFile( path.join(__dirname, app_main_file), 'utf8', (err, data) => { if (err) throw err; let app_main = data; const hotel_id = config.xcxKey[config.appindex].hotel_id; // 替换 source_hotel_id let re = /(?<=source_hotel_id:").*?(?=",source_hotel_id_end_ci:)/; app_main = app_main.replace(re, hotel_id); // 改写 unpackage/dist/dev/mp-weixin/common/main.js 中 source_hotel_id fs.writeFile( path.join(__dirname, app_main_file), app_main, (err) => { if (err) throw err; resolve(); } ); } ); }); return promise; } [代码] upload.js [代码]const ci = require('miniprogram-ci'); const fs = require('fs'); const path = require('path'); let config = { xcxKey: [], //需要上传的小程序列表 version: "", //版本号 desc: "", //备注 env: "", appindex: 0 //当前执行到第几个 } exports.start = async () => { //先拿到需要上传的列表,也就是小程序的appid和名称等相关信息,还有上传的版本和备注 fs.readFile( path.join(__dirname, '../xcxkey/xcxkey.json'), 'utf-8', (err, data) => { const fileJson = JSON.parse(data) console.log(fileJson); config.xcxKey = fileJson.xcxKey; config.version = fileJson.version; config.desc = fileJson.desc; config.env = fileJson.env; config.appindex = 0; console.log(`本次提交--${config.xcxKey.map(item=> config.env + item.desc)} --- config.desc`); console.log(`版本--${config.version}`); uploadStart(); } ); } const uploadStart = async () => { if (!config.xcxKey[config.appindex]) { console.log('上传完成') return; } //开始上传,首先修改文件信息 await setProjectConfig(); await setMain(); console.log(`${config.xcxKey[config.appindex].desc}--${config.env}开始`); const project = new ci.Project({ appid: config.xcxKey[config.appindex].appid, type: 'miniProgram', projectPath: path.resolve(__dirname, '../unpackage/dist/dev/mp-weixin'), privateKeyPath: path.resolve(__dirname, `../xcxkey/private.${config.xcxKey[config.appindex].appid}.key`), ignores: ['node_modules/**/*'], }); // 上传 const uploadResult = await ci.upload({ project, version: config.xcxKey[config.appindex].version, desc: `${config.env}——${config.desc}`, setting: { es6: true, minifyJS: true, minifyWXML: true, minifyWXSS: true, minify: true }, onProgressUpdate: getstate, }); console.log(uploadResult) //监听上传过程,如果上传完成延迟10秒再上传下一个 function getstate(e) { if (e._status == "done" && e._msg == "upload") { console.log(`${config.xcxKey[config.appindex].desc}--${config.env}上传完成`) setTimeout(() => { config.appindex += 1; uploadStart(); }, 1000) } } } //修改 ext.json 内容 const setExtConfig = async () => { // 要读取和替换的文件路径 const project_config = '../ext.json'; const promise = new Promise((resolve, reject) => { // 读取 project.config.json fs.readFile( path.join(__dirname, project_config), 'utf8', (err, data) => { if (err) throw err; let json = JSON.parse(data); // 替换 appid 和 projectname json.extAppid = config.xcxKey[config.appindex].appid; // 改写 project.config.json 中 appid 和 projectname fs.writeFile( path.join(__dirname, project_config), JSON.stringify(json, null, 4), (err) => { if (err) throw err; resolve(); } ); } ); }); return promise; } //修改 project.config.json 内容 const setProjectConfig = async () => { // 要读取和替换的文件路径 const project_config = '../unpackage/dist/dev/mp-weixin/project.config.json'; const promise = new Promise((resolve, reject) => { // 读取 project.config.json fs.readFile( path.join(__dirname, project_config), 'utf8', (err, data) => { if (err) throw err; let json = JSON.parse(data); // 替换 appid 和 projectname json.appid = config.xcxKey[config.appindex].appid; json.projectname = config.xcxKey[config.appindex].name; // 改写 project.config.json 中 appid 和 projectname fs.writeFile( path.join(__dirname, project_config), JSON.stringify(json, null, 4), (err) => { if (err) throw err; resolve(); } ); } ); }); return promise; } //修改 main.js 内容 const setMain = async () => { // 要读取和替换的文件路径 const app_main_file = '../unpackage/dist/dev/mp-weixin/common/main.js'; const promise = new Promise((resolve, reject) => { // 读取 unpackage/dist/dev/mp-weixin/common/main.js fs.readFile( path.join(__dirname, app_main_file), 'utf8', (err, data) => { if (err) throw err; let app_main = data; const hotel_id = config.xcxKey[config.appindex].hotel_id; // 替换 source_hotel_id let re = /(?<=source_hotel_id:").*?(?=",source_hotel_id_end_ci:)/; app_main = app_main.replace(re, hotel_id); // 改写 unpackage/dist/dev/mp-weixin/common/main.js 中 source_hotel_id fs.writeFile( path.join(__dirname, app_main_file), app_main, (err) => { if (err) throw err; resolve(); } ); } ); }); return promise; } [代码] package.json [代码]{ "scripts": { "upload": "node upload-ci.js", "preview": "node preview-ci.js" }, "dependencies": { "gulp": "^4.0.2", "miniprogram-ci": "^1.8.12" } } [代码] [图片] preview-ci.js [代码] const path = require('path'); const preview = require(path.join(__dirname, './ci/preview')); ; (async () => { preview.start(); })() [代码] upload-ci.js [代码] const path = require('path'); const upload = require(path.join(__dirname, './ci/upload')); ; (async () => { upload.start(); })() [代码] [图片] [代码]{ "xcxKey": [ { "name": "名称", "title": "title", "appid": "appid", "version": "1.0.0", "desc": "备注" }, ... ], "env": "正式环境", "desc": "备注", "version": "1.0.0" } [代码] [代码]// npm run preview(会把xcxkey中的所有小程序打包预览) // npm run upload(会把xcxkey中的所有小程序打包提交体验版) [代码]
2023-07-06 - 小程序点金计划,支付完成之后到点金计划跳转页,怎么跳转回小程序了?
小程序点金计划,支付完成之后到点金计划跳转页,怎么跳转回小程序了?
2023-09-22 - 【本地服务-保健品】类目修改指引说明
代码审核环节,将会对小程序运营的内容与所选类目是否相符进行核实,当小程序涉及提供保健食品在线销售配送或预购自提等服务,需要补充【本地服务-保健品】类目合规提审,否则代码审核环节将面临因类目不符被驳回情形。 一、本地服务-保健品服务,你需要了解: [图片] 注意:申请类目资质时,若当地存在不需要办理相关资质即可从事相关服务内容,建议可提供包含但不限于当地的政策/法规/主管部门等情况材料说明直接申请类目,类目侧会根据提供的材料进一步评估反馈。 二、应用场景示例与整改指引: 【本地服务-保健品】类目:适用于提供保健食品在线销售配送或预购自提等服务。 示例: [图片] 整改建议(2选1): 1、补充选择:本地服务-保健品类目。 2、或自查代码,确保移除保健食品在线销售配送或预购自提等内容及相关分类标签。 本文档为本地服务-保健品类目的介绍说明,如存在上述问题应及时调整、修整,避免后续存在上诉问题审核失败;若仍有其他疑惑,可以通过以下咨询入口反馈: 1、微信开放社区-交流专区-小程序发帖咨询-提出问题-运营相关问题 2、代码审核驳回站内信通知-客服咨询入口(客服咨询入口目前正在测试开放阶段,若无客服入口,建议前往开放社区发帖咨询) 我们会根据新出现的问题、相关法律法规更新或产品运营的需要及时对其内容进行修改并更新,制定新的规则,保证微信用户的体验。建议开发者反复查看以便获得最新信息,定期了解更新情况。
2022-09-02 - 微信支付成功后接口被多次回调是什么原因?
微信支付功能接口,支付成功后回调自己开发的一个发送短信的接口。短信接口被发送了十多次,那么我的客户就陆陆续续的收到了十多条的短信。请相关技术人员电话联系:13621871917,跪谢!
01-15 - image组件自适应高度解决方案
imageload(e){ // console.log("widthwidth",e.detail) var { height, width } = e.detail; // console.log("width/height",width/height) if(height>=width){ if(height/width>2){ this.setData({ imageMode:"aspectFill", imgHeight : 360, imgWidth : 180, }) return }else if(height/width>1.3){ this.setData({ imageMode:"heightFix", imgHeight : 350 }) }else{ this.setData({ imageMode:"heightFix", imgHeight : 320 }) } }else{ var ratio=width/height if(ratio>2){ this.setData({ imageMode:"aspectFill", imgHeight : 250, imgWidth : 500, }) }else if(ratio>1.3){ this.setData({ imageMode:"widthFix", imgWidth : 400 }) }else{ this.setData({ imageMode:"widthFix", imgWidth : 350 }) } } },
06-03 - wx.chooseMedia 为什么压缩了图片,之前都没有?
wx.chooseMedia({ count: 9, mediaType: ['image'], sourceType: ['album'], success: (res) => { }, fail: (res) => { }, }); 图片地址:https://host.weddingbo.com/xlapi/HostManage/HostUserManage/HostSmall/GetStartCode?content=e1691ef1173f46fb92a7526505fbfdca&type=0&branchId=2271 [图片][图片] [图片]
05-29 - 纯js绘制雷达,折线图easyCharts.
[图片][图片] import radarMap from "@/components/radar/radar.vue";//组件引入 export default{ components:{ radarMap }, } polygon:{//参数设置 colorAreaInside:"#5179d7",//区域内圈透明颜色 colorAreaOutside:"#d69384",//区域外圈透明颜色 alpha: 0.4,//2个区域透明值 1~0; dege: 6,//几边形 part: 5,//内圈几个 R: 10,//圆的半径 可以不传参默认height的0.4 } 展示网址:http://jstopo.top
2022-08-30 - 如何使用canvas绘制签名板?
场景分析在小程序业务中如需用户进行手写签名的场景如:寄快递,签约合同时需要在小程序中进行手写签名。 处理方法 实现原理运用 canvas 监听用户 touch 事件,然后在 canvas 上画出与 touch 事件相近的线模仿手写签名效果。 实现方法参考如下代码片段:https://developers.weixin.qq.com/s/MYDTQAmR7EIa [图片]
09-09 - 多端框架用户成功案例
Donut 多端框架是小程序团队推出的移动应用开发框架。开发者可以使用小程序技术与工具,高效率开发移动应用,实现一次开发多端运行。现在已有不同领域的开发者选择多端框架,实现更高的开发经营效率。
07-10 - 小程序webview访问oss的图片资源httpstatus是0,是什么原因导致的?
小程序webview访问oss的图片资源httpstatus是0,可能是什么原因导致的,是小程序哪里设置的不对吗?求指教!
2023-08-13 - 微信小程序实现音频播放动态效果代码片段
微信小程序实现音频播放动态效果代码片段 背景 最近在模拟微信小程序里面背景播放音频时,微信原生的浮窗效果,体验了很多优秀的小程序案例 看到好的效果就想看看代码是怎么写的,发现不少优雅的写法 如下图所示,在底部右下角有个音频播放的动态效果,这个实现的方式很多,前几天看组长代码写的也很独辟蹊径,两个图片互相错一位就搞定了 今天在看下面小程序的代码发现这个实现方式更是别出心裁,竟然没有任何素材 [图片] ~ 代码片段 [图片][图片] [图片] ~ 微信小程序实现音频播放动态效果代码片段
2023-06-14 - ICP备案申请指南
根据工信部管理规定,对经营性互联网信息服务实行许可制度;对非经营性互联网信息服务实行备案制度。未取得许可或者未履行备案手续的,不得从事互联网信息服务。 如你的网站没有申请过ICP备案,根据国家相关规定,可能会对网站的解析产生影响,建议尽快到所在省市的通信管理局完成ICP备案。 【申请地址】请点击这里 温馨提示: 若是点击无法跳转,请复制链接"https://beian.miit.gov.cn/#/Integrated/index“更换其他浏览器打开 【申请流程】 一、ICP信息报备流程图: [图片] 二、ICP信息报备流程: 1.网站主办者登陆接入服务商企业侧系统 网站主办者进行网站备案时可有三种供选择的登录方式: 方式一:网站主办者登录部级系统,通过主页面“自行备案导航”栏目获取为您网站提供接入服务的企业名单(只能选择一个接入服务商),并进入企业侧备案系统办理网站备案业务。 [图片] 方式二:网站主办者登录住所所在地省局系统,通过主页面“自行备案导航”栏目获取为您网站提供接入服务的企业名单(只能选择一个接入服务商),并进入企业侧备案系统办理网站备案业务。 登录部级系统,并找到你所在的省局系统点击办理: [图片] 方式三:网站主办者直接登录到接入服务商企业侧系统。请联系你的接入服务商。 2.网站主办者登陆接入服务商企业系统自主报备信息或由接入服务商代为提交信息: 网站主办者通过三种登录方式(详见1)登录到企业侧系统,注册用户->填写备案信息->接入服务商校验所填信息,反馈网站主办者。 网站主办者委托接入服务商代为报备网站的全部备案信息并核实信息真伪->接入服务商核实备案信息->将备案信息提交到省管局系统。 3.接入服务商核实备案信息流程: 接入服务商对网站主办者提交的备案信息进行当面核验:当面采集网站负责人照片;依据网站主办者证件信息核验提交至接入服务商系统的备案信息;填写《网站备案信息真实性核验单》。如果备案信息无误,接入服务商提交给省管局审核;如果信息有误,接入者在备注栏中注明错误信息提示后退回给网站主办者进行修改。 4.网站主办者所在省通信管理局审核备案信息流程: 网站主办者所在地省管局对备案信息进行审核,审核不通过,则退回企业侧系统由接入服务商修改;审核通过,生成的备案号、备案密码(并发往网站主办者邮箱)和备案信息上传至部级系统,并同时下发到企业侧 1.什么是经营性的互联网信息服务?什么是非经营性互联网信息服务? 根据《国务院互联网信息服务管理办法》(国务院292号令)的第三条规定,“经营性互联网信息服务”是指通过互联网向上网用户有偿提供信息或者网页制作等服务活动。“非经营性互联网信息服务”是指通过互联网向上网用户无偿提供具有公开性、共享性信息的服务活动。 2.如何修改备案信息? 根据现有流程,用户在提交网站备案信息后,可通过接入服务商的企业备案系统修改信息,或者由其接入服务商代为修改,其目的在于强化接入服务商的代备案责任,减轻网站主办者自行备案负担。具体可咨询您的接入服务商。 3.在提交新备案信息时,系统提示主体冲突如何处理? 备案系统对主体的要求必须唯一性,即一个主体只能有一个备案号。判断主体冲突,并不是以主办单位名称为标准,而是依据“主办单位证件类型+证件号码”来判断主体是否唯一的。如果提示主体冲突,就说明该证件号码已经在备案库中存在了。您可以通过备案系统公共查询来查主体证件号码是否已经备案过。如果您要注销该主体冲突,请联系备案号发放地通信管理局,按要求提交相应的证明材料后才可进行注销。 4.在提交新备案信息时,系统提示域名冲突如何处理? 如果您在备案过程中发现您的域名先前已经被别人备案过了,可能是因为您以前已经备案过或者在您注册域名前有人购买过该域名并进行了备案。您还可以在备案网站公共查询中查询该域名的备案地(备案号第一个字是省份的简称),并联系该地通信管理局申请网站注销,按要求提交相应的证明材料后才可进行注销。 5.备案密码忘记了怎么办? 方法一:您可以通过备案系统找回。登陆https://beian.miit.gov.cn/#/Integrated/index,在右下角有“找回备案密码”按钮,选择主体所在省,在跳出的网页中,输入“备案/许可证号、证件类型、证件号码”,输入完成后点提交。如果信息填写正确,系统会向您当年注册的E-mail发送新备案密码。 方法二:如果您的备案信息是接入商代为备案的,您可以联系代为备案的接入商告诉您如何找回备案密码。 方法三:您也可以通过联系备案号发放地通信管理局,并按要求提供相应的证明材料后,取回备案密码。 6.在新、旧备案系统中网站备案的流程是否有差别? 升级后的网站备案管理系统实现了工业和信息化部、各通信管理局、接入服务企业三级备案管理服务模式。在原网站备案管理系统的服务功能基础上,增加了通信管理局级和接入服务企业级网站备案管理系统。网站主办者仅需向接入服务企业提交备案申请,接入服务企业核验后将备案信息提交至通信管理局备案系统,通信管理局进行审核,审核通过后生成备案号发给网站主办者和接入服务企业。 7.网站涉及哪些信息内容应办理前置审批手续? 根据《互联网信息服务管理办法》(国务院292号令)第5条等有关规定,拟从事新闻、出版、教育、医疗保健、药品和医疗器械、文化、广播电影电视节目等互联网信息服务,依照法律、行政法规以及国家有关规定应经有关主管部门审核同意的,在履行备案手续时,还应向其住所所在地省通信管理局提交相关主管部门审核同意的文件。 8.备案的审核时间要多长? 根据《非经营性互联网信息服务备案管理办法》(信息产业部令33号令)第12条规定,省通信管理局在收到备案人提交的备案材料后,材料齐全的,应在二十个工作日内予以备案;材料不齐全的,不予备案,在二十个工作日内通知备案人并说明理由。首次备案的,用户备案信息须经过接入商核实后才会递送到通信管理局进行审核;备案信息修改的,备案信息最后修改日期为起始计算时间。工作日不包含法定节假日和周末。 9.我的网站只有独立的IP地址,没有域名需要办理网上备案手续吗? 需要。无论您的网站是通过域名方式访问或是通过IP地址的方式访问,只要在中华人民共和国境内提供非经营性互联网信息服务都要办理备案手续。 10.如果一个备案单位同时具有两个网站,可以将两个网站分别备案在两个相同的主体下吗? 不可以,如果两个网站的备案主体都是同一个备案单位,那么只能将两个网站备案在同一个主体下。
06-21 - 关于小程序隐私保护指引设置的公告
为规范开发者的用户个人信息处理行为,保障用户的合法权益,自2023年9月15日起,对于涉及处理用户个人信息的小程序开发者,微信要求,仅当开发者主动向平台同步用户已阅读并同意了小程序的隐私保护指引等信息处理规则后,方可调用微信提供的隐私接口。 开发者首先需确定小程序是否涉及处理用户个人信息,如涉及,则需配置用户隐私授权弹窗,且仅有在平台《小程序用户隐私保护指引》中声明了所处理的用户个人信息,才可以调用平台提供的对应接口或组件。(隐私相关接口) 隐私协议设置整体流程参考下方指引: 一、设置《小程序用户隐私保护指引》 开发者需在「小程序管理后台」设置《小程序用户隐私保护指引》 [图片] [图片] 二、填写《小程序用户隐私保护指引》 [图片] 只有在指引中声明所处理的用户个人信息,才可以调用平台提供的对应接口或组件。若未声明,对应接口或组件将无法调用成功。隐私接口与对应的处理的用户个人信息关系可见:小程序用户隐私保护指引内容介绍 三、配置用户隐私授权弹窗 微信提供了wx.onNeedPrivacyAuthorization(function callback) 接口,意为用户触发了一个微信侧未记录过同意的隐私接口调用,开发者可通过响应该事件选择提示用户的时机。此外,微信还提供了 wx.requirePrivacyAuthorize(Object object) 接口,可用于模拟触发 onNeedPrivacyAuthorization 事件。 小程序开发者可自行设计提示方式与触发时机,详细文档可查看隐私协议开发指南。 仅有在指引中声明所处理的用户个人信息,才可以调用平台提供的对应接口或组件。若未声明,对应接口或组件将直接禁用。 [图片] (参考样例) 四、如要进行代码提审,开发者需先自行声明是否有采集用户隐私,如有,则需在提审页面-「用户隐私保护设置」选择“采集用户隐私” [图片]
2023-09-18 - 关于新版隐私协议接口wx.onNeedPrivacyAuthorization的适配解读以及实现代码
官方公告地址: https://developers.weixin.qq.com/community/develop/doc/00042e3ef54940ce8520e38db61801 目前,开发工具或者体验版的小程序,调试基础库如果是2.33.0及以上就得适配了,线上版本9月15日之后生效,所以这之前需要尽快改完,发布一版,否则到了9月15号之后 线上就会生效报错了。 其实改起来也很简单,以下是实现步骤和代码: 1、首先看一下这个网址,里边包含涉及到的隐私的接口,这些接口都要适配一下 https://developers.weixin.qq.com/miniprogram/dev/framework/user-privacy/miniprogram-intro.html [图片] 在以上接口用到的页面,需要画一下类似上边的弹窗(这个弹窗可以全局定义个组件,方便多个页面共用),然后里边蓝字可以点击后调用wx.openPrivacyContract(Object object)接口即可,会自动跳转打开隐私协议页面。 拒绝按钮可以加一个点击事件,然后在事件里这样写 [图片] 同意按钮比较特殊,布局需要用button这样写,记得给button加一个Id [图片] 然后在handleAgreePrivacyAuthorization里就可以获取到点击事件,这样写 [图片] 2、最后需要在onLoad或者onShow里加上以下监听代码,在这里边让自定义的隐私弹窗显示出来即可。 [图片] 以上代码加上就可以了,如果业务逻辑用到了需要判断是否授权过,可以加上 wx.getPrivacySetting(Object object)去获取是否授权过,用不到可以不加这个判断。
2023-08-16 - 场景值1168具体是啥意思?
我们小程序目前只在微信里使用,但是发现有1168的访问来源,这是什么原因呢?
2022-09-13 - wx.requestSubscribeMessage 弹出框的消息订阅默认不选中?
[图片]之前是默认选中的,今天打开手机发现默认不选中了,是怎么回事??
2023-07-25 - 小程序公众号干货运营之注销篇
各位亲,面对帐号注销是不是束手无策呢?帐号如何注销,怎么注销,注销需要提供什么信息内容呢?请仔细往下看看 小程序 关于小程序注销的条件,若未冻结的个人帐号和组织类帐号就不 一 一 细讲,详情请参腾讯客服文档:https://kf.qq.com/product/wx_xcx.html#hid=2826 1:小程序注销之政府无对公账户: 详细流程请参考:https://kf.qq.com/faq/190104YnQbYN190104RzaYba.html 政府的有一致主体是提供一致的主体证件和公章,如果有变更请提供4项材料:因机构改革、单位合并、撤一建一等情况,导致机构主体名称有变更,提供以下材料申请注销: 1、更名相关的红头文件(有鲜章); 2、主体名称变更情况说明书(加盖新主体公章); 3、变更后新主体的主体证件;(原件拍照或加盖公章的复印件) 4、注销申请函(加盖新主体公章); 2:小程序注销之个体工商户 若个体工商户存在对公账户,请使用对公账户小额打款注销 若个体工商户类型无对公账户注销小程序工单指引流程如下 工单所需材料 1、小程序绑定邮箱/原始ID: 2、主体证件材料(营业执照/组织机构代码证等): 3、小程序绑定的法人身份证原件正反面的清晰扫描件或照片: 4、小程序的注销书面申请,申请书必须加盖公章。(若个体户没有公章可支持法人手写签名) 附注:注销申请书模板(https://kf.qq.com/faq/200306R7N3mI200306I3aEBz.html) 材料提交链接:https://kf.qq.com/touch/bill/200306selfqaafe6c551.html(手机端打开) 3:小程序注销之帐号主体已注销 主体已注销小程序工单指引流程如下, 1、小程序绑定邮箱/原始ID: 2、主体注销证明: 3、小程序绑定的法人身份证原件正反面的清晰扫描件或照片: 4、小程序的注销书面申请,企业账号的申请必须有加盖公章的函件(公章被收的请法人手写签字)附注:注销申请书模板(https://kf.qq.com/faq/200306R7N3mI200306I3aEBz.html) 材料提交链接:https://kf.qq.com/touch/bill/200306selfqaafe6c551.html(手机端打开) 4:小程序注销之门店小程序 门店小程序依附于公众号,不支持单独注销,公众号注销门店小程序才支持注销 5:公众号正常运营,门店小程序如何释放昵称 如果需要释放该小店小程序昵称,发送邮件到“miniprogram@tencent.com”,标题格式【关于XXX名称释放请求】,需提供以下材料: 1、小程序帐号(原始ID); 2、绑定的管理员微信号; 3、小程序主体营业执照等主体证件; 4、小程序所有者的书面申请,申请书需加盖小程序主体公章;(个体户无公章:申请书需要加上法人签名); 邮件内容:需包含背景、释放请求原因。 6:复用公众号资质快速注册的小程序如何注销 复用资质申请的小程序是独立存在的,请按照正常流程注销即可 7:注册小程序选择微信认证,若未完成微信认证如何注销呢? 小程序30天未认证或认证失败且7天内未发起认证不会释放邮箱,但该邮箱支持重新注册小程序,会释放主体信息、管理员信息、昵称。 公众号 关于公众号若未冻结的个人帐号和组织类帐号就不一一细讲,详情请参考腾讯客服文档:https://kf.qq.com/product/weixinmp.html#hid=2267 1:公众号注销之政府无对公账户: 详细流程请参考:https://kf.qq.com/faq/190531qyuuiY190531BjyyEv.html 政府的有一致主体是提供一致的主体证件和公章,如果有变更请提供4项材料:因机构改革、单位合并、撤一建一等情况,导致机构主体名称有变更,提供以下材料申请注销: 1、更名相关的红头文件(有鲜章); 2、主体名称变更情况说明书(加盖新主体公章); 3、变更后新主体的主体证件;(原件拍照或加盖公章的复印件) 4、注销申请函(加盖新主体公章); 2:公众号注销之个体工商户 若个体工商户存在对公账户,请使用对公账户小额打款注销 若个体工商户类型无对公账户,请使用法人扫脸注销公众号 详情请参考:https://kf.qq.com/faq/220309bUvmIB220309BbAjMz.html 3:公众号注销之帐号主体已注销 主体已注销公众号工单指引流程如下, 1、公众号绑定邮箱/原始id/微信号: 2、主体注销证明: 3、公众号绑定的法人身份证原件正反面的清晰扫描件或照片: 4、公众号的注销书面申请,企业账号的申请必须有加盖公章的函件(公章被收的请法人手写签字) 附注:注销申请书模板(http://kf.qq.com/faq/171018R3IVBF171018INjUvA.html ) 材料提交链接:https://kf.qq.com/touch/bill/180227selfqa9ab6ac55.html(手机端打开) 4:未注册成功的帐号如何注销 若帐号当时没有走完注册流程且长期没有登录该帐号,到期会被系统注销。没有走完注册流程的帐号不占用个人信息,也不支持找回,建议重新注册 5:注册公众号选择微信认证,若未完成微信认证如何注销呢? 若公众号注册时选择微信认证,自注册日起30天内未进行认证(第30天仍在认证中不算),点击“重新提交材料”,帐号角色变为注册失败,不会释放帐号邮箱,但该邮箱支持重新注册公众号,会释放主体信息、管理员信息、昵称, 6:小程序公众号注销确认期 注销确认期的7天内每天会发送一次确认注销的通知,若管理员一直未点击确认注销则默认取消注销,注销失败。因此管理员请关注公众平台安全助手!!!
2022-04-08 - 码农进阶中的思维变化
一、引子 时光如逝,2023年眨眼已经过去快六分之一了,近来跟同事和朋友聊的时候发现,有小伙伴对未来的发展方向和能力提升方式都有一些迷茫和不知所措,同时跟一些大牛们讨论过如何向上向下汇报、如何推动项目、如何成长,也随之有了一些感悟,借此机会写下来,希望能跟大家能一起探讨探讨。 二、概述 本篇文章的主题是思维变化,即讨论研发人员如何在思维上改变自己的工作和学习习惯从而提升自己的整体水平。 三、思维是什么,对我们有什么影响 思维是人类所具有的高级认识活动。按照信息论的观点,思维是对新输入信息与脑内储存知识经验进行一系列复杂的心智操作过程。分析与综合 是最基本的思维活动。以上来自百度百科哈哈:)。从“思维”两个字中,我们也可以领悟到一些东西,“思”即是思考,比较容易理解,关键在“维”字,“维”有角度、维度的意思。言归正传,对一个码农来说日常的工作就是代码开发,而思维方式会决定我们的代码水平和研发能力的提升。 思维如何影响我们呢,举个经典例子:一家大公司引进了一条肥皂生产线。这条生产线能将肥皂从原材料的加入直到包装装箱自动完成。 但是销售部门反映有的肥皂盒是空的,经理要求工程师们解决这个问题。于是成立一个以几名博士为核心、十几名研究生为骨干的团队。在耗费数十万后,工程师们在生产线上一套X光机和高分辨率监视器,当机器对X光图像进行识别后,一条机械臂会自动将空盒从生产线上拿走。 另外一家乡镇企业也遇到了同样的情况,管理生产线的小工找来一台电风扇,摆在生产线旁。装肥皂的盒子逐一在风扇前通过,只要有空盒子便会被吹离生产线,掉在箩筐里。 [图片] 就从本事例上来说确实一套高科技的检测流程还不如一台电风扇,不同的思维方式导致花费的代价不同。 大家别慌,让我们再换个角度探讨一下,假设我们现在生产的装肥皂的盒子进行了改良更精美也更重了,电风扇吹不动了怎么办;假设我们另一个做罐头的生产线也需要检测罐头里是否有桃子怎么办。 再换个角度看上面的例子,有没有感觉像是我们开发一个很小的项目时,投入了大量的人力物力做了一个apm系统来保障这个小项目的线上正常运行和安排一个同学每天去线上看一眼是不是项目还在正常运行类似,那么大家觉得这个apm系统应该不应该开发?对于这个问题,我们先不着急把答案定下来,看完下面的分析我在再来讨论。 四、研发能力的评判 对于研发的能力,各厂都有自己的职级划分,这里我们举个例子吧(一家之言,大家轻拍) 入门阶段:在他人指导下能够完成比较简单的任务 编码达人:代码的质量和效率都很好,能独立完成任务 独当一面:作为核心骨干能够负责中小型项目的研发管理 技术专家:具备架构设计能力,有实现大型系统的能力 领域专家:行业的领军人物,某个头部系统或者产品的领头人 以上不同的级别对应不同的能力,而我们的成长应该包括两个方面,一个是知识,另一个是思维,两者相辅相成。有了一定的知识会改变我们的思维模式;有了一定的思维模式时,会自动去学习欠缺的知识。知识的学习已经又很多教程了,下面我们先从思维模式上聊一聊。 五、聊聊几种研发中的思维 1、框架思维 软件开发是一种知识活动,因此知识的聚集和积累是至关重要的。框架能够采用一种结构化的方式对某个特定的业务领域进行描述,也就是将这个领域相关的技术以代码、文档、模型等方式固化下来。 2、架构思维 一个系统的运行模式是怎样进行,前后端如何协作、数据如何处理、前端如何展示通用逻辑如何公共和抽象、开发调试部署的流程、功能的可扩展性、服务的稳定性设计、高并发的设计、程序的安全性设计、生态建设等等,我们可以将这些通用的设计从架构层面上进行考虑和实现,而业务开发只需关注业务的逻辑。 3、懒人思维 软件的目标,是某些工作自动化,从而让某些人可以更懒。重复的事情一定不要自己手工重复完成,侧重于自动化。思考如何把这些原来需要很麻烦的事情,自动化执行。比如使用脚手架进行项目的初始化、CI/CD减少项目运维的工作、自动化测试减少测试的工作量。 4、全局思维 任何一个岗位都有其上下游的链接。比如研发的上面有市场,下面有生产。当你写客户软件时,你得站在客户的角度看看方不方便使用、系统稳定不稳定、体验有好不友好;当你设计架构的时候,你得考虑软件工程师方不方便使用;当你设计整个开发流程时,你得考虑团队的效能。更进一步,你的这个技术方案对于公司整体技术方案的适配性怎么样,也应该考虑考虑。 5、系统性的思维 当你在写代码的时候,你很容易就认为只要你按照需求实现了指定的功能,你的代码就写完了。如果想写出真正有影响力的代码,你需要从整个系统去理解你的工作: 1).你的代码和其他人写的代码在功能上是什么关系? 2).你有没有好好测试你的代码?或者其他人是否很容易测试你的代码? 3).为了部署你的代码,线上生产环境的代码是不是需要改动? 4).新的代码会不会影响到已经运行的代码? 5).在新的功能下,你的目标用户的行为是不是你期望的? 6).你的代码有没有产生商业上的影响? 7).你的代码是否兼容老数据?兼容不同的入口场景? 6、创新思维 是指一种能够激发创造力和创新灵感的思考方式。创新思维通常包括挑战常规思维方式的能力、在问题解决中采用多种不同的角度和方法、发掘新的机会、将不同的元素或概念组合起来以创造新的东西等能力。技术的更新迭代很快、软件产品也越来越多,各行各业、时时刻刻都在有创新,别人创造出来了,我们不学习就会落后,只有保持进步和创新才能不被这个时代所抛弃。 以上总共介绍了6种思维(如有遗漏欢迎补充),对我们研发来说,如何通过思维上的改变来提升自己的能力呢? 六、能力进阶与思维改变 对于不同阶段的人,进阶的路线也是不一样的,这里我们还是以之前的职级为例,探讨一下如何通过思维的改变来完成能力的进阶,希望能给对自己的成长路线不太明朗的同学有所帮助。 1、假如你是一个加入到码农行业的同学:希望你能有“框架思维”,在稳固基础知识的同时,能够养成良好的思维习惯,做任务前能够了解何种技术可以实现你的需求,完成任务时做好总结并形成文档,反思自己做的好的地方与不好的地方,将解决过程和避坑经验进行归档,方便后来人的查阅和学习,在日益的积累中,你代码的质量和效率都得到很好的提升; 2、假如你是一个编码达人:希望你能有“系统性的思维”,工作中要不断的思考你负责的模块在整个项目中是属于哪部分,你的程序是如何运行,模块之间是如何互相调用的,项目周期的每个阶段需要做那些事情,了解你的角色以及项目负责人的角色需要做哪些事情。日常工作中要以积极的态度去推动项目的进行、遇到技术卡点问题要多从原理层面进行分析。强烈的责任心、良好业务能力、出众的技术能力是你成为项目负责人所不可或缺的因素。 3、假如你已能独当一面:希望你能在日常工作中不仅仅局限于业务的研发,在代码开发的过程中能有“架构思维”。针对需求的实现,要关注:架构设计的是否合理、性能上是否有不必要的浪费、安全漏洞是否有统一解决方案或防御、公共能力的抽象和使用是否合理、核心业务逻辑的流程是否合理、库表设计是否有空间的浪费等等;技术选型上参考以往类似实现怎么做的,是否还适用、是否要有改进、依赖哪些能力等; 4、假如你是一个技术专家:你需要有“全局思维”、“懒人思维”。你已经拥有架构能力,可以设计项目的架构,但与此同时也更需要关注系统的兼容性、数据迁移方案、可拓展性、稳定性,以及架构提供的能力是否可以让开发者不必关注底层基础能力、公共能力而只专注于业务开发;在开发流程上是否可以做到精简,减少项目上线的流程;通过自动化的检测代码安全、逻辑漏洞、文件格式化、测试等提高开发效率保证运行质量;提供的公共化能力是否有相应的文档建设、测试用例、生态能力;完善基建平台的能力,比如监控系统运行情况的apm、实时更新应用配置的配置中心、应用部署运维的平台、公司内部的管理/工具平台等等;产品的功能是否做到了人无我有、人有我优,交互和性能的体验是否做到了行业领尖,如何做到超越;这些都是我们走向行业顶尖所需要的基本能力; 5、“创新思维”具体对我们研发来说怎么理解呢?我先抛个砖:已有的事物,去研究实现的过程,叫学习或者模仿;知道一些技术或理论,去制造未出现的东西,叫创新。创新比较难,相对而言模仿比较简单,因为我们有行业的标准作为参考,比如“小程序”,自从微信有了这个产品之后,大家竞相模仿;但是相反我们会开发native的app却不一定能创新性的开发出“小程序”。不过创新其实无处不在,我举个例子,假设我们学会来使用游戏引擎Cocos,用它我们可以实现一个“小猪挖土豆”(查了下还真没有)的游戏,这个算是一种创新;如果有实力换种实现方式重新写个游戏引擎,这也是一种创新。保持一种思维习惯,说不定哪天突然灵光一闪,就走上人生巅峰了。 最后呢,我们再看下之前说的一个小项目,我们有没有必要花费大量的人力物力去建一个apm系统?这是一个开放的话题,假设的条件不同答案也不相同,但是我相信很多人已经有了自己的想法了。 七、小结: 谈思维是一件很空洞的事情 ,因为思维实在看不见,摸不清。它不像知识,知之为知之,不知为不知。经常听到人说,你说的我都懂,可我就是做不到,这就是一种思维习惯。所以思维不在于你知道还是不知道,而是一个思维惯性,思考问题的时候,多去提醒自己去往这个维度上想一想,时间久了也就成自然了。ps:如有不合适的地方,请指正~
2023-02-24 - 小程序TypeScript请求封装(TS+request),拿来就能用
最近新开项目,想找一份完整版的ts,封装request完整版都很少,于是最近研究并结合网上的资料进行封装,本api封装支持Promise返回,支持传入泛型,定义返回的数据结构,使用该封装大大减少查看字段及维护难问题。 目录结构 [代码]- miniprogram - api - index.ts - base.ts - system - userApi.ts - utils - request.ts [代码] 封装request 首先,我们先搞wx.request先,这个搞完,其它都是小意思,代码如下:<br/> 文件名称[代码]request.ts[代码] [代码] /** * @description: HTTP请求方法枚举 */ export enum HttpMethod { GET = 'GET', POST = 'POST', OPTIONS = 'OPTIONS', PUT = 'PUT', DELETE = 'DELETE' } /** * @description: HTTP请求配置 */ interface RequestConfig { /** API路径 */ url?: string /** Method类型 */ method?: HttpMethod /** 接口返回数据 */ data?: any /** 无TOKEN触发异常捕获时,是否执行异常逻辑 */ needToken?: boolean /** Header头部 */ header?: object /** 返回的数据格式 */ dataType?: string /** 请求报错时,是否弹出message提示(默认弹出)*/ noShowMsg?: boolean } /** * @description: 声明业务数据类型 */ export interface MyAwesomeData<T> { code: number msg: string data: T } class HttpRequest { private static instance: HttpRequest private constructor() { } /** 请求函数(单例模式) * * **注意:** * `method`需使用`HttpMethod`枚举类,切勿自行定义 * * **示例代码** * ```js HttpRequest.getInstance().request({ url: '/Api', method: HttpMethod.GET }) * ``` */ public static getInstance(): HttpRequest { if (!this.instance) { this.instance = new HttpRequest() } return this.instance } // 处理请求异常状态码 private handerErrorStatus(statusCode: number, requestConfig: RequestConfig) { let msg = '服务找不到' if (statusCode === 502 || statusCode === 503) { msg = '服务器开小差了~' } !requestConfig.noShowMsg && wx.showToast({ title: `${msg},错误码:${statusCode}`, icon: 'none' }) return msg } // 处理请求异常 private handerError(err: { errMsg: string }, requestConfig: RequestConfig) { let msg = `请求异常` if (/timeout/.test(err.errMsg)) { msg = '请求超时' } !requestConfig.noShowMsg && wx.showToast({ title: msg, icon: 'none' }); return msg } // 服务器接口请求 public request<T>(requestConfig: RequestConfig): Promise<MyAwesomeData<T>> { let _this = this return new Promise((resolve, reject) => { // 默认header const contentType = requestConfig.method === 'GET' ? 'application/x-www-form-urlencoded' : 'application/json' const header = { 'content-type': contentType } wx.request({ method: requestConfig.method, url: `${requestConfig.url}`, data: requestConfig.data, header: Object.assign(header, requestConfig?.header), dataType: !requestConfig.dataType ? 'json' : '其他', success: function (res) { // console.log('发送返回:', res) //res:{cookies, data, header, statusCode} const code = res.statusCode || -404 const data = res.data /** 接口请求成功*/ if (code == 200) { resolve(data as any) } else if (code === 401) { // 未授权 !requestConfig.noShowMsg && wx.showModal({ title: '登录失效', content: '登录失效,请重新登录', }).then(resModa => { if (resModa.confirm) { } }) reject({ code, msg: '未登录', data: data }) } else { //非200及401状态码-数据处理 const errMsg = _this.handerErrorStatus(code, requestConfig) reject({ code, msg: errMsg, data }) } }, fail: err => { let msg = _this.handerError(err, requestConfig) reject({ msg }) } }) }) } /** * @description: get请求函数 * @param {string} url 请求地址 * @param {Object} data 请求参数 * @param {RequestConfig} OtherConfig request其他配置 * @return {*} */ public get<T>(url: string, data?: Object, OtherConfig?: RequestConfig) { return this.request<T>({ method: HttpMethod.GET, url, data, ...OtherConfig }) } /** * @description: post请求函数 * @param {string} url 请求地址 * @param {Object} data 请求参数 * @param {RequestConfig} OtherConfig request其他配置 * @return {*} */ public post<T>(url: string, data: Object, OtherConfig?: RequestConfig) { return this.request<T>({ method: HttpMethod.POST, url, data, ...OtherConfig }) } /** * @description: delete请求函数 * @param {string} url 请求地址 * @param {Object} data 请求参数 * @param {RequestConfig} OtherConfig request其他配置 * @return {*} */ public delete<T>(url: string, data: Object, OtherConfig?: RequestConfig) { return this.request<T>({ method: HttpMethod.DELETE, url, data, ...OtherConfig }) } /** * @description: put请求函数 * @param {string} url 请求地址 * @param {Object} data 请求参数 * @param {RequestConfig} OtherConfig request其他配置 * @return {*} */ public put<T>(url: string, data?: Object, OtherConfig?: RequestConfig) { return this.request<T>({ method: HttpMethod.PUT, url, data, ...OtherConfig }) } } export const httpRequest = HttpRequest.getInstance() [代码] 封装接口api 对接口名称进行封装,文件名称api-> system-> userApi.ts [代码]import { httpRequest } from '../../utils/request' const baseUrl = require('../base').allBaseUrl.GDEnvs.host export default class userApi { /** * @description: 获取用户信息 * @return {*} */ static getUserInfo = (data: UserInfo) => httpRequest.post<ReturnUserInfo>( baseUrl + '/mock/getUserInfo', data ) /** * @description: * @return {*} */ static getVillageList = () => httpRequest.get<VillageList>( baseUrl + '/mock/villageList', ) } [代码] 环境判断封装 对环境进行封装,可自行判断,目录:api-> base.ts [代码]/** * 获取小程序版本信息 * 值有:develop(开发版)、trial(体验版)、release(正式版) */ const accountInfo = wx.getAccountInfoSync() const envVersion = accountInfo.miniProgram.envVersion || 'release' /** * 国地服务器 */ const GDEnvs = { develop: { host: 'https://mock.com', imgHost: 'http://192.168.0.2:20087' }, trial: { host: 'http://192.168.0.1:20086', imgHost: 'http://192.168.0.2:20086' }, release: { host: 'https://XXXXX.com', imgHost: 'http://image.XXXXX.com' }, } export class allBaseUrl { /** * 国地服务器 */ static GDEnvs = GDEnvs[envVersion] } [代码] 接口统一输出 对封装好的api接口统一输出,这个非必要,见仁见智,目录api-> index.ts [代码]/* * @Author: caiyongqiang * @Date: 2022-10-20 10:46:54 * @LastEditTime: 2022-10-20 16:58:01 * @LastEditors: caiyongqiang * @Description: */ import userApi from './system/userApi' class apis { /** * @description: 用户相关Api */ static userApi = userApi } export default apis [代码] 页面使用 在页面中可以直接api/index.ts引入使用 [代码]import $api from '../../api/index' // 调用 $api.userApi.getUserInfo({ username: 'demo', password: '123456' }).then((res) => { if (res.code === 200) { userStore.setUserInfo(res.data.userInfo) } }) [代码]
2022-11-11 - 微信小程序头像昵称实战篇
2022-08-25 api文档地址: https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/userProfile.html 目前的api变更后,得到的地址为 临时地址, 这个是文档没有说明的, 最佳实践,是需要把得到的地址上传到自己的服务器,然后用服务器返回的地址作为 真实头像的永久地址. 核心点说明: //获取到api返回的新地址路径 onChooseAvatar(e) { this.avatarUrl = e.detail.avatarUrl console.log('e.detail', e.detail) // this.updateUserInfo(); this.uploadFile(); }, /* 上传 头像 转 话格式*/ uploadFile(){ uni.uploadFile({ url: config.webUrl + '/upload/uploadImages',//后台接口 filePath: this.avatarUrl,// 上传图片 url name:'image', // formData: this.formData, header: { 'content-type': 'multipart/form-data', 'token': uni.getStorageSync('token') }, // header 值 success: res => { let obj = JSON.parse(res.data) console.log('obj', obj) if (obj.code == 1) { let imgUrl = obj.data.full_path; this.userImg = imgUrl; this.updateUserInfo(); } else { uni.showToast({ icon: 'none', title: '图片太大,请重新选择!' }); } }, fail: e => { this.$toast('上传失败') } }); }, 这里需要注意, wx.uploadFile 返回的是字符串类型,需要前端自己处理一下数据结构: [图片] 完整代码如下: import config from "@/common/config.js"; import {debounce} from '@/utils/debounce.js' export default { data() { return { defaultAvatarUrl: 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0', avatarUrl: '', nick_name: '', userImg: '', } }, onLoad() { let userInfo = uni.getStorageSync('userInfo') || {}; let { nick_name,img_url } = {...userInfo}; this.userImg = img_url; this.nick_name = nick_name; }, methods: { onChooseAvatar(e) { this.avatarUrl = e.detail.avatarUrl console.log('e.detail', e.detail) // this.updateUserInfo(); this.uploadFile(); }, inputWord: debounce(function(e){ this.nick_name = e.detail.value console.log('this.nick_name.length',this.nick_name.length) let str = this.nick_name.trim(); if(str.length==0){ this.$toast('请输入合法的昵称') return } if((/[^/a-zA-Z0-9\u4E00-\u9FA5]/g).test(str)){ this.$toast('请输入中英文和数字') return } this.updateUserInfo() }, 1500), /* 上传 头像 转 话格式*/ uploadFile(){ uni.uploadFile({ url: config.webUrl + '/upload/uploadImages',//后台接口 filePath: this.avatarUrl,// 上传图片 url name:'image', // formData: this.formData, header: { 'content-type': 'multipart/form-data', 'token': uni.getStorageSync('token') }, // header 值 success: res => { let obj = JSON.parse(res.data) console.log('obj', obj) if (obj.code == 1) { let imgUrl = obj.data.full_path; this.userImg = imgUrl; this.updateUserInfo(); } else { uni.showToast({ icon: 'none', title: '图片太大,请重新选择!' }); } }, fail: e => { this.$toast('上传失败') } }); }, updateUserInfo(){ let self = this; uni.showLoading({}); let params = { img_url: this.userImg, nick_name: this.nick_name.trim(), } self.$http.post('updateUserInfo', params).then(res => { uni.hideLoading() if (res.data.code == 1) { self.$toast('修改成功!') }else { self.$toast(res.data.msg) } }) }, } } 请一键三连,争取升个级,谢谢各位道友! 补充一下,如果api不生效注意切换一下版本库: 我本地用的2.26.1 [图片] 实际效果图: [图片] [图片]
2022-11-24 - 小程序突破10层路由方案
问题:微信限制10层内的路由跳转 10以后报错 需要使用redirectTo跳转 先前条件:使用这套解决方案需要项目中所有跳转页面的地方调同一个方法 解决方案:添加一个中转页面,由开发者维护一套虚拟路由栈数据,当跳转页面路由到第十层时需要把第9层重定向到中转页,再由中转页跳转到10层 方案细节: 9层(含9层)以内路由:走小程序自己的历史栈就,跳转时候更新一下自己维护的路由栈从9层跳转10层:需要把第9层重定向到中转页,再由中转页跳转到10层10层以后跳转:在navigateTo方法中处理,到10层之后,再跳转就第10层页面一直做redirectTo操作了10层以上返回:先返回到中转页,根据自己维护的虚拟路由栈判断具体返回到哪个页面,然后navigateTo过去从10层返回到9层:返回到中转页,将中转页redirectTo到第9层页面9层内的返回:使用小程序自己的返回更新虚拟栈节点 // 虚拟栈操作 switch (type) { case 'navigateTo': $history.push(target); break; case 'redirectTo': if (originType === 'navigateTo') $history.push(target); else $history.replace(target); break; case 'switchTab': $history.reset(target); break; case 'reLaunch': $history.reset(target); break; default: break; } 方案缺点:虽然突破了10层路由的限制但是10层之后的跳转会有中转页闪一下,返回也要重新走一遍小程序生命周期。(如果你的项目超过了10层路由先看能不能从产品角度优化掉毕竟10层路由对用户来说入口太深了~)
2022-11-07 - 微信小程序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 - 自己写的一个前端面试题库微信小程序上线了
业余时间做了一个前端题库的一个小程序,设计也是自己做的,希望能给入门的朋友们做个学习参考 下面是部分功能截图: [图片][图片][图片][图片] 第三方服务来源: 前端面试3+1每日鸡汤:爱词霸 功能介绍 首页(展示今日题目,分类,热门题目,精选文章等)题库 (展示所有分类下的题目)我的 (个人信息墙)基础架构 |- app.js 工程入口 |- app.json 小程序原生配置 |- app.wxss 部分公共样式 |- image 资源目录 |- components 公用组件存放目录 |- pages 页面路径 |- service 适配当期页面服务,api存放 request 请求 |- utils 工程工具类 开源地址 https://git.weixin.qq.com/JsLin/fe-source 附言 有兴趣的小伙伴可以体验下看看,给出宝贵意见,下面是体验码 [图片]
2022-10-20 - 小程序订单中心path设置审核一直不通过?
我们提交审核,会有40%的概率不通过,腾讯审核进入到了我们的订单详情页面。明明提交的是订单中心页面。为什么会进入订单详情页面??
2022-12-27 - 关于小程序订单中心页设置的公告
为进一步规范小程序交易生态、提升用户购物体验、满足用户在有交易的小程序中便捷查看订单信息的诉求,自 2022 年 12 月 31 日起,对于有 “选择商品 / 服务 - 下单 - 支付” 功能的小程序,需按照平台制定的规范,在小程序内设置订单中心页。同时开发者需将小程序订单中心页的 path 同步给平台,以便平台核实设置情况。 一、需设置订单中心页的小程序类型针对同时满足以下条件的小程序,开发者需在小程序内设置订单中心页并将对应 path 同步给平台 1、实际经营类型为电商平台、商家自营、生活服务等涉及线上支付的小程序,购买对象为实物、虚拟商品或线下 / 线上服务等; 2、小程序内的交易涉及选择商品 / 服务 - 下单 - 支付的完整流程。 涉及的小程序类目如下: [图片] 二、订单中心页的设计规范为保障用户易用性,订单中心页需通过统一页面,展示所有涉及资金交易的订单明细或订单分类入口,详情请参考以下两种设计规范: 1、页面包含所有涉及资金交易的订单明细 [图片] 2、页面包含所有涉及资金交易的订单分类入口 [图片] 三、小程序订单中心页 path 规范1、规范生效的时间 自 2022 年 12 月 1 日起,开发者可通过代码提审入口、小程序管理后台 -> 设置 -> 功能设置进行 path 登记; 自 2022年 12 月 31 日起,若相关小程序仍未提交符合规范的订单中心页 path ,其后续代码提审可能会被驳回。 2、规范细则 (1)格式规范 i. 通过主 path(不拼接参数)可访问订单中心页面,设置时仅填写主 path; ii. path 内不含中文字符。 (2)跳转规范 i. 通过 path 进入订单中心,不自动跳转至小程序首页等其他页面,页面不出现加载失败等 bug ; ii. 通过 path 进入订单中心,如检测到用户无登录态,则在该页面通过弹窗等方式引导用户登录,登录后停留在订单中心页;或者跳转到登录页面,登录成功后返回订单中心页。 (3)修改规范 path 设置成功后,若对页面内容有调整,请确保调整后的页面仍符合订单中心页的各项规范。对于已发现的不再符合规范的订单中心页,平台会通知开发者限期调整。 四、订单中心页 path 同步方式自 2022 年 12 月 1 日起,平台提供以下两种方式供开发者将小程序订单中心页的 path 同步给平台(订单中心页的 path 如有变更,请及时重新设置): 1、对于新注册或有版本迭代需求的小程序:可在代码提审环节设置订单中心 path 2、对于无版本迭代需求的小程序:可在小程序管理后台 -> 设置 -> 功能设置 -> 小程序订单中心 path 设置入口进行设置 [图片] 五、第三方开发者代设置 path 的方式1、对于新注册或有版本迭代需求的小程序:可在提审时通过参数配置该商家小程序的订单中心页 path 新增参数为:order_path;接口为:submit_audit2、对于无版本迭代需求的小程序:第三方开发者可通过以下接口代商家设置订单中心页 path applySetOrderPathInfo:该接口可用于批量代商家小程序提交申请设置订单中心页 pathgetOrderPathInfo:该接口可用于查询商家小程序订单中心页 path 信息 微信团队 2022年12月2日
2023-09-26 - 使用公众号、小程序,查看任意小程序的页面路径
前言 需要准备一个 公众号 或 小程序 账号才能查看小程序页面路径,如果你没有账号但是想获取页面路径,可以尝试咨询小程序的客服、开发者。 步骤1.打开小程序搜索框 公众号看这条:登录公众号后台,依次点击 图文素材(草稿箱) -> 新的创作 -> 写新图文 -> 小程序 [图片] [图片] [图片] 小程序看这条:登录小程序后台,依次点击 工具 -> 生成小程序码 [图片] 步骤2.搜索与配置微信号 [图片] [图片] 步骤3.复制页面路径 进入要复制的小程序页面,依次点击 右上角 ··· 按钮 -> 复制页面路径(部分手机需要向左滑动才能看到) [图片] ⚠️ 注意事项 复制出来的路径 pages/watermark/index.html?key_=16311567863922 在小程序、文章使用时候,里面的 .html 需要删除: 删除前:pages/watermark/index.html?_key=16311567863922 删除后:pages/watermark/index?_key=16311567863922 如果路径用在APP、小程序推送,则不需要删除后面的.html
2022-04-16 - kbone怎么返回刷新?
用vue写小程序,框架使用kbone,返回上一页用wx.navigateBack();返回到上一页后页面数据没有刷新,我没有找到刷新的节点和时机
2021-04-01 - 开发者工具升级到最新版本后,控制台为什么找不到AppData和storage选项?
开发者工具版本号:1.05.2110110 调试工具显示如下图 [图片]
2021-10-21 - 为啥最新文档版本,升级后,打包老是过大。前版本都不超出体积, 更新版本就全部超出体积?
[图片] 为啥最新文档版本,升级后,打包老是过大。前版本都不超出体积, 更新版本就全部超出体积,代码一行都没增加
2021-07-20 - 扫普通链接二维码打开小程序的问题
https://developers.weixin.qq.com/miniprogram/introduction/qrcode.html 官方文档里有这么一句话:一个小程序帐号一个月可发布不多于100次二维码跳转规则。 如果我有几千个人员, 每个人员要生成普通二维码,是不是不支持?
2022-06-15 - canvas的bindtouchstart、bindtouchend失效,没有参数
第一次的touchstart的事件是有参数的,在点击就没有了(第二张图) iPhone 11 ios:16.0.3 微信:8.0.29 [图片][图片] [图片]
2022-10-18 - 微信人脸核身接口能力
一、能力背景 近年来,国家在医疗挂号、APP注册、快递收寄、客运、运营商等多领域规定,需要用户实名才可办理业务,预计后续也会有越来越多的此类法规。因此,微信参照公安部“互联网+”可信身份认证服务平台标准,依托腾讯公司及微信的生物识别技术,建立微信“实名实人信息校验能力” ,即通过人脸识别+权威源比对,校验用户实名信息和本人操作(简称微信人脸核身)。 目前接口限定主体及行业类目开放公测,提供给资质符合要求的业务方,在合适的业务场景内使用。目前仅支持持二代身份证的大陆居民。 由于人脸核身功能涉及到用户的敏感、隐私信息,因此调用此接口的小程序,需要满足一定的条件。即:小程序的主体以及类目,需要在限定的类目范围内,且与小程序的业务场景一致。开展的业务也需要是国家相关法规、政策规定的需要“实名办理”的相关业务(其他未在范围内的业务,则暂不支持)。 以下为接口接入及开发的详细内容。如开发中遇到任何疑问,可以点击此处通过社区反馈,将有工作人员跟进回复。 文档第四部分【再次获取核验结果api】,有助于提高业务方安全性,请务必接入! 现阶段微信人脸核验能力,针对小程序,开放的主体类目范围包含: 小程序一级类目 小程序二级类目 小程序三级类目 使用人脸核验接口所需资质 物流服务 收件/派件 / 《快递业务经营许可证》 物流服务 货物运输 / 《道路运输经营许可证》(经营范围需含网络货运) 教育 学历教育(学校) / (2选1):1、公立学校:由教育行政部门出具的审批设立证明 或 《事业单位法人证书》;2、私立学校:《民办学校办学许可证》与《民办非企业单位登记证书》 医疗 公立医疗机构 / 《医疗机构执业许可证》与《事业单位法人证书》 医疗 互联网医院 / 仅支持公立医疗机构互联网医院(2选1):1、卫生健康部门的《设置医疗机构批准书》;2、 《医疗机构执业许可证》(范围均需含“互联网诊疗”或名称含“互联网医院”等相关内容 医疗服务 三级私立医疗机构 / 仅支持三级以上私立医疗机构,提供《医疗机构执业许可证》、《营业执照》及《医院等级证书》 政务民生 所有二级类目 / 仅支持政府/事业单位,提供《组织机构代码证》或《统一社会信用代码证》。 金融业 银行 / (2选1):1、《金融许可证》; 2、《金融机构许可证》。 金融业 信托 / (2选1):1、《金融许可证》; 2、《金融机构许可证》。 金融业 公募基金 / (4选1):1、《经营证券期货业务许可证》且业务范围必须包含“基金”;2、《基金托管业务许可证》; 3、《基金销售业务资格证书》;4、《基金管理资格证书》。 金融业 证券/期货 / 《经营证券期货业务许可证》 金融业 保险 / (8选1):1、《保险公司法人许可证》;2、《经营保险业务许可证》;3、《保险营销服务许可证》;4、《保险中介许可证》;5、《经营保险经纪业务许可证》;6、《经营保险公估业务许可证》或《经营保险公估业务备案》;7、《经营保险资产管理业务许可证》 ;8、《保险兼业代理业务许可证》。 金融业 消费金融 / 银监会核准开业的审批文件与《金融许可证》与《营业执照》 金融业 汽车金融/金融租赁 / 仅支持汽车金融/金融租赁主体,同时提供:1、《营业执照》(公司名称包含“汽车金融” /“金融租赁”;营业范围包含“汽车金融”/“金融租赁”业务);2、《金融许可证》或银保监会及其派出机构颁发的开业核准批复文件。 交通服务 网约车 快车/专车/其他网约车 (自营性网约车)提供《网络预约出租汽车经营许可证》。(网约车平台)提供与网约车公司的合作协议以及合作网约车公司的《网络预约出租汽车经营许可证》。 交通服务 航空 / (航司)提供《公共航空运输企业经营许可证》。(机场)提供《民用机场使用许可证》或《运输机场使用许可证》。 交通服务 公交/地铁 / 提供公交/地铁/交通卡公司《营业执照》 交通服务 水运 / (船企)提供《水路运输许可证》。(港口)提供《港口经营许可证》 交通服务 骑车 / 仅支持共享单车,提供共享单车公司《营业执照》 交通服务 火车/高铁/动车 / 仅支持铁路局/公司官方,提供铁路局/公司《营业执照》 交通服务 长途汽车 / (2选1):1、《道路运输经营许可证》(经营范围需含客运);2、官方指定联网售票平台(授权或协议或公开可查询文件)。 交通服务 租车 / 运营公司提供《备案证明》与对应公司《营业执照》,且营业执照中包含汽车租赁业务 交通服务 高速服务 / 仅支持ETC发行业务,(2选1):1、事业单位主体,需提供《事业单位法人证书》;2、官方指定的发行单位(一发单位),需提供“官方授权或协议,或公开可查询的文件”; 生活服务 生活缴费 / (供电类)提供《电力业务许可证》与《营业执照》,且《营业执照》且经营范围含供电。(燃气类)提供《燃气经营许可证》与《营业执照》,且《营业执照》且经营范围含供气。(供水类)提供《卫生许可证》与《营业执照》。(供热类)提供《供热经营许可证》与《营业执照》,且《营业执照》且经营范围含供热。 IT科技 基础电信运营商 / (2选1):1、基础电信运营商:提供《基础电信业务经营许可证》;2、运营商分/子公司:提供营业执照(含相关业务范围)。 IT科技 转售移动通信 / 仅支持虚拟运营商,提供《增值电信业务许可证》(业务种类需含通过转售方式提供移动通信业务) 旅游服务 住宿服务 / 仅支持酒店,提供《酒店业特种行业经营许可证》 商业服务 公证 / 仅支持公证处,提供《公证处执业许可证》或《事业单位法人证书》 社交 直播 / (2选1):1、《信息网络传播视听节目许可证》;2、《网络文化经营许可证》(经营范围含网络表演)。 如对以上类目或资质有疑问,可点击参考小程序“非个人主体开放的服务类目”,详细了解小程序开放的服务类目及对应资质。 二、准备接入 (请在小程序发布后,再提交人脸核身接口申请) 满足第一节中描述的类目和主体的小程序,可申请微信人脸核验接口。目前微信人脸核身接口已改为线上自助申请方式,需按照如下图例指引,进行接口申请: 第一步:请通过mp.weixin.qq.com登录小程序账号在后台“功能-人脸核身”的路径,点击开通按钮—— [图片] 第二步:仔细查阅《人脸识别身份信息验证服务条款》后,点击“同意并下一步”—— [图片] 第三步:请正确填写服务信息,并上传该小程序类目下所要求的资质—— [图片] 第四步:请按照业务实际需求填写使用人脸接口的场景和用途—— [图片] 第五步:请完善测试信息和联系人—— [图片] 第六步:提交后请耐心等待1-3个工作日的审核期,审核结果将以站内信通知—— 如申请期间遇到问题,可联系腾讯工作邮箱 wx_city@tencent.com,将会有相关工作人员进一步指引。 三、接口文档: (一)接口描述 名称: wx.startFacialRecognitionVerify(OBJECT) 功能:请求进行基于生物识别的人脸核身 验证方式:在线验证 兼容版本: 一闪:android 微信7.0.22以上版本, iOS 微信7.0.18以上版本 建议在微信官网升级至最新版本 (二)参数说明 1、OBJECT参数说明: 参数 类型 必填 说明 name String 是 姓名 idCardNumber String 是 身份证号码 success Function 否 调用成功回调 fail Function 否 调用失败回调 complete Function 是 调用完成回调(成功或失败都会回调) 2、CALLBACK返回参数 参数 类型 说明 errMsg String 错误信息 errCode Number 错误码 verifyResult String 本次认证结果凭据,第三方可以选择根据这个凭据获取相关信息 注 1:传递用户姓名和身份证有两种方式 业务方没有用户实名信息,用户需要在前端填写身份证和姓名,那么前端直接通过jsapi 调用传递 name 和 idCardNumber。 业务方已经有用户实名信息,后台通过微信提供的 api(详情见文档后面“上传姓名身份证后台 api”)上传用户身份证姓名和身份证,api 返回 user_id_key 作为凭证传给前端,前端再调用 jsapi,用户姓名、身份证信息不需要经过前端,参数只需要传递 userIdKey。Tips:使用该功能需要小程序基础库版本号>=1.9.3。 3、回调结果说明 回调结果请参考以下释义: [图片] [图片] [图片] 4、示例代码 [图片] [图片] (三)上传用户姓名身份证的后台api 1、API说明 1.1说明 业务方上传用户姓名和身份证,获取用户凭证,把凭证给到前端通过 jsapi 调用。 Tips :使用该功能需要小程序基础库版本号>=1.9.3。 1.2请求URL https://api.weixin.qq.com/cityservice/face/identify/getuseridkey?access_token={ac cess_token} 1.3请求方式 POST 2、请求数据格式 [代码]Json { "name" : “张三”, "id_card_number" : "452122xxxxxxx43215" } [代码] 请求示例 [代码]#!/bin/bash TOKEN='xxxxxxxxxxxx' URL='https://api.weixin.qq.com/cityservice/face/identify/getuseridkey' JSON='{ "name": "张三", "id_card_number": "452344xxxxxxxxxxxxx234"}' curl "${URL}?access_token=${TOKEN}" -d "${JSON}" [代码] 参数说明 json 字段 中文显示 是否必传 name 姓名 是 id_card_number 身份证号码 是 out_seq_no 业务方唯一流水号 否 3、返回数据 参数 类 型 说明 errcode int 错误码 errmsg string 错误信息 user_id_key string 用于后台交互表示用户姓名、身份证的凭证 expires_in uint32 user_id_key 有效期,过期需重新获取 [代码]{ "errcode" : 0, "errmsg" : "ok", "user_id_key" : "id_key_xxxx", "expires_in": 3600 } [代码] 4、后台消息推送 如果业务方传入out_seq_no,核身完成后会通过消息推送回调给业务方的服务器,如果回调业务方失败,会在5s尽力推送,超过5s不再推送。 参数说明 参数 类 型 说明 ToUserName string 小程序原始ID FromUserName string 事件消息openid CreateTime uint32 消息推送时间 MsgType string 消息类型 Event string 事件类型 openid string 核身用户的openid out_seq_no string 业务方唯一流水号 verify_result string 核身返回的加密key(凭据) 返回示例 [代码]{ "ToUserName": "gh_81fxxxxxxxx", "FromUserName": "oRRn15NUibBxxxxxxxxx", "CreateTime": 1703657835, "MsgType": "event", "Event": "face_identify", "openid": "oRRn15NUibBxxxxxxxxx", "out_seq_no": "test1234", "verify_result": "XXIzTtMqCxwOaawoE91-VNGAC3v1j9MP-5fZJxv0fYT4aGezzvYlUb-n6RWQa7XeJpQo0teKj8mGE4ZcRe1JI3GqzADBYORBu613rKjKAFfEXTXw_bu1bs7MnmPOpguS" } [代码] 四、再次获取核验结果api 此接口是前端完成人脸核身后,基于前端返回的凭据,通过后台api再次进行核验结果和身份信息的校验,有助于提高安全性,请务必接入! 前端获取结果不可信,存在被篡改的风险,为了保障请求结果安全性,请务必对identify_ret、id_card_number_md5、name_utf8_md5字段进行校验! (一)API说明 1、说明 人脸核身之后,开发者可以根据jsapi返回的verify_result向后台拉取当次认证的结果信息。 2、请求URL https://api.weixin.qq.com/cityservice/face/identify/getinfo?access_token={access_token} 3、请求方式 POST 4、请求格式 json (二)请求数据说明 1、请求 参数 类型 是否必填 描述 verify_result String 是 jsapi返回的加密key(凭据) 2、数据返回 HTTP 头如下 Date: Mon, 06 Feb 2017 08:12:58 GMT Content-Type: application/json; encoding=utf-8 Content-Length: 85 Connection: close json示例 [代码]{ "errcode" : 0, [代码] [代码]"errmsg" : "ok", "identify_ret" : 0, "identify_time" : 1486350357 "validate_data": "8593" [代码] [图片] (三)返回参数说明 1、返回参数 注:errcode和identify_ret同时为0,代表本次认证成功。 参数 类型 描述 errcode int 错误码, 0表示本次api调用成功 errmsg string 本次api调用的错误信息 identify_ret int 人脸核身最终认证结果 identify_time uint32 认证时间 validate_data string 用户读的数字(如是读数字) openid string 用户openid user_id_key string 用于后台交互表示用户姓名、身份证的凭证 finish_time uint32 认证结束时间 id_card_number_md5 string 身份证号的md5(最后一位X为大写) name_utf8_md5 string 姓名MD5 2、错误码对应信息 errcode 备注 84001 非法identity_id 84002 用户信息过期 84003 用户信息不存在 五、小程序辅助接口:检查设备是否支持人脸检测 1、接口名称 接 口 :wx.checkIsSupportFacialRecognition(OBJECT) 功能:检查设备是否支持人脸检测 2、接口说明和使用 小程序调用该接口,可以检测当前手机设备是否具备支持人脸检测的能力,可与以上接口分开使用,为了用户体验,建议调用后对手机设备不支持的用户做对应功能处理。 3、接口说明和使用 01 OBJECT 参数说明: 参数 类型 是否必填 描述 success Function 否 调用成功回调 fail Function 否 调用失败回调 complete Function 是 调用完成回调(成功或失败都会回调) checkAliveType Number 否 人脸核验的交互方式,默认读数字(见表 2) 表 2:checkAliveType 的值和对应的解释: 参数 解释 2 先检查是否可以屏幕闪烁,不可以则自动为读数字 02 CALLBACK 返回参数 参数 类型 说明 errMsg Boolean 错误信息 errCode Number 错误码 03 回调结果说明 回调类型 ErrCode 说明 sucess 0 支持人脸采集 fail 10001 不支持人脸采集:设备没有前置摄像头 fail 10002 不支持人脸采集:没有下载到必要模型 fail 10003 不支持人脸采集:后台控制不支持 回调结果说明仅对Android生效,iOS不返回errcode。 04 示例代码 [图片] 六、安全性说明 为保障业务可用性以及安全性,请详细研读微信人脸核身接口相关基础说明及安全说明文档:https://docs.qq.com/doc/DTFB0YWFIdGV6amly 备注:如开发中遇到任何疑问,可以点击此处通过社区反馈,将有工作人员跟进回复。 七、案例展示及补充说明 安徽医科大学第二附属医院,微信人脸核验登录: 安徽医科大学第二附属医院,是三级甲等综合医院。其小程序为用户提供挂号、门诊费用、住院费用、检查报告、体检等医疗服务,同时也提供停车、餐饮等便民服务,是医疗小程序中完整的案例。 小程序使用了微信人脸核验能力作为登录的核验。满足医院管理要求,也满足国家对于实名就医的管理规则。 案例实现的截图效果如下: [图片] [图片] 针对近期少数小程序方面反馈的两类问题,也在本课程进行补充说明。 1、本接口的开放范围,即:可支持的主体类目,是否可以扩大? 说明:基于本接口整体使用范围的评估、相关法规的参考、监管策略的理解执行等,暂时未立刻进行扩大开放范围的工作。 但我们会持续基于不同行业的法规、政策及监管要求等,逐一进行研究考量,以便确认如何扩大开放范围。 2、小程序如果涉及用户本人的生物特征采集,(如本人人脸照片、人脸视频),或涉及采集用户本人生物特征信息并开展人脸核验功能,则存在被驳回的情况? 说明:近两年“人脸识别”技术在社会上掀起了热潮。人脸识别虽然作为摆脱“中间媒介”或“承载载体”的一种直接技术手段,解决了部分政务、交通、医疗、零售等证明“操作者是本人”的问题,但也因此,引入了新的更大的安全风险。 一是,虚假安全风险。 身份认证领域的安全三因素包括“我知道什么”、“我拥有什么”、“我的特征是什么”,通用的安全做法,是要双因素认证(2FA),人脸识别技术如仅凭“我的特征是什么”这一个因素,则容易被攻破或利用。表象给用户以安全的感觉,但实际并不能达到安全效果。 二是,信息泄漏的风险。 越来越多的组织或个人,在并非必需用户敏感信息、生物特征的情况下,采集并存储此类信息。在信息加密、传输、存储过程中,容易暴漏更多的网络节点,使得此类信息有更大的风险被网络黑客拦截、窃听、窃取,或直接被脱库。 三是,消除风险的难度大。 以往基于“中间媒介”或“承载载体”的方式,如出现丢失、被冒用、恶意盗用等风险,可以通过挂失、更换、使用新载体或新媒介等方式,快速排除一定的风险。C端主动,B端主动,都能解决一部分问题。但人脸识别做为更直接的方式,一旦出现冒用、盗用,受害者将面临更大的财产及人生安全风险,且C端用户更多时候无法主动消除风险。 基于以上问题风险,加之国家出台《网络安全法》、《用户隐私保护条例》等法律法规标准,网信办、公安部、工信部及市场监管总局等四部委发起的app获取隐私整治,结合平台安全、用户敏感隐私信息保护要求及监管,针对部分暂无相关法规或要求,需要采集或生物认证方式进行身份核验的,或以“追热点”或“尝鲜”为目的,采集用户生物特征或进行身份核验的,进行严格审核,必要时不予以支持。
11-18 - 微信小程序开发之富文本编辑器
微信小程序开发之富文本编辑器 一年多去了,还有这么多人关注这个编辑器,那就索性把这个组件放上去,各位直接引用吧!如果您感觉很好用,很实用,也请大家给点一个赞!前言:富文本在Web开发上的地位大家可想而知,很多地方都需要用到富文本编辑器,比如开发类似新闻管理小程序、商品简介等。微信小程序在基础库2.7.0之后上线了一个editor富文本编辑器组件,这个组件是本次要讲的内容。组件相关的内容大家可以去看官方文档的内容,这里我们就不进行讲解。而我们要做的就是将官方的富文本组件进行二次开发达到一个好用而又实用的地步:https://developers.weixin.qq.com/miniprogram/dev/component/editor.html 先看效果图(以下只是一个基础的实用): [图片] 代码方案: 1.引入组件(组件的下载地址链接:https://pan.baidu.com/s/15D3ejvs30BZPwn94RgyNmw 提取码:hg66) 2、在你需要的使用的页面的JSON文件中引入该组件,引入方法如下: "usingComponents": { "hg-editor":"../../../components/hg-editor/hg-editor(根据自己的放置位置修改,其中/hg-editor/hg-editor是固定的)" } 3、在wxml文件中使用,使用案例如下,可选参数有四个 参数详解: [图片] showTabBar :是否显示工具栏(默认为true,显示,如果改为false则为不显示)placeholder:文本框提示文字,默认为“请输入相关内容”name:是编辑器的name属性,默认为空uploadImageURL:图片的上传地址,默认为空使用属性案例测试: bind:input可以获得用户输入的内容: onInputtingDesc: function (e) { let html = e.detail.html; //相关的html代码 let originText = e.detail.text; //text,不含有任何的html标签 this.setData({ ['topic.text']: html, ['topic.originText']: originText }); } 使用案例: [图片][图片][图片] 您的想法有多大,组件拓展的无限可能就有多大,欢迎各位留言,欢迎各位使用! 好用,就来收藏一下,更新不易,点个赞!
2022-04-22 - 如何编写微信小程序大赛参赛作品的介绍文档
本人声明:这里所写的内容只是我个人的观点,不代表大赛官方,仅供选手参考。这个不是标准模板,大赛介绍文档没有模板,自己的文档应该怎么写比较好是你们自己考虑的事情,事后不能以此文档的建议作为评价标准来要求。 参赛作品提交要求: 1. 介绍文档:综合描述作品情况,突出作品的创新点和优势,内容应包括但不限于小程序说明、应用场景、解决的实际问题、产品设计、技术实现方案(包括小程序端和后台服务器端)等。使用微信云开发作为作品主要后端服务的小程序,应在技术实现方案中说明所使用的云开发技术。如果参赛作品引用了非团队成员的开发成果(如开源代码或其他应用系统),请务必在文档中说明。文档要求提交PDF格式,文件大小在10M以内。 2. 演示视频:演示参赛作品的主要使用流程并配上讲解,时长限在3分钟内,在微信开发者工具直接上传视频文件。 3. 小程序appid(允许上线版本和体验版)。 很多选手一直在问到底如何写介绍文档,我这里将之前在群里的讨论交流归纳整理如下几点建议,选手可以参考,但不要局限于此。 (一)介绍文档有什么用?让评委老师更好地了解你的作品! 虽然开发团队对自己的作品很熟悉,但是评委并不清楚这个小程序,包括应用背景、内部技术、作品特色以及未来运维等等,这些内容也无法通过直接试用而全面了解,所以团队需要在文档中清楚地展现这些内容。 (二)介绍文档主要应该写什么? 文档应该包括封面、目录和正文三个部分,封面仅列出作品名称即可,目录要清晰正确,封面和正文中都不要刻意出现团队和学校信息。如果作品需要给评委提供测试帐号,或者另有一个管理端小程序,建议在正文的第一页进行简单说明,并提供帐号信息或小程序码,以免放在正文后面被评委忽略。 正文部分简单地说,就是针对作品评分标准,写清楚相关的内容。下面所列的部分只是一个引导,选手可以根据自己的产品进行删减和补充,不一定要全部照搬。 1. 选题定位 (1) 应该说清楚这是一个什么小程序,具体的应用场景是什么以及解决什么实际问题?建议直接了当,突出重点,应用场景和实际问题要有一定的调查材料支撑,注意不能是网上随便抄来的。这部分是让评委大概了解这个小程序是干什么用的以及为什么要开发。 (2) 提出现实问题之后,建议简单地阐述一下自己的产品方案,这里的方案不是技术方案,而是自己打算做一个什么样的产品来解决现实的问题。 (3) 今年大赛的作品主题是“用科技创造社会价值与助力乡村振兴”,希望选手不要仅仅局限在校园范围去选题,可以从创造社会价值或乡村振兴等角度去寻找突破。注意避免随便选择往届比赛中做过多遍的选题,如果没有更多的创新而只是重复模仿,作品选题部分的得分肯定受影响。 2. 需求分析 (1) 在用户和业务分析方面,大家可以采用自己学过的一些方法和技术,原则就是用户分析到位,尤其要知道用户的人群和特点,明确相应业务的完整流程。 (2) 系统需求应该包括功能需求和非功能需求,不论是哪方面的需求,都应该是紧密结合自己要开发的系统,而不是泛泛地抄一些类似教科书上面的内容。 举例:“参观清华”小程序的非功能需求就是根据系统的实际要求,提出了关键的三个内容:一是性能,给出具体的量化指标;二是安全性,诸如身份证敏感信息等;三是可靠性,包括停电和断网问题、游客快速进入的问题等。 (3) 在做需求调研时选手应该适当进行一定的竞品分析,包括这些竞品的用户群、覆盖的主要业务场景以及产品功能和页面设计等。在文档中可以选1-2个竞品进行简单的对比分析,说明自己产品的优势和创新之处。 3. 产品设计 交互设计部分应展现整个系统的信息结构,说明配色和整体设计原则,把系统核心功能的交互设计图展现出来,然后选择自己认为可以突出亮点的几个关键设计进行说明。 4. 技术实现 作品的技术方案部分应给出系统的总体框架设计图,并做相应的说明,然后给出系统的技术选型、开发环境,包括所采用的框架、第三方组件等。 总体框架介绍清楚之后,应该着重介绍系统开发方面自己的突出贡献部分或者亮点部分,这个需要根据自己开发的系统进行归纳,选择核心重点或技术难点部分来说明相应的技术实现。 系统测试可以考虑写一下功能测试和性能测试,说明测试方案和测试结果,要注意清楚而且有实际的真实测试结果,不要乱写乱编。如果自己开发的系统非常简单,而且没有特别的性能要求,可以忽略性能测试部分。 5. 应用运营 大赛鼓励参赛作品上线发布,如果由于个人资质受限等因素无法上线,也可以提交体验版。对于同等质量的作品,上线版本略有优势,但是需要强调的是作品质量更为重要。 对于一些需要自己运营的作品,这部分也是非常重要的,需要说明如何上线以及未来的运营和维护方案,特别是一些需要特殊资质的作品,更要说清楚这一点。 如果上线发布的作品已经积累了一定的用户量,可以用小程序上线后的实际运行数据展现产品的应用效果,注意数据要有说服力。 (三)其他 也许选手们认为评委只要体验小程序就应该可以了解整个作品,实际上小程序本身呈现的更多是从用户角度的使用,对于小程序的应用背景、交互设计思路、所用开发技术的复杂度和难度以及系统实现水平等,很难从简单的试用了解清楚,因此需要开发团队在文档中写清楚,以便评委更好地了解你们的作品。但是,需要特别强调的是要阐述清楚和突出重点,切忌胡抄乱写,也不建议套用所谓某些软件工程文档模板而长篇大论,太长的文档是很难阅读的。当然,文档只是作品的一部分,好的小程序是至关重要的!
2022-05-28 - 微信支付V3-商家转账到零钱
微信支付V3-商家转账到零钱 ~ [图片] ~ 连续熬了几个晚上,终于在社区某高人的指点下完成了这块逻辑。由于V3的逻辑相对复杂,网上的资料也相对有限,在这块遇到很多坑 场景 最近答题活动增加了抽奖发红包的活动,抽奖其实在答题活动经常存在,但是之前都是通过线下领取奖励或者充话费的行为完成这个闭环模式; 在当前新的项目中是要抽奖并实时下发奖励,具体就是直接把对应抽中的金额下发到用户的微信零钱里面 效果 [图片] ~ 准备条件 1、商户号码 2、APIV3秘钥 3、证书系列 4、api cert 5、需要在小程序进行绑定 参考资料 ~ 参考项目1 https://github.com/wechatpay-apiv3/wechatpay-php [图片] ~ 参考项目2 https://github.com/TheNorthMemory/wechatpay-php [图片] 相关细节 ~ 调用下发的接口,会返回以下信息,我们不能通过该成功回调去判断是否真的已经发放成功了,这是V3很重要的一点 [图片] 下发的数据结构 "appid" => "wxcc26cf72611aeef0", "out_batch_no" => "45465plfk2020042013", "batch_name" => "2019年1月深圳分部报销单", "batch_remark" => "2019年1月深圳分部报销单", "total_amount" => 30, "total_num" => 1, "transfer_detail_list" => [[ "out_detail_no" => "1234x23zy545Bd5436", "transfer_amount" => 30, "transfer_remark" => "2020年4月报销", "openid" => "osPw15JkAUgpY6aPTrnBIg2gZ5zU" ],] ~ [图片] ~ { "appid": "wxcc26cf72611aeef0", "batch_id": "1030001083101257713912022062300867725335", "detail_id": "1040001083101257713912022062300861404139", "detail_status": "FAIL", "fail_reason": "TRANSFER_QUOTA_EXCEED", "openid": "osPw15JkAUgpY6aPTrnBIg2gZ5zU", "out_batch_no": "plfk2020042013", "out_detail_no": "x23zy545Bd5436", "transfer_amount": 10, "transfer_remark": "2020年4月报销", "update_time": "2022-06-23T09:43:52+08:00" } ~ 到账属于准实时 PAYEE_ACCOUNT_ABNORMAL:用户账户收款异常,请引导用户完善其在微信支付的身份信息以继续收款 REALNAME_ACCOUNT_RECEIVED_QUOTA_EXCEED:用户账户收款受限,请引导用户在微信支付查看详情 以下场景,即使调用成功也不会成功发放 1)用户微信支付被封 2)用户没有实名认证 待办 后面还有一些优化事项需要完成 2)抽奖规则梳理 1)安全策略,这块就是通过商户后台进行设置以下事项 1)下发最高奖励设置 2)单日下发次数限制 3)请求安全校验,真实下发之前,对入参进行校验,以排查一些非法的请求。 商家转账到零钱 答题抽奖活动 答题活动抽奖
2022-06-24 - wx.getLaunchOptionsSync()获取场景值是上次进入的场景值?
获取场景值的时候,一直获取的是第一次进小程序的场景值,微信版本号8.0.16,基础库版本2.21.2, 从微信聊天主界面下拉的[最近使用]栏进,场景值是正常的1089,返回退出以后,还有缓存,然后分享给最近,应该是单人聊天会话中的小程序消息卡片的场景值1007,但是显示的场景值还是1089,如图状态栏点击重新进入小程序正常显示1007, [图片] 然后从其他路径进入小程序,显示的仍然是1007,需要重新进或者清除缓存才能显示正确的 问题是近两天才有的,以前体验版打开调试面板,再打开发布的线上版本小程序,线上版本可以看到调试工具,现在打开线上版本没有调试工具,场景值也不对了 [图片]
2021-12-24 - 在kbone中使用腾讯视频小程序播放插件
需求:在kbone项目中引入腾讯视频小程序播放插件渲染视频 腾讯视频小程序播放插件介绍:github传送门 在代码中需要使用<txv-video>标签进行展示,如下所示: [代码] // 在你们的wxml上这样插入视频元素 <txv-video vid="e0354z3cqjp" playerid="txv1"></txv-video> [代码] 但是kbone框架并不认识<txv-video>标签,因为不是他的内置标签名,直接使用编译完成后会发现被渲染成<view>标签,当然视频也没法正常显示。 这时需要借助kbone官方提供的方法:使用小程序自定义组件官方文档传送门,使用自定义组件可以让kbone无法识别的一些标签进行正确解析和渲染。 以kbone框架为例,正确引入步骤如下: 1.建立自定义组件目录 要在 kbone 中使用自定义组件,需要将所有自定义组件和其依赖放到一个固定的目录,这个目录可以自己拟定,假设这个目录为 src/custom-component: 然后建立要创建的自定义组件名文件夹,比如这次要使用的txv-video [图片] 2.修改webpack插件的配置 在miniprogrom.config.js中的 generate 字段内补充 wxCustomComponent [图片] root 是组件根目录,即上面提到的目录:src/custom-component, usingComponents 则用来配置要用到的自定义组件。 键为组件名(txv-video),值可以为组件相对 root 字段的路径,也可以是一个配置对象。 本例使用配置对象进行相应配置: path 为组件相对路径 props 表示要这个组件会被用到的 properties(txv插件需要的两个必需属性vid、playerid) propsVal 表示对应属性的默认值(本例未用到) events 表示这个组件会被监听到的事件(本例未用到) 3.将自定义组件放入组件根目录 以txv-video组件为例 index.wxml文件:使用<txv-video>标签 注意:需要使用插值{{}}语法方式赋值,如果使用v-bind指令(或简写:)并不生效,使用该组件时无法正常获取到对应值 [代码]// index.wxml <txv-video vid="{{vid}}" playerid="{{playerid}}"></txv-video> [代码] index.js文件:声明所需的属性和方法,可以参考官方文档 [代码]// index.js Component({ properties: { vid: String, playerid: String }, }); [代码] index.json文件:非kbone要求,属于腾讯视频小程序播放插件要求,键值名必须按如下正确书写 [代码]// index.json { "usingComponents": { "txv-video": "plugin://tencentvideo/video" } } [代码] 4. 在app.json中引入txv-video插件 此步骤属于腾讯视频小程序插件要求配置,在kbone中打开miniprogrom.config.js文件,找到appExtraConfig字段(kbone中appExtraConfig字段对应小程序中的app.json配置) 添加如下代码: [代码] plugins: { tencentvideo: { version: "1.5.2", provider: "wxa75efa648b60994b" } } [代码] 5.使用自定义组件 如下图所示,不需要额外导入可以直接使用该组件。 [图片] 可以看到<txv-video>标签成功渲染,视频也可以正常显示,如下图所示: [图片]
2021-10-10 - 微信公众号无法注销,管理员要怎么解绑?
我有一个公众号,是几年前从某宝购买的,该公众号状态正常。 现在想注销,但是无法法人扫脸或者打款,因为我根本不认识法人更不知道她的对公账号。 但我确实是该公众号的管理员,现在我已经不想要这个账号了。 我有什么办法注销或者解绑这个公众号吗?
2022-08-05 - 小程序代码加固功能上线公告
为提高微信开放平台生态安全性,针对小程序开发过程中的安全问题,如代码易被反编译,核心业务逻辑被破译,算法易被二次打包等,导致小程序存在被破解、核心代码被盗取的风险,平台在微信开发者工具上线了代码加固功能,协助开发者保护小程序安全。 一、功能介绍 小程序代码加固是提供给开发者对小程序前端代码进行加密的功能,以防止代码暴露。该功能可将 JavaScript 文件传递给加密工具,从而实现字符串加密、属性加密、调用转换、代码混淆等多项保护措施,提高攻击者阅读前端代码逻辑的难度。 二、解决方案 微信开放平台通过在微信开发者工具中提供插件的方式,以便开发者进行功能的使用。同时还提供了Sourcemap代码加固调试工具,来帮助开发者对于加固后的文件进行错误分析。 三、功能使用 1、首先需在微信开发者工具选择代码加固插件进行安装; 2、选择需要加固的文件并进行配置操作,建议加固小程序中的敏感数据信息、核心算法逻辑、关键执行路径、接口(签名算法、协议、密钥等)。 另:界面操作和渲染、引用的第三方开源库等非必要安全保护内容可不进行加固,避免过多影响小程序体积及性能。 3、最后加固成功后可进行后续页面的预览,具体使用说明详见 功能介绍文档。 四、常见问题 Q1: 加固后显示编译结果失败? A1: 表示所加固的小程序内容,在小程序编译结果中没有对应的代码,所以导致替换失败,可以根据失败的提示信息,进行具体排查 [图片] Q2: 如果想一次性批量进行代码加固,应该如何操作呢?A2: 若需要批量进行代码加固,可直接修改[代码]code_obfuscation_config.json[代码]中的[代码]configs[代码]字段即可 [图片] 代码示例如下: [图片] Q3: 使用 Sourcemap 代码加固调试时,为什么查找不到报错路径?A3: srcMiniprogramRoot目录下不存在该报错文件所对应的源文件 [图片] Q4: 代码加固后会对产品性能有影响吗?A4: 产品性能影响与代码加固的内容、大小和数量有关,可能会影响代码体积,产品初始化耗时和执行速度,可通过 性能说明文档 作进一步了解。 如有其他相关疑问,欢迎随时参与社区讨论。
2022-07-22 - 实现小程序分享朋友圈功能
一大早在各科技公众号有看到小程序支持直接分享到朋友圈,这么好的功能,忍不住要实践下。 根据官方文档走起,文档地址:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share-timeline.html 然后根据官方文档的意思,目前之支持Android版本,为什么IOS版本总是慢一些呢,(╯▔皿▔)╯ 接下来先上代码(需要注意的是得是最新版的预发布版本才行,下载链接:https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html) [图片] [图片] 在需要分享的页面对应的js文件里面写入"onShareTimeline"即可,需要注意的是需要先编写"onShareAppMessage"方法。 [图片] 点击右上角三个点,出来的效果如下图所示 [图片][图片] 再次点击右下角得"查看小程序分享页"就可以看到类似官方文档上的效果,具体如下图所示: [图片][图片] 在Android手机端下载最新版本的小程序示例,也未发现对应的分享朋友圈功能,静候微信团队的更新
2020-07-08 - 地理位置接口新增与相关流程调整
一、地理位置接口新增说明 由于精确地理位置接口只允许部分类目的小程序申请使用,为了满足开发者在更多场景使用地理位置接口,自 2022 年 7 月 14 日起,新增获取模糊地理位置接口(wx.getFuzzyLocation)。同时为保障用户合法权益,该接口调用前需进行准入开通申请,该接口准入规则与 wx.chooseLocation 一致。 wx.getFuzzyLocation 接口说明: 1、该接口返回的是经过模糊处理的经纬度坐标; 2、该接口支持返回 wgs84 或 gcj02 两种类型的坐标; 3、该接口需要用户授权 scope.userFuzzyLocation。 二、app.json 的配置指引 为了开发者能够正常使用获取模糊地理位置等接口,以及后续对于代码提审环节的优化(见「三、地理位置接口使用流程」),自 2022 年 7 月 14 日起,开发者在使用地理位置相关接口时(共计 8 个,见表1),需要提前在 app.json 中进行配置。 1、需配置的接口列表 [图片] 表1 2、配置规则 1)在代码中使用的地理位置相关接口(共计 8 个,见表1),开发者均需要在 app.json 中 requiredPrivateInfos 配置项中声明,代码格式如下: [图片] 2)表1中模糊位置信息(序号1)和精确位置信息(序号2-5)是互斥的,即声明了模糊位置信息就无法声明精确位置信息。若同时声明模糊位置信息和精确位置信息,则在编译代码时出现错误; 3)注意:自 2022 年 7 月 14 日后发布的小程序,如果未在 app.json 中声明表1中的相关接口,则小程序调用这些接口(表1)时会出现错误,在 2022 年 7 月 14 日之前发布的小程序不受影响; 4)对于第三方开发者,需要在上传代码时通过参数在 ext.json 中声明其需调用的地理位置相关接口,配置规则和普通小程序的配置规则相同。 三、地理位置接口使用流程 自 2022 年 7 月 14 日起,开发者如需在最新版本发布后使用地理位置相关接口,除需完成接口权限开通外,还需在 app.json(或ext.json)配置环节,具体如下: 1、接口权限开通 以下 8 个接口需完成准入开通流程:wx.getFuzzylocation、wx.getLocation、wx.onLocationChange、wx.chooseAddress、wx.choosePoi、wx.chooseLocation、wx.startLocationUpdate、wx.startLocationUpdateBackground 1)普通开发者:需要在 “小程序管理后台 -「开发」-「开发管理」-「接口设置」” 中完成权限申请; 2)第三方开发者:可通过 apply_privacy_interface 接口完成权限申请。 2、app.json(或 ext.json)配置 1)普通开发者:需在 app.json 中声明其需调用的地理位置相关接口,具体配置流程见「二、app.json 的配置指引」; 2)第三方开发者:需要在上传代码时通过参数在 ext.json 中声明其需调用的地理位置相关接口(配置方式:可通过 commit 接口配置)。 同时,为了提升开发者体验,平台在代码提审环节会协助开发者对地理位置接口进行检测,如检测出代码中包含未完成准入开通的地理位置接口,平台将再次提醒开发者确认是否需使用相关接口。 1)普通开发者:若无需使用,开发者可在提审时确认不使用该接口,即可正常进行代码提审。小程序审核通过且新版本发布完成后,平台将对小程序确认不使用的接口关闭使用权限; 2)第三方开发者:若无需使用,可在提审时通过参数声明不使用该接口(声明方式:可通过 submit_audit 接口配置),即可正常进行代码提审,审核通过后发布上线,将对其声明不使用的接口关闭使用权限。 以上调整将仅对所有小程序生效。 微信团队 2022年6月1日
2023-09-26 - 小程序性能优化实践
小程序性能优化课程基于实际开发场景,由资深开发者分享小程序性能优化的各项能力及应用实践,提升小程序性能表现,满足用户体验。
10-09 - [已解决]利用云开发解决小程序加载自定义字体无效果问题
终极效果 效果要求:使得最终页面效果在开发者模拟器、安卓、iOS都可正常显示字体效果。 [图片] 问题背景 如何在微信小程序上利用wx.loadFontFace方法加载自己要上传的字体的文件一直是困扰很多开发者的问题,很多人反映使用该方法在开发者工具模拟器上是可以显示的,有的开发者说在模拟器和iOS系统上可以正常显示自定义字体,但是安卓机上无法正常显示。 很多人为了能够实现加载自定义字体想了很多办法,比如 方法1: 字体文件转base64代码(如网站https://www.transfonter.org) ,然后存储在wxss文件中。这也是我曾使用的方法之一,确实很好用,安卓/苹果机上都可以正常实现效果。 缺点:但是面对字体文件包一般都很大的中文字体来说,转换成base64代码是极容易出现仅用来引用字体的wxss代码就超过2M的情况。 根据小程序的开发规矩,即使采用分包形式开发一个小程序,单个分包的代码量也是不能超过2M的,此时就是该方法的鸡肋。 方法2: 也有开发者利用iconfont上的在线引用方法,把自己会用到的字输进入然后点击生成字体,引用一个url即可实现。这种方法也是可行的。 缺点:但是对于部分字多或者可能出现用户输入文字的情况,这种方法就不太方便。 解决方案 今天,和大家讲的就是wx.loadFontFace方法,也是很多人一直在尝试,执着于想要利用这种方法实现。 在小程序开发者文档中,这一段文字是你不陌生的。 wx.loadFontFace(Object object) 基础库 2.1.0 开始支持,低版本需做兼容处理。 本接口从基础库版本 2.15.0 起支持在小程序插件中使用 动态加载网络字体,文件地址需为下载类型。‘2.10.0’起支持全局生效,需在 app.js 中调用。 注意: 字体文件返回的 contet-type 参考 font,格式不正确时会解析失败。 字体链接必须是https(ios不支持http) 字体链接必须是同源下的,或开启了cors支持,小程序的域名是servicewechat.com canvas等原生组件不支持使用接口添加的字体 工具里提示 Faild to load font可以忽略 ’2.10.0’ 以前仅在调用页面生效。 ——来源于《微信小程序开发者文档》 分析: 注意点1是大家一般无需担心的,我们下载到的字体文字很多是ttf文件,都是符合相关要求的。 注意点2也是一般不会犯错的,大家都会避开这个。 注意点3是非常重要的,也是很多开发者不明白的,下面,我会着重讲如何解决这个问题,解决了这个问题,无论调试还是真机都能正常显示。 在开发者文档中,有这样一段代码: [代码]wx.loadFontFace({ family: 'Bitstream Vera Serif Bold', source: 'url("https://sungd.github.io/Pacifico.ttf")', success: console.log }) [代码] 可以看出使用的是https链接,或许你曾经拿这段代码测试过。 或者你也曾经把字体文件上传到一些存储空间然后得到上传后文件的地址,或者说你曾经在开发者社区看到别人上传的字体文件的https链接然后来调用。 在开发者工具模拟器上正常显示,一到真机就显示不了。 当然为了想要使用我自己喜欢的字体,得到该字体的文件链接,我也突然脑洞大开,尝试把字体文件上传到云开发的云存储上,然后得到一个FileID链接和一个下载链接。 随后在页面或者全局的JS中加载该字体文件: 代码: [代码]loadFontFace() { wx.loadFontFace({ family: 'XXX', source: 'url("xxxxxx.ttf")', success(res){ console.log('res', res) }, fail(err){ console.log('err', err) } }) }, [代码] 遗憾的是,也是能在模拟器中显示出自定义字体效果,在安卓的真机上无法正常显示,iOS未知(我没有iOS系统故无法测试)。 到底是怎么回事,问题出在哪呢?于是一遍遍琢磨开发文档中的注意事项“字体链接必须是同源下的,或开启了cors支持,小程序的域名是servicewechat.com”。 后来琢磨后面一句话,我也是不明白啥是cors,于是就搜索了,记得其中一篇文章就讲到腾讯云的cors之类的。 操作步骤 1 进入腾讯云的官网(https://cloud.tencent.com),然后登录账号,选择公众号小程序登录,扫码并选择需要实现自定义字体的小程序进行登录 2 在顶部菜单栏找到“对象存储” [图片] 3 存储桶列表中新建一个存储桶 [图片] 4 给存储桶设置配置,跨域访问中设置好“cors规则”,把https://servicewechat.com域名填写到来源Origin的方框内。 [图片] 现在再来读读“字体链接必须是同源下的,或开启了cors支持,小程序的域名是servicewechat.com”是不是有了新的体会。 5 把需要使用的字体文件上传到该存储桶,然后点击文件右边的“详情”,你就会看到“对象地址”,这个地址就可以粘贴到JS文件的wx.loadFontFace使用。 [图片] 6 不要忘了设置刚刚上传的字体文件“访问权限”为“公有读私有写”,这样每个用户都可以读取这个字体文件了。 源码分享 JS文件 [代码]loadFontFace() { wx.loadFontFace({ family: 'XXX(你给字体拟的名称,最好英文如kaiti)', source: 'url("对象地址")', success(res){ console.log('res', res) }, fail(err){ console.log('err', err) } }) }, [代码] WXSS文件 [代码]page{ font-family: 'XXX'(你给字体拟的名称,最好英文如kaiti); } [代码] 或者 [代码].xxx(class名){ font-family:'xxx(你给字体拟的名称,最好英文如kaiti)' } [代码]
2021-04-13 - 微信小程序Android系统左上角没有首页按钮,ios系统有,Android系统可以加上吗?
想在Android系统左上角加上首页按钮,又不与ios系统冲突
2019-10-19 - 在必要的时候,是频繁的使用setData好些,还是setData一次大量数据好些?
如题,求指导,谢谢
2020-04-28 - URL Link和URL schema 打开小程序属于哪种统计指标?
[图片] 如果小程序是通过URL Link或者URL schema 打开,在统计里的场景访问里面,属于哪种指标?
2022-05-26 - innerAudioContext.pause 方法触发碰到bug,暂停不了?
调用innerAudioContext.onTimeUpdate方法获取播放时间,根据播放时长对比设定时长,超过设定时长则暂停。目前碰到的问题是,第一次触发超过时长的判断的时候,暂停失败、第二次触发事件之后才能成功暂停。开发工具中没有碰到这个问题,问题是真机调试的时候碰到的[图片][图片][图片]
2022-05-22 - 小程序客服能力迭代 - 移动端操作bar+PC端设置改版 20220517
本次迭代针对移动端「客服小助手」会话操作区域和PC端网页客服「设置」模块(https://mpkf.weixin.qq.com/)做升级迭代,提升客服回复效率。 1. 移动端「客服小助手」会话操作区域改版 新增移动端客服会话页消息输入栏上方操作栏,便于客服直接发送图片、转接会话、结束会话等操作,后续操作栏功能项将会持续新增迭代。 [图片] 2. PC端网页客服设置改版(https://mpkf.weixin.qq.com/) 2.1 网页端设置入口位置从左下角改为左侧导航栏,原左下角区域改为展示客服个人头像和设置在线状态。 [图片] 2.2 网页端客服工作台设置模块新增修改名称、快捷键的能力。 客服名称展示在用户会话页客服接入时,客服名称修改仅在单个小程序生效。 [图片] [图片] 后续客服系统将会持续迭代更新,欢迎各位开发者/商家分享使用体验及建议。
2022-07-11 - PowerWeChat 微信SDK 介绍
## 产品介绍 PowerWechat是一款全覆盖微信开发接口,基于Golang的开源项目。您只需安装一次Power WeChat SDK,就可以对接企业微信,小程序,公众号,支付等,微信的开发功能接口。同时我们提供了丰富的文档教程和辅助工具,帮助您轻松使用微信的接口功能。 ## 快速上手 go get -u github.com/ArtisanCloud/PowerWeChat/v2 示范:初始化实例对象,调用小程序的授权登陆接口 ```go import ( "github.com/ArtisanCloud/PowerWeChat/v2/src/miniProgram" "os" ) // 1. 初始化小程序应用实例 app, err := miniProgram.NewMiniProgram(&miniProgram.UserConfig{ AppID: os.Getenv("miniprogram_app_id"), // 小程序、公众号或者企业微信的appid Secret: os.Getenv("miniprogram_secret"), // 商户号 appID HttpDebug: true, Debug: false, }) // 2. 调用小程序的授权登陆接口 var code string = "CODE" // 前端小程序登录时,从微信获取的 coders, err := app.Auth.Session(code) // 查看获取强类型对象的属性 // 请参考官方文档的返回值 printf(rs.OpenID) printf(rs.SessionKey) printf(rs.UnionID) ``` 更多实例接口,请打开 https://powerwechat.artisan-cloud.com/zh/start/ ## 产品概述 ### 核心产品 [PowerWeChat SDK](https://powerwechat.artisan-cloud.com/ "PowerWeChat SDK") :是核心的SDK产品,安装后即可开箱即用。 在github上,长期维护的开源项目,可以提Issue在讨论版块。也可以在ArtisanCloud官网上,扫企业微信讨论群,方便用户提问,给宝贵的意见。 ### 辅助产品 PowerWeChat Document :全面的接口文档,方便用户查找,使用我们开发的sdk功能 PowerWeChat Tutorial :独立的golang项目,提供完整的web接口,让开发者方便调试PowerWeChat 接口实例 [图片] PowerWeChat 配置中心客户端/SAAS:如果您有多个微信的开发环境,或者多个应用,可以使用这个配置中心来方便切换账号(此应用暂时内部使用,如需体验,可以联系我们) [图片] # 产品诞生背景 团队也是很多同学一样,从PHP转向Golang,具体为什么,有什么好处,就不用我这里多介绍了吧。 但是现在因为微信的生态做私域化管理是得天独厚,所以我们公司也开发了蛮多企业微信的功能。只是在转型golang的过程中,没有找到像 (PHP语言)这样好用的sdk。所以我们就自己想为golang的同学们做一点贡献。产品会长期维护,迭代,希望同学们有兴趣在使用的过程中,多给意见。 # 产品特性 - 简易上手,安装一次,全覆盖微信功能接口 - 开源项目,丰富的文档内容,长期维护 - 新增群机器接口和文档 - Golang特性,强类型覆盖 - 完整的测试项目,支持web API测试 # 相关资源 ## 阅览教程文档 ## Github开源代码 [图片]
2022-05-31 - 短视频小程序Swiper+Video在大部分苹果手机IOS机型中出现闪退?
在开发短视频小程序中,使用Swiper+ Video 的方式实现,目前是保持Swiper中四个swiper-item,在每次滑动时进行替换,默认播放首个视频,滑动暂停上一个,在swiper的chnge绑定的方法中,每次都有判断更新替换视频数据, 在IOS中滑动视频过程中会出现有些视频滑到后不播放,频繁滑动后会出现闪退! IOS机型如下图 [图片] [图片] 监控日志中显示 应该是内存溢出导致的 <view class="wrapper"> <swiper style="width:{{screenWidth}}px;height:{{screenHeight}}px" class="video-swiper" circular="{{circular}}" easing-function="{{easingFunction}}" vertical current="1" duration="{{duration}}" bindanimationfinish="animationfinish"> <!-- curQueue 循环会导致video重新插入,objectFit 不可变更 --> <swiper-item wx:for="{{curQueue}}" wx:key="index"> <view class="shadow"></view> <video style="width:{{screenWidth}}px;height:{{screenHeight}}px" miLinToken="{{miLinToken}}" id="{{tabType}}video_{{index}}" class="video_item" loop="{{loop}}" enable-play-gesture enable-progress-gesture show-center-play-btn="{{false}}" controls="{{false}}" src="{{item.video_url}}" data-id="{{item.id}}" object-fit="{{item.sp_text ? item.sp_text: 'contain'}}" data-index="{{index}}" > </video> <view class="video_box_fn"> <view class="vbf_avatar mb32"> <image src="{{item.logo}}" class="avatar" mode="aspectFill" catch:tap="toHome" data-videodata="{{item}}" /> <image src="../../images/explosive/add@2x.png" wx:if="{{item.is_follow===0}}" class="add_icon" catch:tap="addFollow" data-type="1" data-itemindex="{{itemIndex}}" data-videodata="{{item}}" /> <image src="../../images/explosive/checkedfollow.png" wx:else class="add_icon" catch:tap="addFollow" data-type="0" data-itemindex="{{itemIndex}}" data-videodata="{{item}}" /> </view> <view class="vbf_fn mb32"> <image src="../../images/explosive/like@2x.png" wx:if="{{item.is_zan===0}}" class="fn_icon" catch:tap="addLike" data-itemindex="{{itemIndex}}" data-videodata="{{item}}" /> <image src="../../images/explosive/checked_like@2x.png" wx:else class="fn_icon" catch:tap="addLike" data-itemindex="{{itemIndex}}" data-videodata="{{item}}" /> <text class="fn_num">{{toUnit.numToUnit(item.sum_zan)}}</text> </view> <view class="vbf_fn" catch:tap="openShare" data-itemindex="{{itemIndex}}" data-videodata="{{item}}"> <image src="../../images/explosive/share@2x.png" class="fn_icon" /> <text class="fn_num">{{toUnit.numToUnit(item.sum_fen)}}</text> </view> </view> <!--视频描述--> <view wx:if="{{!controls}}"> <view class="video_box_desc"> <!--产品卡片--> <view class="video_box_product" data-videodata="{{item}}" catch:tap="toDetail"> <image class="vbp_pic" src="/images/explosive/product.png" mode="aspectFill" /> <view class="vbp_desc"> <text class="vbp_desc_name">{{item.tc_name}}</text> <text class="vbp_desc_price">¥{{(item.discount_price)}}</text> </view> </view> <view class="video_desc">{{item.video_title}}</view> </view> <!--店铺地址--> <view class="shop_address" catch:tap="toShopHome" data-videodata="{{item}}"> <image src="/images/explosive/shop@2x.png" class="shop_icon" /> <text class="shop_name">{{item.shop_name}}({{item.distance}})</text> </view> </view> <view class="bottom_shadow"></view> </swiper-item> </swiper> <!-- 暂停按钮 --> <view wx:if="{{isShowPauseBtn}}" class="push_btn" catch:tap="handlePlay" data-itemindex="{{itemIndex}}" data-videodata="{{item}}"> <image src="/images/explosive/pause.png" class="pause_icon"/> </view> <view wx:if="{{isShowLikeIcon}}" class="like-icon" style="position:absolute; left:{{row-200}}px; top:{{top-200}}px;width:800rpx;height:800rpx;"> <canvas id="like_lottie" type="2d" style="width: 100%;height: 100%;"/> <!-- <image src="/images/bg/love.png" animation='{{animationMiddleHeaderItem}}' style="width: 100%;height: 100%;" />--> </view> </view> <wxs module="toUnit"> var numToUnit = function (num) { var w = num; if (num >= 10000) { w = num / 10000; w = w.toFixed(1); w = w + 'w'; } return w; } module.exports = { numToUnit: numToUnit } </wxs>
2021-03-08 - 【小程序代码自查】小程序闪退-内存泄露导致
背景用户经常出现闪退的情况,并提示内存不足。根据用户操作场景,猜测页面存在内存泄露。 内存泄露是什么?内存泄露是程序运行过程中产生的内存变量会一直存在,不会被垃圾回收机制检测到,导致一直不会被销毁,内存占用会越来越大。 比如说: 我们在运行小程序的时候会产生一个页面,小程序会给这个页面创建一个实例,当这个页面销毁的时候,这个实例应该会被销毁。 但是如果我们有个定时器(setInterval),定时器里面对这个页面实例存在引用,那这个页面实例就不会被销毁,因为有被用到。 当存在内存泄露的情况,用户长期使用我们的小程序会导致小程序占用的内存越来越大,最后会导致小程序闪退(被微信强制销毁) 排查内存泄露用到的工具-weakSet先简单描述一下weakSet,让大家有个简单的认识,详细需要去看下文档。 weakSet 是一个可以存储唯一变量的集合,和Set不一样的是,weakSet存储的变量都是弱引用,就是不会影响垃圾回收,如果存储的变量被回收了,在这个集合里面就找不到。 所以weakSet不能被遍历,也没有长度的概念。但是我们可以通过控制台打印weakset的指向,知道里面有多少个元素。如下图: [图片] 通过展开,我们可以知道里面是哪个页面的实例,但是我们在控制台展开就意味着我们对这个页面实例存在引用,则无法被垃圾回收。所以在执行垃圾回收之前需要清空控制台的输出。 如何确定页面是否存在内存泄露如果页面存在内存泄露则不会销毁页面实例。我们只需要判断页面实例有没有被销毁即可。 我们在一开始就把页面实例加到weakSet里面,当执行多次跳转页面之后,会存在多个页面实例,最后回到首页,触发小程序的垃圾回收。 如果不存在内存泄露,那weakSet集合里面只会存在两个页面实例(当前页面实例+返回回来的页面实例),比如下图的页面A和页面B。 如果存在内存泄露,那weakSet集合里面会存在多个页面实例(当前页面实例+存在内存泄露的页面实例*n),比如下图的页面A、页面B、页面C和页面D. 具体如下图: [图片] 如何主动触发小程序的垃圾回收小程序没有api可以让我们触发小程序的垃圾回收,我们目前可以通过开发者工具的performance面板或memory的垃圾回收(collect garbage 垃圾桶图标)按钮。 [图片] [图片] 触发垃圾回收之后的结果如图: [图片] 这个需要手动触发才可以,我们在测试的时候需要手动点击,无法自动触发,所以我们想了个方案自动触发垃圾回收。 通过给内存塞很多数据,然后将这些数据标为无用的,当内存达到500m左右小程序就会触发垃圾回收。这个办法会导致我们内存一段时间激增,建议尽量在跳转页面的时候不要开启,只有在最后页面跳转回首页才进行。 // 主动触发垃圾回收 setInterval(()=>{ if(!global.startGC){ return } let a = [] for (let i = 0; i < 10000000; i++) { a.push({ name: "pling", age: Math.random() * 10000 }) } console.log("length", a.length) a = [] }, 3000) 如何定位页面内存泄露的原因内存泄露的情况举例: global.list = [] Page({ // ... onLoad() { // ... 省略其他代码 // 将页面实例挂载到全局对象,如没有清理,则页面实例会一直不被销毁 global.list.push(this) // 存在Interval计时器,则会一直存在对页面实例的引用 setInterval(() => { console.log("test", this.data) }, 5000); // 通过settimeout的循环调用,实现了类似于interval的效果也会导致页面实例不会被销毁 this.testLoop() const that = this function test(){ console.log(that.data) } // 将内部函数挂载到全局变量,则会导致函数的作用域链都会存在引用,不会被销毁 global.logThis = test }, testLoop(){ setTimeout(() => { this.testLoop() }, 10000); } }) 通过上面我们可以知道一般会有上面四种情况导致内存泄露。 将对象挂载到全局对象上,页面写在没有清楚通过暴露内部函数给外部对象,导致存在作用域的引用,页面卸载没有清楚内部函数存在定时执行的函数存在对页面实例的引用,页面销毁没有清除定时器通过延时执行的函数循环调用,并存在对页面实例的引用,页面销毁没有停止调用。第一第二种情况会比较少出现,目前暂时还没考虑如何去排查。 第三第四种都会对页面实例存在调用,所以我们在页面实例销毁之后对页面实例上的属性进行监听,如果一直存在调用则会有问题。 [图片] 具体实现代码: // 检查页面卸载后对页面实例调用 Page({ data: { test: "111" }, onLoad() { global.pageSet.add(this) setInterval(() => { console.log("test", this.__wxExparserNodeId__, this.data.test) }, 5000); }, // .... onUnload(){ console.log("unload"); const that = this // 获得可以枚举的属性列表 const keys = Object.keys(that) // 加入data 因为data 不是可以枚举的属性 keys.push("data") console.log(keys); keys.map(key=>{ // 获得原本的属性描述 const property = Object.getOwnPropertyDescriptor(that, key) // 保留原有的值 const origin = that[key]; // 获得属性的get方法 有可能没有 const getter = property && property.get // 获得属性的set方法 有可能没有 const setter = property && property.set const isFunction = typeof origin === "function" // 如果是function的话 需要绑定this if(isFunction){ origin.bind(that) } const newThis = {} // 拦截属性 Object.defineProperty(that, key, { get: function(){ console.log(`调用了this.${key}的getter`); // 有getter 调用getter if(getter){ return getter.call(that) } return newThis[key] || origin }, set: function(newVal){ console.log(`调用了this.${key}的setter`); if(setter){ return setter.call(that, newVal) } newThis[key] = newVal } }) }) } }) 测试demo我们在自己项目里面测试会比较麻烦,一开始可能会有干扰,所以我这边弄了个代码片段,先校验一下这个方法是否可行,如果可行再加到自己的项目里面。 小程序代码片段
2021-05-12 - 小程序云测试服务近期更新(2022.05.05)
体验地址:快速开始 近期小程序云测试服务新增以下特性 `A` 支持设置录制回放和Minium的用例排序功能`A` 任务结束通知优化,增加邮件和短信的通知方式`A` 支持通过HTTPS第三方接口提测任务`A` 录制回放报告在出错时,新增下载错误步骤wxml功能修复或优化以下问题 `F`修复了Minium框架中自定义组件定位问题`U` Minium与录制回放任务增加初始化失败自动重试功能`U`【录制回放优化】当回放超时任务时,可查看超时时用例运行的进度`U`【录制回放优化】优化录制回放异步加载页面加载完成的判断,减少由页面未加载完成引起的"element not found"的报错 1、支持设置录制回放和Minium的用例排序功能 用户打开插件后,在“测试用例管理”—“测试计划”—“新建测试计划/编辑”,勾选测试用例时,根据勾选的顺序来执行用例 [图片] 2、任务结束通知优化,增加邮件和短信的通知方式 用户 前往“我的信息”页面绑定自己的邮箱或手机号,任务结束会通知到相关账号 [图片] 3、支持通过HTTPS第三方接口提测任务 用户可以通过第三方HTTPS接口提测云测任务,方便和现有的Devops流程打通。Jenkins打通可参考 教程 4、录制回放报告在出错时,新增下载错误步骤wxml功能 录制回放任务步骤执行失败时,支持下载WXML功能,方便用户排查问题。WXML文件可在开发工具中直接打开,主要用于排查元素找不到问题,具体使用可以参考 录制回放常见问题汇总文档。 [图片]
2022-06-14 - map上的cover-view标签里动态数据偶现渲染不出来,还比较频繁,有什么解决办法吗?
[图片][图片]
2022-05-07 - 同一个小程序同一个用户手机号,获取的openid不一样?
APPID:wx7b93bbe604502da6 openid: odYa45QR5g7R4v-JvCNY3ZZuiZVA odYa45a7vPqrf8ar3UHn-VNN-HIs 麻烦官方帮排查一下,发生概率大概1000分之一
2021-03-04 - 小程序webview缓存清除
请问小程序webview里面的缓存怎么清,样式怎么改都是以前的,直接在微信访问链接都改了,小程序里面的还没改。非常严重!!!!!!!希望有人帮我顶上去,让官网的人看到,给出一个有效的解决方案!
2018-09-23 - 开发智能名片小程序时遇到的技术问题以及解决办法
开发智能名片小程序时遇到的技术问题以及解决办法[图片]智能名片小程序,又叫电子名片小程序 关键词 this & thatthis是相对于当前函数而言的。如果在onLoad里定义了一个函数,并且需要调用根部数据 则可以在onLoad里先定义一个变量that,将this赋值给that 那此时调用的that,则是相对于onLoad()的当前对象onLoad函数内一个function需要用到setData;则可以在onLoad里先定义;再在function里调用that.setData setData对单个元素进行赋值直接this.setData({ele : ele})对数组赋值先拼接字符串 eg:对Stu: ['Li' , 'Yang' , 'Wang']进行某一索引值var index = 0 var str = "Stu[" + index + "]" for(index = 0; index < length; index++) this.setData({ str : "" }) 对对象赋值首先let arr = this.data.arr 然后创造obj let obj = {} 对obj赋值——类似于数组赋值,在拼接字符串时,后面加上.属性即可 最后用arr.push(obj) 数组push时被覆盖问题描述 这是一个数据库读取事件,actLine被加值后,在下次开启加值时,会将之前加的值替换,但对原本的值无影响,即几次push后,所有push的值都会变成最后一次push的值//原代码 if(res.data.length != 0){ //查询成功时 for(let i = 0; i < res.data.length; i++){ obj.title = res.data[i].title obj.host = res.data[i].host actLine.push(obj)) console.log(i,actLine) } 解决方法 第五行push时将其改为以下内容if(res.data.length != 0){ //查询成功时 for(let i = 0; i < res.data.length; i++){ obj.title = res.data[i].title obj.host = res.data[i].host actLine.push(Object.assign({}, obj)) //采用Object.assign将obj置于对象中再push给actLine console.log(i,actLine) } 原理 Object.assign() : 将所有可枚举的自有属性的值从一个或多个源对象复制到目标对象,返回目标对象。 icon与文字对不齐问题描述 使用vant组件库图标时,将icon与文字放在一个view标签里。显示情况,总是icon偏上一些,无论怎样调节字号都无效。/*原代码*/ <view class="actLable"><van-icon name="label-o" size="40rpx" />{{item.lable}}</view> 解决办法 在wxss里对vant-icon设置垂直居中即可van-icon { vertical-align:middle } icon 换行与连续空格换行 wxml里的/n或者br都不会被识别; 通过后台中传入的富文本换行,富文本中的\n会被当作字符串处理; 所以要在js里声明,wxml里调用/*js*/ Page({ data: { text: '这是一个段落 \n 看我变身换行', }, }) /*wxml*/ <view> <text>这是一个段落 \n 看我变身换行</text> </view> <view> <text>{{text0}}</text> </view> 连续空格 在view里输入多个空格,只会被当作一个处理;要放在text标签里,并且设置decode为ture ensp:中文字符一半大小 emsp:中文字符大小 nbsp:根据字体设置<view> <text decode="{{true}}">我要 开始 空格了(空格是中文字符一半大小)</text> </view> <view> <text decode="{{true}}">我要 开始 空格了(空格是中文字符大小)</text> </view> <view> <text decode="{{true}}">我要 开始 空格了(空格根据字体设置)</text> </view> [图片] 智能名片小程序,又叫电子名片小程序 [图片]
2022-04-25 - kbone中 我怎样给子路由页面添加下拉刷新?
[图片] 现在情况是Home 和Login 和Registeion页面都可以下拉刷新 期望是只在Home页面中才能拉刷新
2021-05-11 - 云函数无法开启本地调试
- 需求的场景描述(希望解决的问题) 云函数开启本地调试、node modules未安装 [图片] - 希望提供的能力 需要怎么安装node modules
2019-06-03 - 社区每周 | 单页模板开放公测、模板有奖调研启动及上周问题反馈(3.28-4.01)
各位微信开发者: 以下是单页模板开放公测、模板有奖调研启动及上周我们在社区收到的问题反馈的处理进度,希望与大家一同打造更好的小程序生态! 单页模板开放公测 模板有奖调研启动 微信云开发「单页模板」功能已开放公测,支持在微信开发者工具中快速导入官方提供的小程序业务常用模块,导入后即可快速获得前端示例源码,同时支持可视化管理后台。开发者仅需要根据单页模板所提供的已封装好的功能接口,专注前端页面的交互开发,即可快速上线此类功能。同时还支持对模块代码进行二次开发以满足业务个性化需求,让标准化的组件获得 “新生” 。 当前已支持积分中心、签到打卡、邀请有礼模板,邀请各位开发者参与 模板有奖调研。官方团队将根据大家的反馈,不断优化模板功能,满足更多开发需求。 注意:请下载 1.05.2203251 预发布版本的微信开发者工具体验此功能。下载地址 上周问题反馈和处理进度(3.28-4.01) 已修复的问题取消开通的交易组件一直加载中的问题 查看详情 修复中的问题 通过微信开发者工具 picker 省市区选择器,设置 level 属性却出现点击不触发的问题 查看详情 URL Scheme 唤起微信频繁卡在 “请稍后” 页面的问题 查看详情 微信团队 2022.4.8
2022-04-10 - IOS小程序使用Canvas电子签名保存后,下半部分图片丢失了
canvas画完图片之后用微信的这个方法wx.canvasToTempFilePath可以把canvas转成一张临时文件,然后调后台的接口上传图片,测试环境都可以,生产环境临时文件是png的时候只有一半,是jpg的时候显示完全,但是会多些笔画。安卓没有问题,只有IOS有这个问题。 [图片]
2019-08-27 - 小程序没有 DOM 接口,原因竟然是……?
拥有丰富的 Web 前端开发经验的工程师小赵今天刚刚来到新的部门,开始从事他之前没有接触过的微信小程序开发。在上手的第一天,他就向同办公室的小程序老手老李请教了自己的问题。 [图片] ———— 翻了一圈文档,小程序好像并不提供 DOM 接口?我还以为可以像之前一样用我喜欢的前端框架来做开发呢。老李,你说小程序为什么不给我们提供 DOM 接口呀? ———— [图片] 要提供 DOM 接口也没那么容易。你知道小程序的双线程模型吗?小程序是基于 Web 技术的,这你应该知道,但小程序和普通的移动端网页也不一样。你做了很多前端项目了,应该知道在浏览器里,UI 渲染和 JavaScript 逻辑都是在一个线程中执行的? [图片] ———— 这我知道,在同一个线程中,UI 渲染和 JavaScript 逻辑交替执行,JavaScript 也可以通过 DOM 接口来对渲染进行控制。 ———— [图片] 小程序使用的是一种两个线程并行执行的模式,叫做 双线程模型 。像我下图画的这样,两个线程合力完成小程序的渲染:一个线程专门负责渲染工作,我们一般称之为渲染层;而另外有一个线程执行我们的逻辑代码,我们一般叫做逻辑层。这两个线程同时运行,并通过微信客户端来交换数据。在小程序运行的时候,逻辑层执行我们编写的逻辑,将数据通过 setData 发送到渲染层;而渲染层解析我们的 WXML 和 WXSS,并结合数据渲染出页面。一方面,每个页面对应一个 WebView 渲染层,对于用户来说更加有页面的感觉,体验更好,而且也可以避免单个 WebView 的负担太重;另一方面,将小程序代码运行在独立的线程中的模式有更好的安全表现,允许有像 open-data 这样的组件可以在确保用户隐私的前提下让我们展示用户数据。 [图片] [图片] ———— 怪不得所有和页面有关的改动都只能通过 setData 来完成。但是用两个线程来渲染我们平时用单线程来渲染的 Web 页面,会不会有些「浪费」?而且每一个页面有一个对应的渲染层,那页面变多的时候,岂不是会有很大的开销? ———— [图片] 并不浪费,因为界面的渲染和后台的逻辑处理可以在同一时间运行了,这使得小程序整体的响应速度更快了。而在小程序的运行过程中,逻辑层需要常驻,但渲染层是可以回收的。实际上,当页面栈的层数比较高的时候,栈底页面的渲染层是会被慢慢回收的。 [图片] ———— 原来如此。这么说的话,实际的 DOM 树是存在于渲染层的,逻辑层并不存在,所以逻辑层才没有任何的 DOM 接口,我明白了。但是……既然可以实现像 setData 这样的接口,为什么不能直接把 DOM 接口也代理到逻辑层呢?我觉得小程序可以做一个封装,让我们在逻辑层调用 DOM 接口,在渲染层调用接口后再把结果返回给我们呀。 ———— [图片] 从理论上来说确实是可以的。但是线程之间的通信是需要时间的呀。将调用发送到渲染层,再将 DOM 调用结果发送回来,这中间由于线程通信发生的时间损耗可能会比这个接口本身需要的时间要多得多。如果以此为基础使用基于 DOM 接口的前端框架,大量的 DOM 调用可能会非常缓慢,让这个设计失去意义。 在实际测试中,如果每次 DOM 调用都进行一次线程通信,耗时大约是同等节点规模直接在渲染层调用的百倍以上;如果忽略通信需要的时间,一个实现良好的基于 DOM 代理的框架可以近似地看成一个动态模板的框架,而动态模板和静态模板相比要慢至少 50%。 [图片] ———— 原来如此,线程通信的时间确实是我没有考虑到的问题。那现在的小程序框架中难道不存在这个问题吗? ———— [图片] 在现在的小程序框架中,这个问题也是存在的,这也是现在的框架基于静态模板渲染的原因。静态模板可以在运行前就做好打包,直接注入到渲染层,省去线程传输的时间。在运行时,逻辑层只和渲染层进行最少的、必要的数据交换:也就是渲染用的数据,或者说 data 。另一方面,静态模板让两个线程都在启动时就拥有模板相关的所有数据,所以框架也充分利用了这一点,进行了很多优化。 [图片] ———— 怪不得我在文档里发现很多和 setData 有关的性能提示,都提醒尽量减少设置不必要的数据,现在总算是知道为什么了。但是具体到实际开发里的时候,还是总觉得很难每次只设置需要的数据啊,像对象里或者数组里的数据怎么办呢? ———— [图片] 如果只改变了对象里或者数组里的一部分数据,可以通过类似 array[2].message , a.b.c.d 这样的 数据路径 来进行「精准设置」。另外,现在自定义组件也支持 纯数据字段 了,只要在自定义组件的选项中设置好名为 pureDataPattern 的正则表达式, data 中匹配这个正则的字段将成为纯数据字段,例如,你可以用 /^_/ 来指定所有 开头的数据字段为纯数据字段。所有纯数据字段仅仅被记录在逻辑层的 this.data 中,而不会被发送到渲染层,也不参与任何界面渲染过程,节省了传输的时间,这样有助于提升页面更新性能。 [图片] ———— 小程序还有这样的功能,受教了。不过说来说去,我还是想在小程序里用我顺手的框架来开发,毕竟这样事半功倍嘛。我在网上搜索了一下,发现现在有很多支持用 Web 框架做小程序开发的框架,但好像都是将模板编译成 WXML,最终由小程序来做渲染,但这样的方法好像兼容性也不是很好。我在想,我们能不能在逻辑层仿造一套 DOM 接口,然后在运行时将 DOM 调用适配成小程序调用? ———— [图片] 你的这个脑洞有一些意思。在逻辑层仿造一套 DOM 接口,直接维护一棵 DOM 树,这当然没问题。但是没有代理 DOM 接口,逻辑层的 DOM 树没法反映到渲染层,因为渲染层具体会出现什么样的组件,是运行时才能知道的,这不就没法生成静态模板了? [图片] ———— 静态模板确实是没法生成了,但我看到小程序的框架支持自定义组件,我是不是可以做一个通用的自定义组件,让它根据传入的参数不同,变成不同的小程序内置组件。而且自定义组件还支持在自己的模板中引用自己,那么我只需要一个这个通用组件,然后从逻辑层用代码去控制当前组件应该渲染成什么内置组件,再根据它是否有子节点去递归引用自己进行渲染就可以了。你看这样可行吗? [图片] ———— [图片] 这样的做法确实可行,而且微信官方已经按照这个思路推出小程序和 Web 端同构的解决方案 Kbone 了。Kbone 的原理就像你刚才说的那样,它提供一个 Webpack 插件,将项目编译成小程序项目;同时提供两个 npm 包,分别提供 DOM 接口模拟和你说的那个通用的自定义组件作为运行时依赖。要不你赶紧试试? [图片] ———— 还有这么好的事,那我终于可以用我喜欢的框架开发小程序了!这么好的框架,为什么不直接内置到小程序的基础库里呀? ———— [图片] 因为这样的功能完全可以用现在已有的基础库功能实现出来呀。Kbone 现在是 npm 包的形式,使得它的功能、问题修复可以随着自己的版本来发布,不需要依赖于基础库的更新和覆盖率,不是挺好的吗? [图片] ———— 好是好,但我担心的是代码包大小限制的问题。除了我们已经写好的业务逻辑之外,现在还得加上 Kbone,会不会装不下呀? ———— [图片] 原来你是担心这个呀,放心,Kbone 现在已经可以在 扩展库 里一键搞定啦。扩展库是帮我们解决依赖的全新功能,只要在配置项中指定 Kbone 扩展库,就相当于引入了 Kbone 相关的最新版本的 npm 包,这样就不占用小程序的代码包体积了,快试试吧! [图片] ———— 哇,那可太爽了,马上就搞起! ———— [图片] 如果使用Kbone的过程中遇到问题,还可以到PC端 Kbone社区主页 发帖交流,上面这个框架的官方开发人员会和大家一起互动哦!
2022-06-24 - 你想知道的Kbone适配
本文主要介绍了 Kbone 接入过程可能会遇到的情况,包括请求、DOM/BOM、全局变量、样式、第三方UI库、环境区分。 Kbone 推出已有一段时间了,使用 Kbone 的你有没有遇到一些问题呢? 今天小编带大家来探一探 Kbone 接入过程中你可能会遇到的情况。 请求 对小程序了解的同学应该都知道,小程序的请求使用的是 wx.request,而在 Web 中,使用的是 XMLHttpRequest,那用 Kbone 要怎么处理呢? 简单~直接使用 XMLHttpRequest (公测中)。 当然,如果你想做一些个性化的处理,也可以自己实现 adapter。 DOM/BOM 为了更好地适配小程序端接口,Kbone 在原有的 DOM/BOM 之上进行了扩展,当然,这些适配也不是完全的,比如 getBoundingClientRect 在小程序中只能通过异步的方式实现。或者是对于 Kbone 没有实现的接口,你可以通过 扩展 API 来适配~ [图片] 全局变量 Web 开发中,我们使用 window 的方法都是直接访问的,因为 window 是顶级作用域,但是在小程序中却不是,所以直接访问是会报错的。 为了解决这个问题,Kbone 允许注入全局变量,这里通过 generate.globalVars 来实现: // mp-webpack-plugin 配置 { generate: { globalVars: [ ['TEST_VAR_STRING', '\'miniprogram\''], ['TEST_VAR_NUMBER', '123'], ['TEST_VAR_BOOL', 'true'], ['TEST_VAR_FUNCTION', 'function() {return \'I am function\'}'], ['TEST_VAR_OTHERS', 'window.document'] ], }, // 其他配置... } 样式 开发页面中,样式必不可少。由于 Web 与小程序标签的差异,Kbone 在转化过程中会将标签选择器转换为类选择器,比如: // Web span {} // 小程序 .h5-span {} 这里可能会带来选择器的权重被提升,所以依赖选择器权重这里需要手动调整一下。 Tips:小程序不支持 ~ 选择器 第三方UI库 目前,第三方 UI 库存在兼容的问题,有些接口无法兼容,比如 getComputedStyle、getBoundingClientRect 等接口。所以,Kbone 推出 Kbone-ui 来解决兼容问题。 [图片] 环境区分 虽然是多端适配,但是总会有一些情况是要区分处理的,比如小程序有 map 组件可以使用,而 Web 端没有,这个时候需要我们从代码层面进行适配处理。 对于开发者来说,我们可以通过 webpack 注入一个环境变量: // webpack.mp.config.js module.exports = { plugins: [ new webpack.DefinePlugin({ 'process.env.isMiniprogram': true, }), // ... other options ], // ... other options } 后续在业务代码中,就可以通过 process.env.isMiniprogram 来判断是否在小程序环境: if (process.env.isMiniprogram) { console.log('in miniprogram') } else { console.log('in web') } 关于 Kbone 你有什么使用问题或建议? 欢迎来到 #Kbone官方框架 社区主页发帖交流
2022-06-24 - 基于Kbone使用React同构小程序开发实践总结
导语:Kbone 是微信推出的 Web 与小程序同构解决方案,该方案现已支持 Vue、React 等同构。 1 背景 新人课程礼包是腾讯课堂双十一活动需求之一,该需求中有一个礼包课程领取页在多端(H5、小程序、app)都有涉及。 在小程序端我们可以使用 web-view 嵌入 H5,但该方案加载耗时以及无法使用微信特有的能力(例如:获取微信用户绑定的手机号,沉浸式状态栏),适逢 Kbone 已支持 React 同构,因此我们针对该页面尝试基于 Kbone 使用 React 同构小程序实践。 最终实现的效果,左边是 H5,右边是小程序: [图片] 体验二维码 [图片] 2 框架选择 目前使用 React 构建小程序的方案大都使用静态编译的方式实现,例如 taro,nanachi。 这种静态编译方式只是让我们使用 React 和 JSX 的语法来编写小程序代码,然后通过语法分析工具把代码翻译成小程序模板。由于 JSX 并非模板语言,要将其翻译成小程序模板,则必须要牺牲一些 JS 的动态特性,这也就是为什么这种方案在编写上有很多限制,其本质缺陷在于语法分析是静态的,而 JS 是动态的。 此外,这种方案实际运行时并非 “真 React ”,因此对于跟进 React 特性来说,无法做到与官方同步。 [图片] 至于 Kbone ,它能够支持完整的 React 和 JSX 语法,是因为它把 React 给完整引入进来,而对于 React 底层依赖了的 dom/bom 接口,它提供一套轻量的小程序适配层接口([代码]miniprogram-render[代码] 和 [代码]miniprogram-element[代码])。 正是因为通过提供适配器的方式来仿造出 Web 环境,所以我们可以在任意位置任意方式书写 React 和 JSX,而无须担心是否不支持某些新特性。 [图片] [图片] 3 React-Kbone-Miniprogram 过程 从 kbone-template-react 官方例子来看,React 代码使用 Kbone 构建出小程序,其流程是基于 Webpack 来实现的,它使用 Babel 转换 React 代码并通过 mp-webpack-plugin 在构建 Web 端代码后追加 Kbone 和小程序相关的文件到小程序工程。 [图片] package.json、pages/、app.、project.config.json 等文件由 mp-webpack-plugin 插件生成的小程序工程文件。 [代码]miniprogram-render[代码] 和 [代码]miniprogram-element[代码] 是 Kbone 两个核心模块:仿造接口和自定义组件,它们通过小程序 npm 包安装。 common 目录包含业务样式、业务代码和第三方库(React 相关),是由 Babel 转换并打包输出的。 从上图看,例子主要是以新项目出发,通过 [代码]webpack.mp.config.js[代码] 配置生成完整的小程序工程,但对于现存的小程序工程来说,其实我们并不需要 app.* 、project.config.json 等文件,同时更多时候我们希望是在现有的 H5 项目中书写代码和复用代码,然后生成小程序页面输出到现有小程序工程中。 4 接入现有工程 礼包课程领取页主要涉及到两个现存的工程: m-core:是腾讯课堂 H5 页面,技术栈是 Webpack 4 + Babel 7+ React ^16.8 + Typescript。 weapp-ke:是腾讯课堂小程序,技术栈是小程序原生框架。 为了优先保证 H5 能够正常运行,我们将新页面的代码放到 m-core 项目,接着增加 [代码]webpack.mp.config.js[代码] 配置,由于同构生成的小程序页面依赖 Kbone 的适配层库,为避免原小程序工程主包过大,我们需要构建生成分包页面,同时上面说到 [代码]mp-webpack-plugin[代码] 会生成额外的小程序工程文件,所以我们要么在其构建结束后移除这部分文件,要么修改该插件仅生成必要的文件。我们暂时采用后一种方案,相对灵活一些,并已反馈给微信同学以支持生成单一页面代码到指定目录。 [图片] 4.1 构建配置 我们基于 kbone-template-react 提供的 [代码]webpack.mp.config.js[代码] 来修改,以支持项目中使用的 React、Typescript、PostCSS、条件编译、Tree Shaking 等特性,还有与小程序代码复用。 4.1.1 Babel 以下是 H5 和小程序代码转换的公用规则,依据 isMp 来区分不同的转换处理 [代码]{ test: /\.(ts|js)x?$/, use: [ 'thread-loader', { loader: 'babel-loader?cacheDirectory', options: isMp ? { configFile: false, // 避免babel加载babel.config.js presets: [ '@babel/preset-typescript', // 支持typescript '@babel/preset-react', // 支持react ], plugins: [ '@babel/plugin-proposal-class-properties', ] } : { configFile: path.resolve(rootDir, 'babel.config.js'), }, }, { loader: 'webpack-strip-block', options: { // 依据标记移除代码块 start: isMp ? 'strip-block--h5-only:begin' : 'strip-block--mp-only:begin', end: isMp ? 'strip-block--h5-only:end' : 'strip-block--mp-only:end', }, } ], include: [ path.resolve(rootDir, 'src'), path.resolve(rootDir, 'node_modules/@tencent'), ], sideEffects: !isMp, // 小程序开启tree shaking } [代码] 同构小程序使用的 babel-loader 配置与一般 H5 使用的配置有些不同,对于小程序我们可以不加 [代码]@babel/preset-env[代码],是因为小程序开发者工具本身提供 ES6 转 ES5 的代码编译能力和增强编译能力。 至于插件**请不要使用 [代码]@babel/plugin-transform-runtime[代码] 和 [代码]@babel/plugin-transform-modules-commonjs[代码] **插件,这两个插件在 h5 中比较常见,但在这里 [代码]@babel/plugin-transform-runtime[代码] 会导致小程序开发者工具运行报错,[代码]@babel/plugin-transform-modules-commonjs[代码] 会影响 Webpack 的 Tree Shaking。 此外,我们使用到 [代码]webpack-strip-block[代码],目的就是根据环境移除不必要的代码块(效果与 [代码]DefinePlugin[代码] 相同,但 [代码]DefinePlugin[代码] 无法处理 import 声明),配合 [代码]DefinePlugin[代码] 和 Tree Shaking 一起使用。 4.1.2 Tree Shaking 由于小程序对包大小有严格限制,因此我们需要尽可能地减少包大小。Tree Shaking 是一种代码优化技术,它可以消除那些无用的代码。 Webpack 中要使用 Tree Shaking,我们必须保证: 使用 ES2015 模块语法(即 import 和 export)。 确保没有编译器将 ES2015 模块语法转换为 CommonJS 模块。 在项目 package.json 文件中添加一个 “sideEffects” 属性或者在 module.rules 配置选项中设置 “sideEffects”。 使用 production mode 配置选项启用各种优化插件,包括 Minification 和 Tree Shaking。 如上述条件所示,在同构项目中我们需要注意以下几点: [代码]tsconfig.json[代码] 中的 [代码]compilerOptions.module[代码] 切勿设置为 “CommonJS”。 [代码]@babel/preset-env[代码] 的 [代码]modules[代码] 切勿设置为 “commonjs”,同时避免使用 [代码]@babel/plugin-transform-modules-commonjs[代码]。 如果项目中 H5 部分使用了某些自执行的模块而无法使用 Tree Shaking,那么我们可以仅在构建小程序的配置中使用 [代码]Module.Rule.sideEffects[代码] 开启 Tree Shaking 而不影响 H5 的构建。 4.1.3 与小程序代码复用 现有 weapp-ke 小程序工程中使用了 [代码]@tencent/imwxutils[代码] 等 npm 库以及实现了各种 utils 代码,如果在同构代码中再实现一遍显然是再造轮子,同时会增加小程序包的大小,因此我们需要复用 weapp-ke 已有的代码。 对于 npm 包,由于 weapp-ke 小程序主包已经引入,所以同构代码在构建小程序代码时只需要通过 Webpack 的 [代码]externals[代码] 将 npm 包从输出的代码中排除,这样小程序在运行时会去主包获取这些依赖。 对于 weapp-ke 小程序已实现的 utils 代码,首先我们需要定位到 utils 目录并给它取一个别名,例如 [代码]weappKeUtils[代码]。 [代码]resolve.alias.weappKeUtils = path.resolve(weappKeDir, 'utils'); [代码] 接着我们在同构的代码中引用小程序的代码模块。 [代码]import * as keRouter from 'weappKeUtils/router'; export function refresh() { if (process.env.isMiniprogram) { keRouter.refresh(); } else { window.location.reload(); } } [代码] 最后通过 Webpack 的 [代码]externals[代码] 将 [代码]weappKeUtils[代码] 代码模块以相对路劲的方式外部依赖到小程序中。 [代码]externals: [ (context, request, callback) => { if (/^weappUtils/.test(request)) { // 通过commonjs引入小程序项目的utils,小程序模块定位只能使用相对路径 return callback(null, request.replace('weappUtils', '../../../utils'), 'commonjs'); } return callback(); } ], [代码] 4.2 代码编写 4.2.1 小程序、H5 公共库适配 由于原本的 H5 和小程序项目是分开的,暂时没有统一的模块管理。尤其是涉及两端特有 api 的库无法共用。 需要注意的是有副作用的库,有些库中会除了 export 方法外会有一些自执行逻辑,若是其中逻辑涉及到 wx API,或 Web API,会导致另一端上抛出异常,需要注意分别在两端中剔除无关的库。 因此可以考虑抽出一个适配层,抹平两端公共库的差异,如 request、上报组件、统一路由跳转等。 举个例子,由于同构的代码在 H5 项目中,我们将小程序的 request 方法向 H5 的 request 方法对齐入参和返回值,进行适配。 [代码]/* strip-block--h5-only:end */ request = function mpRequest(url: string, options: any = {}) { // ... } /* strip-block--h5-only:end */ /* strip-block--h5-only:begin */ request = require('assets/request').default; /* strip-block--h5-only:end */ export default request; [代码] 4.2.2 open-type button 的回调函数 React 有一套自己的事件系统,用事件委托的方法,在 document 对事件进行监听。因此我们在 JSX 中所传入的若不是 React 支持的 DOM 事件(如 click、mouseenter),DOM 上是获取不到我们传入的回调方法的。 而在小程序中,对于部分设置了 open-type 的 button,小程序支持设置回调来获取一些用户授权的信息,如 [代码]<button open-type="getPhoneNumber">[代码] 对应了 [代码]bindgetphonenumber[代码] 回调,我们从在回调中获得解密用户手机号码的参数。这些都不是 React 中支持的回调函数。 因此这些方法需要被手动绑定到 DOM 上,才能被 Kbone 获取并触发到。我们可以另外封装一个 WxButton 组件,对这种特殊的回调做处理: [代码]processWxEvents = (fn: any) => { if (process.env.isMiniprogram) { Object.keys(this.props).forEach((k) => { if (k.indexOf('wxOn') === 0) { const eventName = `on${k.slice(4)}`; fn(eventName, this.props[k]); } }); } } componentDidMount() { this.processWxEvents(this.addEventToDom); } componentWillUnmount() { this.processWxEvents(this.removeEventFromDom); } render() { const { children, className } = this.props; return ( <wx-button {...this.props} {...(className ? { class: className } : null)} ref={this.buttonRef} > {children} </wx-button> ); [代码] 4.2.3 小程序组件 boolean 类型的属性 小程序组件有时候需要传递 boolean 类型的参数,如 [代码]<image>[代码] 的 lazy-load 属性,直接在 JSX 中书写[代码]<img lazy-load />[代码],属性也无法被 Kbone 读取到,可以换种方式,通过类型转换来传递 boolean 类型的属性: [代码]<img lazy-load={1} /> [代码] 5 小程序同构页面优化 5.1 体积优化 腾讯课堂小程序原本大小大约是1350k,同构页面基本开发完后,构建出的页面分包大小约800k,页面甚至比主包还要多出200k。 [图片] 5.1.1 主要打包内容分析 React:由于使用 Kbone 能够真正引入 Vue、React 的运行时,最终的代码包也会完整包含这些库的代码。本次同构页面引入压缩后的 react + react-dom 大约是120k。 Kbone适配层组件:Kbone 通过两个 npm 包 [代码]miniprogram-element[代码] 和 [代码]miniprogram-render[代码] 来提供基础的 dom/bom api,这两个包在压缩后上传约180k。 业务wxss代码:压缩前约350k。 业务js代码:压缩前约340k。 其中1、2部分属于第三方库,不容易进一步优化,于是我们把目光聚焦在构建出的业务代码。 5.1.2 精简 css 业务 wxss 代码达到 350k 显然是不正常的。经过排查,PostCSS 转换出的 wxss 文件中包含了两块“庞然大物”:base64的背景图和iconfont。 其中背景图是当前需求引入的,我们将背景图上传到cdn上,并设置图片加载失败时的背景色,避免将图片资源打包入 css 中。 而 iconfont 在小程序中本身就有一份设置在了全局样式中,没有必要重复打包一份到页面级的 wxss。于是这里选择复用小程序公共样式,对 H5 和小程序分开处理。首先抽出 iconfont 相关的 css 文件 [代码]catefont.css[代码],在构建 H5 时引入,而在构建小程序时将其去除。 [代码]import './index.css'; /* strip-block--h5-only:begin */ import './catefont.css'; /* strip-block--h5-only:end */ [代码] 在去除了背景图和重复样式(iconfont)后,wxss仅剩约90k(压缩前)。 5.1.3 精简 js npm 包和小程序代码复用,通过前面 Webpack 构建实现。 Tree Shaking,通过前面 Webpack 构建实现。 精简后,js 仅剩约100k(压缩前)。 最终代码约420k,其中包含约300k的第三方库。活动页面是一个分包,对主包大小不造成影响。 [图片] 6 总结 就目前 Kbone 实现的同构小程序效果来看还是不错的: 开发体验:低成本接入现有 H5 项目,并只需要针对 [代码]process.env.isMiniprogram[代码] 做小程序端特有的逻辑,其他完全与开发 H5 无异。 性能质量:由于实践的页面结构相对简单,所以流畅性基本可以与原生开发一样。后续实践将会针对结构复杂的页面研究其性能。 从上面开发实践来看,虽然已实现 H5 和小程序同构,但仍有一些可以改进优化的地方,例如 [代码]webpack-strip-block[代码] 这个 loader,它通过注释包裹的方式来区分 H5 端和小程序端的依赖引入(import),在 vscode 下可能会自动修正依赖引入的顺序,导致注释包裹内的依赖乱掉并影响到程序正常的运行,所以后续需要通过另外一种方式来优化这一部分。
2019-11-04 - 报名开启:云开发技术峰会-公益编程挑战赛
[图片][图片][图片][图片]
2022-03-08 - 我想问一下 button hooseavatar获取到的头像临时路径如何保存到自己的服务器?
我想问一下 button hooseavatar获取到的头像临时路径如何保存到自己的服务器?只有一个临时图片文件路径,好像不能做上传,存到自己的服务器上吧?
2021-12-29 - 小程序网页端客服功能上新
为更好地满足小程序客服人员使用网页端客服的需求,平台更新网页端客服状态设置、会话转接、主动结束会话、自动接入、自动回复、数据面板、拉起小程序能力,提升客服的沟通效率。 本次更新点: 1. 客服状态,明确客服在线/离线 为便于客服更好地体现在线状态,平台将原网页端客服设置内的新消息通知开关升级为客服状态,并将展示位置迁移至左上角小程序头像处。切换客服状态,搭配其他功能使用,提升立客服应答率,提升用户体验。 [图片] 2. 会话转接,把用户咨询分配给对应客服 为便于客服更好地解答用户咨询,支持客服将已接入的用户咨询转接给另一个在线的客服,并附带转接留言。 [图片] [图片] [图片] 3. 主动结束会话,便于会话新增消息时被其他客服接入 为便于客服更好管理会话消息的收发,支持客服主动结束会话,操作后用户再次咨询,会话会出现在待接入列表,可被其他客服接入。 [图片] 4. 自动接入,快速接入多个会话,减少用户等待时间 为便于客服更快接入会话,支持自动接入,自定义接入规则(已接入列表中,待回复低于X人,自动接入Y人,已读未回视作待回复,会话右上角有红圈标识),无需手动逐个接入。 [图片] [图片] 5. 自动回复,提升用户接入体验,提高离线应答率 为便于客服在线和离线时更好的回复咨询,支持客服接入时欢迎语,提升用户接入体验;同时支持离线时自定义回复和关键词回复,且支持定义离线回复优先级。 5.1 客服在线接入时自动回复:仅在客服接入用户咨询时触发。 5.2 客服离线时自定义回复与关键词回复:仅在客服离线时触发。 [图片] [图片] [图片] 6. 数据面板,掌握小程序客服应答情况 为帮助客服提升客服应答质量,支持展示商家的客服整体使用概况和单客服服务情况,同时支持聊天记录下载。小程序管理员可查看店铺所有回复情况和下载所有聊天记录,非管理员客服可查看自己的服务情况和下载自己的聊天记录。 [图片] [图片] [图片] 7. 网页端客服拉起小程序,打开小程序更方便 为提升客服在网页端的体验,支持在登录电脑微信客户端的情况下,在网页端点击小程序卡片直接拉起小程序,无需转换到移动端再打开小程序,同端操作更方便。 [图片] 后续客服系统将会持续迭代更新,欢迎各位商家分享使用体验及建议。
2021-09-15 - 报告微信公告的小bug
第一个常用主页列表排版不对,第二个文本无换行 [图片][图片]
2022-01-26 - 小程序安全检测上线公告
为进一步提升小程序的安全性和用户体验,目前平台将对提审的小程序进行安全检测,以便能及时帮助开发者发现小程序可能存在的安全漏洞。 一、背景介绍 小程序在开发过程中若存在安全漏洞的情况,如敏感数据篡改、拖库信息泄露、WEB攻击等,容易造成小程序的安全隐患,可能带来代码易被反编译、核心业务逻辑被破译、算法易被二次打包等风险。因此,平台将对提审的小程序进行安全检测,以协助开发者提升小程序服务的安全性,同时开发者也应加强自身小程序安全漏洞监测能力,保证可及时消除潜在的安全风险。 二、审核过程 安全检测过程中,平台会模拟真实业务场景,向提审小程序的后台发送服务请求,服务器会收到来自平台(显示为:Tencent Security Team,请求IP为106.55.202.118;113.96.223.69;125.39.132.125;43.139.209.119)的请求。该请求均以较低速率进行,正常情况下不会影响小程序的正常服务。若确实出现了影响小程序正常业务的特殊情况,如用户无法进行小程序的正常访问,开发者可基于自身业务情况,对相应请求加以限频,如有其他疑问,欢迎随时通过官方社区进行反馈。 三、审核结果 安全检测的结果是小程序审核的重要参考。若小程序在安全检测中被检测到存在安全漏洞,该小程序的审核将不予通过。开发者可根据扫描报告中的修改指引,对安全漏洞进行相应修复后,再重新进行提审。 其他常见问题 Q1:可以选择不进行安全检测吗,是否会影响小程序代码提审结果? A1:安全检测是小程序审核的环节之一,所有提审的小程序均需进行,若检测中发现安全漏洞或小程序故意采取措施规避检测,该小程序的审核将不予通过。 Q2:若在小程序代码审核已结束或审核已撤销的情况下,可以停止安全检测吗? A2:若在小程序代码审核已结束的情况下,平台将持续进行未完成的安全检测直至完成,如有需要,开发者可通过平台提供的相应链接(在【小程序管理后台 → 通知中心】查看站内信即可)自行中止安全检测;若在小程序审核已撤销的情况下,平台将自动中止未完成的安全检测。 附表:安全检测内容详情 [图片]
03-08 - 个人微信支付新手攻略整理
前言: 虽然有部分微信支付对接经验,但在整个微信支付生态中,我自己也是新手。 此文用来制作新手攻略,以及微信支付知识的梳理记录。 一、【入门问题篇】 入门级的几个初级问题。 1,申请接入微信支付要花钱吗? 申请费用:无 交易服务费:根据商家经营类目判定,0.6%-1%不等 费率与结算周期说明:https://kf.qq.com/faq/140225MveaUz1501077rEfqI.html 2,我该去哪申请? 微信支付商户平台:https://pay.weixin.qq.com/ 3,我们有APP、公众号、小程序等多个应用,需要申请几个商户号? 申请1个商户号即可,都关联同一个商户号。 4,需要写代码进行支付对接吗? 多数支付都需要商家有开发能力,进行代码研发; 也有无需开发的,比如微信收款商业版。 5,申请微信支付需要哪些企业信息? 一般需要营业执照、对公账号、法人证件等。 6,各种微信支付对接都涉及哪些平台网站? 微信商户平台(商户号):https://pay.weixin.qq.com/ 微信公众平台(公众号、小程序):https://mp.weixin.qq.com/ 企业微信平台:https://work.weixin.qq.com/ 二、【场景选择篇】 这需要根据你们的业务场景,申请接入对应的微信支付。 官方指引截图:https://pay.weixin.qq.com/static/applyment_guide/applyment_index.shtml [图片] 场景 前提 对接支付 是否需开发 文档地址 线下场所 付款码支付 需要 开发文档 JSAPI支付 需要 开发文档 微信收款商业版 不需要 文档地址 公众号 已做微信认证;服务号、政府或媒体订阅号。 JSAPI支付 需要 开发文档 小程序 已做微信认证的小程序。 小程序支付 需要 开发文档 PC网站 网站域名已ICP备案。 JSAPI支付 需要 开发文档 Native支付 需要 开发文档 APP 微信开放平台创建APP,且平台已认证。 APP支付 需要 开发文档 企业微信 企业微信平台注册,且平台已认证。 向员工发红包 需要 开发文档 向员工付款 需要 开发文档 向员工收款 需要 开发文档 手机网站(非微信环境) H5支付 需要 开发文档 三、【业务流程篇】 简要业务实现逻辑描述。 大体流程: 商家系统:通过各种处理(预订单、二维码等),向用户展示收款页面; 用户:付款支付; 微信系统:异步通知商家服务器; 商家系统:处理用户付款后续。 以JSAPI支付为例,下图来自官方。 [图片] 四、【运营工具篇】 你可能感兴趣的: 现金红包: https://pay.weixin.qq.com/static/product/product_intro.shtml?name=hongbao 代金券: https://pay.weixin.qq.com/static/product/product_intro.shtml?name=coupon 立减与折扣: https://pay.weixin.qq.com/static/product/product_intro.shtml?name=minus 企业付款到零钱: https://pay.weixin.qq.com/static/product/product_intro.shtml?name=wallet 分账: https://pay.weixin.qq.com/static/product/product_intro.shtml?name=cmn 五、【高手进阶篇】 社区网友文章推荐: 1,如何用十个月时间,做出一款迄今为止无法超越的微信支付SDK基础开发包? - 微信开放社区 https://developers.weixin.qq.com/community/pay/article/doc/000886b054c7708ae8ebcc04b5b013 2,ASP.NET Core 微信支付? - 微信开放社区 https://developers.weixin.qq.com/community/pay/article/doc/0000aef5b20b002a02fb5a9f75b013 3,微信支付商户入门(合集)最后更新时间2021年4月5号? - 微信开放社区 https://developers.weixin.qq.com/community/pay/article/doc/000ce0be104fe8db37fbf478b5b813 4,「干货分享」一文了解微信优惠券产品(卡券、代金券、商家券)? - 微信开放社区 https://developers.weixin.qq.com/community/pay/article/doc/000460b5934fd0f7f1eb902a251013 5,真香:一行命令即可体验「微信支付」全系接口能力? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/000e264b100a88609bebe202856413 6,订单支付成功,但是一直未收到微信的支付成功回调通知? - 微信开放社区 https://developers.weixin.qq.com/community/develop/doc/000a8e42b54488af574b1f48156809 7,搞懂微信支付 v3 接口规则-【附Java源码】? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/000cca8440c6a0dca61a3efb053c13 8,微信支付后默认关注公众号与推荐关注公众号规则? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/0008c6203446a0dc706ba798f51c13 9,微信支付普通分账、服务商分账申请高比例流程及材料(4月8号更新)? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/00042e3a5b4d78f5f06bcdfb951c13 10,云开发微信支付配置添加商户号后,绑定状态为“待模板消息确认”如何处理?? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/0004e0e32bcf006ab06bdca4f56813 11,微信支付商户免充值代金券接口升级验收指引(一)用例组合1003+1004+1005? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/0000c6941647a085d6fbe0fb256013 12,申请退款API 所使用资金对应的资金账户类型区别? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/00042215948a6895ecfb44b935d013 13,创建代金券接口报错:“可用商户不符合规则,请检查” 是什么原因? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/00064aac3c00b075e8fb57c0c54c13 14,发送失败,此请求可能存在风险,已被微信拦截,是什么原因? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/0004c65f0640804db3fba1feb56413 15,V3调起支付报错:“支付失败,请稍后重试” 解决方案? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/000482f9ce03e847faebc2c0756413 16,公众号支付报错:“当前页面的URL未注册”? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/0002cc472406c8f0e7eb09cfa54c13 17,企业付款到零钱API钱没到账该如何处理? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/00082a437648f8b0daebad6b05b013 18,收不到微信支付回调通知解决方案? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/000cc28e044630e65deba58ad56c13 19,openid和appid不匹配该如何解决? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/00080a39a30378f34eebe89575b013 20,图片上传(营销)demo_PHP版本? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/0008aea4170db86b1aeba260a5b413 六、【社区支付专区篇】 有支付问题可以到微信开放社区发问。 专区地址:https://developers.weixin.qq.com/community/pay 官方介绍:【微信支付新人必读】智慧的提问,快速的解答? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/0004a8c574082063ab3b2703751813 感谢阅读!
2021-05-10 - 云开发实战教程
用云开发来做一个小程序的功能与实战教程,讲解核心能力如何用云开发实现,例如:用户管理、小程序码、短信应用、分享卡片等。
2022-03-28 - 小程序中如何实现并发控制?
小程序中如何实现并发控制? 一、性能之网络请求数 wx.request、wx.uploadFile、wx.downloadFile 的最大并发限制是 10 个; 小程序中,短时间内发起太多请求会触发小程序并发请求数量的限制同时太多请求也可能导致加载慢等问题,应合理控制请求数量,甚至做请求的合并等。 上传多图使用Promise.all并发处理,很容易触发限制,导致请求失败。 故需做并发控制。实现并发控制此处将对p-limit和async-pool进行研究 二、p-limit并发控制的实现 2.1 p-limit的使用 [代码]const limit = pLimit(1); const input = [ limit(() => fetchSomething('foo')), limit(() => fetchSomething('bar')), limit(() => doSomething()) ]; // 一次只运行一个promise const result = await Promise.all(input); console.log(result); [代码] pLimit(concurrency) 返回一个[代码]limit[代码]函数。 concurrency(Number): 表示并发限制,最小值为1,默认值为Infinity limit(fn, …args) 返回通过调用[代码]fn(...args)[代码]返回的promise fn(Function): 表示Promise-returning/async function args: 表示传递给fn的参数 limit.activeCount 当前正在运行的promise数量 limit.pendingCount 等待运行的promise数量(即它们的内部fn尚未被调用)。 limit.clearQueue() 丢弃等待运行的pending promises。 2.2 p-limit 的实现 要想理解p-limit必须先掌握浏览器中event-loop的执行顺序: [代码]console.log('script start') async function async1() { await async2() console.log('async1 end') } async function async2() { console.log('async2 end') } // 以上两个async函数可改写为以下代码 // new Promise((resolve, reject) => { // console.log('async2 end') // // Promise.resolve() 将代码插入微任务队列尾部 // // resolve 再次插入微任务队列尾部 // resolve(Promise.resolve()) // }).then(() => { // console.log('async1 end') // }) // 如果 await 后面跟着 Promise 的话,async1 end 需要等待三个 tick 才能执行到 async1() setTimeout(function() { console.log('setTimeout') }, 0) new Promise(resolve => { console.log('Promise') resolve() }) .then(function() { console.log('promise1') }) .then(function() { console.log('promise2') }) console.log('script end') // script start => async2 end => Promise => script end => promise1 => promise2 => async1 end => setTimeout [代码] 先介绍下宏任务和微任务具体有哪些内容, 微任务包括 [代码]process.nextTick[代码] ,[代码]promise[代码] ,[代码]MutationObserver[代码],其中 [代码]process.nextTick[代码] 为 Node 独有。 宏任务包括 [代码]script[代码] , [代码]setTimeout[代码] ,[代码]setInterval[代码] ,[代码]setImmediate[代码] ,[代码]I/O[代码] ,[代码]UI rendering[代码]。 Event Loop 执行顺序如下所示: 首先执行同步代码,这属于宏任务 当执行完所有同步代码后,执行栈为空,查询是否有异步代码需要执行 执行所有微任务 当执行完所有微任务后,如有必要会渲染页面 然后开始下一轮 Event Loop,执行宏任务中的异步代码,也就是 [代码]setTimeout[代码] 中的回调函数 [代码]function pLimit(concurrency) { if(!((Number.isInteger(concurrency)||concurrency===Number.POSITIVE_INFINITY)&&concurrency>0)) { throw new TypeError('Expected `concurrency` to be a number from 1 and up'); } // 用一个queue队列维护所有Promise异步函数 const queue=[]; let activeCount=0; const next=() => { // 某异步函数完成后,需要将activeCount-- activeCount--; if(queue.length>0) { // 再次从队列中出队并执行异步函数,activeCount维持在concurrency queue.shift()(); } }; const run=async (fn,resolve,args) => { // activeCount++; // 进一步将fn封装为异步函数并运行 const result=(async () => fn(...args))(); // 此处返回generator函数 的resolve值,即Promise.all resolve(result); try { // 等待result异步函数完成(例如某请求完成) await result; } catch {} next(); }; const enqueue=(fn,resolve,args) => { queue.push(run.bind(undefined,fn,resolve,args)); // setTimeout(()=>{ // // 正在运行的Promise数量activeCount始终不大于concurrency,从而达到控制并发的目的 // if(activeCount<concurrency&&queue.length>0) { // // 队列出队并执行改函数 // queue.shift()(); // } // },0); (async () => { // 这个函数需要等到下一个微任务再比较 `activeCount` 和 `concurrency` // 因为 `activeCount` 在 run 函数出列和调用时异步更新。 // if 语句中的比较也需要异步进行,以获取 `activeCount` 的最新值。 await Promise.resolve(); // 正在运行的Promise数量activeCount始终不大于concurrency,从而达到控制并发的目的 if (activeCount < concurrency && queue.length > 0) { // 队列出队并执行改函数 queue.shift()(); } })(); }; const generator = (fn,...args) => new Promise(resolve => { enqueue(fn,resolve,args); }); Object.defineProperties(generator,{ // 正在运行的Promise数量 activeCount: { get: () => activeCount, }, // 等待运行的Promise数量 pendingCount: { get: () => queue.length, }, // 清空queue队列中的异步函数 clearQueue: { value: () => { while(queue.length!=0) { pueue.shift(); } }, }, }); return generator; } [代码] 三、asyncPool并发控制的实现 async-pool 这个库提供了 ES7 和 ES6 两种不同版本的实现,在分析其具体实现之前,我们来看一下它如何使用。 3.1 asyncPool 的使用 [代码]function asyncPool(poolLimit, array, iteratorFn){ ... } [代码] 该函数接收 3 个参数: [代码]poolLimit[代码](Number):表示限制的并发数; [代码]array[代码](Array):表示任务数组; [代码]iteratorFn[代码](Function):表示迭代函数,用于实现对每个任务项进行处理,该函数会返回一个 Promise 对象或异步函数。 [代码]asyncPool[代码]在有限的并发池中运行多个promise-returning & async functions。一旦其中一个承诺被拒绝,它就会立即拒绝。当所有 Promise 完成时,它就会resolves。它尽快调用迭代器函数(在并发限制下)。例如: [代码]const timeout = i => new Promise(resolve => setTimeout(() => resolve(i), i)); await asyncPool(2, [1000, 5000, 3000, 2000], timeout); // Call iterator (i = 1000) // Call iterator (i = 5000) // Pool limit of 2 reached, wait for the quicker one to complete... // 1000 finishes // Call iterator (i = 3000) // Pool limit of 2 reached, wait for the quicker one to complete... // 3000 finishes // Call iterator (i = 2000) // Itaration is complete, wait until running ones complete... // 5000 finishes // 2000 finishes // Resolves, results are passed in given array order `[1000, 5000, 3000, 2000]`. [代码] 通过观察以上的注释信息,我们可以大致地了解 [代码]asyncPool[代码] 函数内部的控制流程 3.2 asyncPool 实现 [代码]async function asyncPool(poolLimit, array, iteratorFn) { const ret = []; // 存储所有的异步任务 const executing = []; // 存储正在执行的异步任务 for (const item of array) { // 调用iteratorFn函数创建异步任务 const p = Promise.resolve().then(() => iteratorFn(item, array)); ret.push(p); // 保存新的异步任务 // 当poolLimit值小于或等于总任务个数时,进行并发控制 if (poolLimit <= array.length) { // 当任务完成后,从正在执行的任务数组中移除已完成的任务 const e = p.then(() => executing.splice(executing.indexOf(e), 1)); executing.push(e); // 保存正在执行的异步任务 if (executing.length >= poolLimit) { await Promise.race(executing); // 等待较快的任务执行完成 } } } return Promise.all(ret); } [代码] 在以上代码中,充分利用了 [代码]Promise.all[代码] 和 [代码]Promise.race[代码] 函数特点,再结合 ES7 中提供的 [代码]async await[代码] 特性,最终实现了并发控制的功能。利用 [代码]await Promise.race(executing);[代码] 这行语句,我们会等待 正在执行任务列表 中较快的任务执行完成之后,才会继续执行下一次循环。 四、实践运用 使用p-limit [代码]const limit=pLimit(5); const fn=() => { return axios({ method: 'get', url: 'https://www.fastmock.site/mock/883c2b5177653e4ef705b7ffdc680af1/daily/story', }) .then(function(response) { return response.data; }); }; const input=[]; for(let i=0;i<50;i++) { input.push(limit(fn)) } Promise.all(input).then(res => { console.log('res',res) }); [代码] [图片] 使用asyncPool [代码]const fn=() => { return axios({ method: 'get', url: 'https://www.fastmock.site/mock/883c2b5177653e4ef705b7ffdc680af1/daily/story', }) .then(function(response) { return response.data; }); } const input=[]; for(let i=0;i<50;i++) { input.push(fn); } const timeout= f => new Promise(resolve => setTimeout(() => resolve(f()))); asyncPool(5,input,timeout).then(res => { console.log('res',res); }) [代码] [图片]
2021-12-09 - 小程序·云开发实战 - 校园约拍小程序
创意来源于生活,之所以开发这个校园约拍小程序,是因为在摄影选修课上常听老师抱怨外出写生老找不到模特,许多大学生都想拥有一套专属自己记忆的摄影作品,记录下不会磨灭的美好回忆,可如何找到让自己满意的摄影师是他们的难题。悦拍屋是一个校园摄影o2o的约拍平台,提供全方位的约拍服务,同时提供一个自我展示,学习交流,互动娱乐的平台。接下来我将结合项目的讲解给大家分享一些实用技术和对于云开发的一些经验,希望对正在学习小程序的你有帮助。 前言 在开发一个项目之前首先要进行技术选型从而降低产品开发的技术风险和提高开发效率,技术选型必须得紧紧围绕着业务场景来选择。 产品原型设计:墨刀 UI组件库 1.微信原生样式库[代码]WeUI[代码],让用户使用感知更加统一 2.注重视觉交互体验的[代码]ColorUI[代码]组件库,在感知统一的基础上视觉元素多样化 前端 1.小程序原生语法以及[代码]API[代码] 2.[代码]Promise[代码]实现异步调用 3.[代码]ES6[代码]编写页面交互逻辑 后端 1.云函数:无需自建服务器,在云端运行的代码,微信私有协议天然鉴权,开发者只需编写自身业务逻辑代码 2.云数据库:无需自建数据库,一个既可在小程序前端操作,也能在云函数中读写的 [代码]JSON[代码] 数据库 3.云存储:实现小程序前端直接上传/下载云端文件,在云开发控制台可视化管理 4.云调用:由原生微信服务集成,基于云函数免鉴权使用小程序开放接口的能力,包括服务端调用、获取开放数据等能力 其他 1.使用微信提供的云测试对未上线的小程序进行缺陷测试、性能数据分析、机型覆盖测试,确保小程序上线后正常运营 2.使用基于云开发的[代码]AI视觉能力[代码]-身份证识别实现实名认证,智能鉴黄结合人工完成发布信息的审核 3.开发工具:微信开发者工具、VScode 4.部分图标使用自阿里巴巴矢量图标库 总体设计 功能结构图 大家可以通过此图了解整个项目的主要功能点 [图片] 产品原型图 此处给出一张主页原型图示例,墨刀还是挺好用的 [图片] 色彩设计图 悦拍屋的整体色调为浅蓝色,各位小伙伴在开发自己项目的时候可以根据色彩标准搭配来设计项目所采用的色彩,合适的色彩搭配可以给用户良好的视觉体验 [图片] 功能模块详解 接下来我会对部分功能模块以图文结合的形式详细描述,将其中涉及的技术、知识分享给大家 约拍邀请 用户可在首页查看约拍需求,并点击查看需求详情,用户在了解需求后,若自己符合条件即可提交约拍信息,等待发布者的回复,可将此需求收藏方便查看 [图片] 技术分享:自定义顶部导航栏 官方默认的导航栏只能对背景颜色进行更改,对于想要在导航栏添加一些比较酷炫的效果则需要通过自定义导航栏实现 实现原理:通过设置[代码]app.json[代码]中页面配置的[代码]navigationStyle[代码](导航栏样式)配置项的值为[代码]custom[代码],即可实现自定义导航 [代码]"window":{ "navigationStyle":"custom" } [代码] 本项目的部分页面自定义导航栏实现使用了[代码]ColorUI[代码]的导航栏组件,在完成上一步属性设置后再引入导航栏组件即可 [代码]"usingComponents":{ "cu-custom":"/colorui/components/cu-custom" //该路径替换为自己项目内ColorUI组件所在位置 } [代码] 主页自定义导航栏通过设置背景图片加上GIF波浪效果 [代码] <view class='page__bd'> <view class="bg-img padding-tb-xl" style="background-image:url('http://wx4.sinaimg.cn/mw690/006UdlVNgy1g2v2t1ih8jj31hc0p0qej.jpg');background-size:cover;"> <view class="cu-bar"> <view class="content text-bold text-white"> 悦拍屋 </view> </view> </view> <view class="shadow-blur"> <image src="https://image.weilanwl.com/gif/wave.gif" mode="scaleToFill" class="gif-black response" style="height:100rpx;margin-top:-100rpx;"></image> </view> </view> [代码] 效果图 [图片] 使用组件定义的导航栏 [代码]<cu-custom bgImage="https://s2.ax1x.com/2019/05/02/Etiyng.jpg" isBack="{{true}}"> <view slot="backText">返回</view> <view slot="content">认证信息说明 </view> </cu-custom> [代码] 效果图 [图片] [代码]特别提醒1:使用自定义导航后,页面的返回需要在自定义导航栏中自行设置 [代码] [代码]特别提醒2:导航栏组件需要自行引入ColorUI组件库后才能使用,具体引入教程地址在附录中给出 [代码] 发布约拍 选择发布约拍功能填写约拍需求,提交审核通过后可在首页实时查看发布结果 [图片] 技术分享:入场动画 额。。录制可能略微有点卡顿,实际效果挺流畅的,各位大佬有什么好的录制工具推荐可以在评论中回复 实现原理:通过[代码]toggleDelay[代码]的布尔值为真动态添加动画类名,在生命周期函数[代码]onReady[代码]中控制[代码]toggleDelay[代码]的值从而控制整个动画过程(原理与[代码]Vue[代码]的动态类名相似) [代码]data:{ toggleDelay;false }, onReady:function(){ let that = this //toggleDelay的值为真,动画开始 that.setData({ toggleDelay: true }) //控制整个动画的时长 setTimeout(function() { that.setData({ toggleDelay: false }) }, 2000) } [代码] [代码]<view class="padding-xs {{toggleDelay?'animation-slide-bottom':''}}" style="animation-delay: {{item.time}}s;" wx:for="{{list}}" wx:key="{{index}}"> <image class="img" id='img{{index}}' src="{{item.src}}" mode="widthFix" /> </view> [代码] [代码]//所有动画的定义 [class*=animation-] { animation-duration: .5s; animation-timing-function: ease-out; animation-fill-mode: both } //animatioon-slide-bottom所定义的动画 .animation-slide-bottom { animation-name: slide-bottom } //动画效果 @keyframes slide-bottom { 0% { opacity: 0; transform: translateY(100%) } 100% { opacity: 1; transform: translateY(0) } } [代码] [代码]animation-slide-bottom[代码]是动画类名,[代码]animation-delay[代码]是每一个卡片动画执行的延迟时间,每一个动画的执行时长为0.5s,所以延迟时间是以0.5s递增的,三个卡片的动画总时长就为2s,即2s后就执行[代码]onReady[代码]中的[代码]settimeout[代码]事件结束动画 [代码]特别提醒:动画的延迟时间,执行时间可以自行设计,动画效果过渡自然即可 [代码] [代码]特别提醒:由于触发动画的钩子函数定义在页面初次渲染的生命周期函数中,故只有在页面初次渲染时才执行,避免每次显示页面时加载动画造成用户的视觉疲劳 [代码] 智能推荐约拍对象 系统会根据约拍需求自动推荐约拍对象(个人开发精力有限,推荐算法后续推出。。。) [图片] 技术分享:CSS3实现酷炫搜索动画 在模态框内放置两个[代码]view[代码]标签,以下是标签定义 [代码] <view id='preloader'> //外围的圆形框定义 <view id='loader'></view> //内部的线条定义 </view> [代码] [代码]#preloader { width: 150px; height: 150px; border-radius: 50%; border: 1px solid #97b2ff; } #loader { //中间线条定义 display: block; position: relative; left: 50%; top: 50%; width: 150px; height: 150px; margin: -75px 0 0 -75px; border-radius: 50%; border: 3px solid transparent; border-top-color: #97b2ff; -webkit-animation: spin 2s linear infinite; animation: spin 2s linear infinite; } #loader:before { //通过伪类元素定义外围线条 content: ""; position: absolute; top: 5px; left: 5px; right: 5px; bottom: 5px; border-radius: 50%; border: 3px solid transparent; border-top-color: #97b2ff; -webkit-animation: spin 3s linear infinite; animation: spin 3s linear infinite; } #loader:after { //通过伪类元素定义最内部线条 content: ""; position: absolute; top: 15px; left: 15px; right: 15px; bottom: 15px; border-radius: 50%; border: 3px solid transparent; border-top-color: #97b2ff; -webkit-animation: spin 1.5s linear infinite; animation: spin 1.5s linear infinite; } [代码] 实名认证 [图片] 嘿嘿,由于懒得给个人信息打码,就暂时不给大家演示认证过程了。。 技术分享:Ai视觉能力 很多小伙伴都有过在自己项目中使用AI技术的想法,但又因为入门AI的难度比较大,并且需要的时间较长就放弃了,现在给大家安利一个可以直接使用的AI服务,让AI不再具有神秘感(AI大佬可以忽略此部分。。) 方案一 在腾讯云中搜索身份证识别,上面会有详细的API文档以及测试工具帮助你快速使用 [图片] 点击查看腾讯云-身份证识别 方案二 方案一是以提供API接口的形式提供身份证识别服务,而接下来要介绍的方案真的就比较简单了,在腾讯云中搜索智能图像,其中的增值服务AI智能图像能力,你可以通过云函数和云存储实现相应功能,基于小程序云开发的 AI DEMO中开发好了部分功能,你只需通过教程将云函数和组件引入你的项目即可使用 [图片] 点击查看腾讯云-智能图像 点击查看基于小程序云开发的 AI DEMO [代码]特别提醒:当然使用这些服务也并非是完整的解决方案,对于身份证信息的加密、存储方案、安全协议等还是需要各位小伙伴自行设计解决方案哦。 [代码] 云开发 云开发为开发者提供完整的原生云端支持和微信服务支持,弱化后端和运维概念,无需搭建服务器,使用平台提供的 API 进行核心业务开发,即可实现快速上线和迭代,同时这一能力,同开发者已经使用的云服务相互兼容,并不互斥。 官方文档中API被分为了小程序端和服务端,一开始看过两端的API之后,感觉好像没有什么不同啊,在查阅相关资料以及实际开发中某些业务的处理总结出一些经验后才明白了两者的不同,下面给各位具体说说两者的不同之处,应该能帮助大家在使用云开发实战时少踩一点坑 初始化的不同 小程序端 全局声明一次 [代码]if (!wx.cloud) { console.error('请使用 2.2.3 或以上的基础库以使用云能力') } else { wx.cloud.init({ env:'xxx', traceUser: true, }) } [代码] 服务端 每个云函数中声明一次 [代码]const cloud = require('wx-server-sdk') cloud.init() [代码] 权限不同 小程序端 在小程序端可以选择直接操作数据库,但由于是前端操作数据库存在一些安全问题,有较多的权限限制,在云控制中可对每个集合进行权限设置,这也就是为什么有小伙伴在小程序端对某些数据进行更新,显示更新成功但并未更新数据,就是因为小程序端默认只能更新当前用户写入的数据 [图片] [代码]特别提醒:在小程序端使用创建者的权限对数据进行修改时一定要确保该集合中有_openid字段,否则系统在权限判断时是没有办法识别当前操作为创建者的,数据修改无法执行 [代码] 服务端 服务端拥有管理员的权限,对所有数据拥有读写权限 语法支持不同 小程序端 在微信开发者工具里,以及Android端手机(浏览器内核是QQ浏览器的X5),[代码]async[代码]/[代码]await[代码]是天然支持的,但 iOS 端手机在较低版本则不支持,因此需要引入额外的[代码]polyfill[代码]。可以在有使用[代码]async[代码]/[代码]await[代码] 的文件当中引入[代码]polyfill[代码]文件。 [代码]const runtime = require('相对路径/lib/runtime') [代码] 服务端 在云函数里,由于 Node 版本最低是 8.9,因此是天然支持 async/await 语法的 示例:获取约拍需求列表 [代码]//云函数入口文件 const cloud = require('wx-server-sdk') //初始化 cloud.init() //连接数据库 const db = cloud.database() async function getAll(){ const result = await db.collection('ypList') .orderBy('cameraInfo.launchTime','desc').where({}).get() return result } // 云函数入口函数 exports.main = async (event, context) => { //此处的action是用来判断该调用哪一个方法 if(event.action === 'getAll'){ return getAll() } } [代码] 结语 一个人手撸个全栈项目确实很辛苦,但收获也很多。至少对于小程序的实战开发更为熟练了,对MVVM的思想的理解也更加深刻了。技术发展得很快,学习一项技术如果不深入其本质,那么技术是学不完的。深入学习就是个解决问题的过程,或是帮助别人解决问题,或是借助他人的力量解决问题。目前在正在学习Vue、React、TypeScript等技术,后续会推出相关技术的项目解析文章,希望对于同样在学习的你有帮助。 [代码]特别说明:本项目已参加2019届中国高校计算机-微信应用开发赛完,开源至github,感兴趣的小伙伴可以看看 [代码] 附录 在此提供一些本项目涉及到的技术、工具等链接供大家学习使用 产品原型设计工具:墨刀 色彩搭配设计:配色网 在线作图:ProcessOn UI样式库:WeUI UI样式库:ColorUI 图标库:Iconfont阿里巴巴矢量图标库 开发工具:微信开发者工具 开发者工具:Vscode 腾讯云服务:身份证识别 腾讯云服务:智能图像 API文档:微信官方文档.小程序 技术文档:ES6 源码链接 https://github.com/TencentCloudBase/Good-practice-tutorial-recommended 如果你有关于使用云开发CloudBase相关的技术故事/技术实战经验想要跟大家分享,欢迎留言联系我们哦~比心! [图片]
2019-08-05 - 小程序原生高颜值组件库--ColorUI
[图片] 简介 ColorUI是一个Css类的UI组件库!不是一个Js框架。相比于同类小程序组件库,ColorUI更注重于视觉交互! 浏览GitHub:https://github.com/weilanwl/ColorUI [图片] 如何使用? 先下载源码包 → Github 引入到我的小程序 将 /demo/ 下的 colorui.wxss 和 icon.wxss 复制到小程序的根目录下 在 app.wxss 引入两个文件 [代码]@import "icon.wxss"; @import "colorui.wxss"; [代码] 使用模板全新开发 复制 /template/ 文件夹并重命名为你的项目,微信开发者工具导入为小程序就可以使用ColorUI了 体验沉浸式导航 [图片] App.js 获取系统参数并写入全局参数。 [代码]//App.js App({ onLaunch: function() { wx.getSystemInfo({ success: e => { this.globalData.StatusBar = e.statusBarHeight; let custom = wx.getMenuButtonBoundingClientRect(); this.globalData.Custom = custom; this.globalData.CustomBar = custom.bottom + custom.top - e.statusBarHeight; } }) } }) [代码] Page.js 页面配置获取全局参数。 [代码]//Page.js const app = getApp() Page({ data: { StatusBar: app.globalData.StatusBar, CustomBar: app.globalData.CustomBar, Custom: app.globalData.Custom } }) [代码] Page.wxml 页面构造导航。更多导航样式请下载Demo查阅 操作条组件。 [代码]<view class="cu-custom" style="height:{{CustomBar}}px;"> <view class="cu-bar fixed bg-gradual-pink" style="height:{{CustomBar}}px;padding-top:{{StatusBar}}px;"> <navigator class='action border-custom' open-type="navigateBack" delta="1" hover-class="none" style='width:{{Custom.width}}px;height:{{Custom.height}}px;margin-left:calc(750rpx - {{Custom.right}}px)'> <text class='icon-back'></text> <text class='icon-homefill'></text> </navigator> <view class='content' style='top:{{StatusBar}}px;'>操作条</view> </view> </view> [代码] 自定义系统Tabbar [图片] 按照官方 自定义 tabBar 配置好Tabbar (开发工具和版本库请使用最新版)。 使用ColorUI配置Tabbar只需要更改 Wxml 页的内容即可。 更多Tabbar样式请下载Demo查阅 操作条组件。 /custom-tab-bar/index.wxml [代码] <view class="cu-bar tabbar bg-white shadow"> <view class="action" wx:for="{{list}}" wx:key="index" data-path="{{item.pagePath}}" data-index="{{index}}" bindtap="switchTab"> <view class='icon-cu-image'> <image src='{{selected === index ? item.selectedIconPath : item.iconPath}}' class='{{selected === index ? "animation" : "animation"}}'></image> </view> <view class='{{selected === index ? "text-green" : "text-gray"}}'>{{item.text}}</view> </view> </view> [代码] 作者叨叨 ColorUI是一个高度自定义的Css样式库,包含了开发常用的元素和组件,元素组件之间也能相互嵌套使用。我也会不定期更新一些扩展到源码。 其实大家都在催我写文档,但这个库源码就在这,所见即所得,粘贴复制就可以得到你想要的页面。当然,文档我还是要写的,也希望大家多多提意见。 现在前端的开发方向基本都是奔着Js方向的,布局和样式大家讨论的有点少。以后我会在开发者社区多聊一聊关于开发中的布局和样式。 [图片] 感谢阅读。
2019-02-26 - 小程序中实现页面截图
最近接到一个需求,需要在小程序中实现页面截图,我一开始的考虑是使用官方提供的扩展组件wxml-to-canvas,但是实际体验下来效果很糟糕,首先它并不能截取实际的页面,而是必须传入[代码]wxml[代码]和[代码]wxss[代码];然后他能支持的效果也很少,并不能满足需求中稍微复杂的效果。最终我决定用web-view加载的网页中使用html2canvas来实现功能。 实际代码 网页部分我用了[代码]vue[代码],首先需要安装[代码]html2canvas[代码] [代码]npm install html2canvas [代码] 页面中引入 [代码]import html2canvas from 'html2canvas'; [代码] 需要截图的dom节点上添加ref属性 [代码]<div ref="page"> [代码] 截图代码 [代码]... document.body.scrollTop = 0; // 将页面滚动至顶部后再开始截图,才能保证截图的完整 html2canvas(this.$refs.page, { allowTaint: false, useCORS: true, width: document.body.scrollWidth, height: document.body.scrollHeight // 实际体验中发现最好设置宽高为页面的宽高才能获得完整的截图 }).then(canvas => { this.savedPic = canvas.toDataURL('images/png') // 用于在页面中展示的截图完成的网址 ... // 以下代码为模拟a标签的点击直接下载截图 // 但是这部分代码在移动端网页和小程序中并不会生效 let a = document.createElement('a'), blob = this.dataURLToBlob(canvas.toDataURL('images/png')); a.setAttribute('href', URL.createObjectURL(blob)); a.setAttribute('download', 'pic.png'); document.body.appendChild(a); a.click(); URL.revokeObjectURL(blob); document.body.removeChild(a); }); ... [代码] 兼容性 网页毕竟不是原生小程序,还是会存在一些兼容性问题,比如网页中不能使用小程序的wx.saveImageToPhotosAlbum直接保存生成好的截图。移动端和微信中也不支持模拟a标签的点击来下载图片,最终只能通过展示生成的截图并提示用户长按图片来实现保存图片的功能,用户体验会差点,但是考虑到截图效果比[代码]wxml-to-canvas[代码]好太多了,还是可以接受的。 最后说一下[代码]html2canvas[代码]的支持度,目前实际用下来发现不支持的样式为阴影和伪元素,其他基本上都支持。网页中的图片必须为本地图片或者支持跨域的网络图片。用到图片的地方建议直接使用[代码]img[代码]标签,而不是背景图片,[代码]img[代码]标签展示的图片清晰度远远高于背景图片。
2021-07-13 - Let's Encrypt默默的不再被支持?爬坑ing
深夜的我,正在爬坑。 因为是自己的小程序,一是节省成本,二是体验感。 先吐槽 微信小程序的自定义tabbar,因为它闪,闪,闪。等了三年愣是没改好,只能放弃。用单页面组件形式构建效果更佳。 开始, 图片防盗链设置了非空referer,开发者工具中调试图片是显示的,到真机(正式环境/调试环境)上打死都不显示。为了找错image标签加了个binderror,发现它居然报错的是404(not found),而不是403???真的狗,就直接跟我说ssl证书有问题呗。 我的域名就是用的Let's Encrypt,然后换了ssl证书,它竟然神奇的在真机的调试环境下显示了。果不其然证书问题! 腾讯云可以申请免费的ssl证书,地址:https://buy.cloud.tencent.com/ssl [图片] 太香了哈哈哈
2021-12-13 - 关于小程序获取用户信息调整的使用 调试中出现了 wx.getUserProfile is not a function
获取用户信息的调整 引起了对于wx.getUserProfile 这个API的关注 经过尝试 这个API并不支持官方文档中说的 2.10.4以上的所有版本 低于基础版本的 请调高版本 高于基础版本并出现not a function的 可以尝试调整为以下基础版本 [图片] [图片] 另外wx.getUserProfile 在 onload 或者 onshow 里面无法调用 需要设置点击事件触发获取
2021-04-07 - 一个小程序最多同时开多少个直播间?小程序直播组件直播间的直播时长是否有限制?
同一个小程序最多可以支持50个直播间同时直播,每天的直播上限也是50场。每个直播间不能直播超过12小时。
2020-04-17 - 小程序没有 DOM 接口,原因竟然是……?
拥有丰富的 Web 前端开发经验的工程师小赵今天刚刚来到新的部门,开始从事他之前没有接触过的微信小程序开发。在上手的第一天,他就向同办公室的小程序老手老李请教了自己的问题。 小赵:翻了一圈文档,小程序好像并不提供 DOM 接口?我还以为可以像之前一样用我喜欢的前端框架来做开发呢。老李,你说小程序为什么不给我们提供 DOM 接口呀。 老李:要提供 DOM 接口也没那么容易。你知道小程序的双线程模型吗?(小赵漏出了疑惑的表情)小程序是基于 Web 技术的,这你应该知道,但小程序和普通的移动端网页也不一样。你做了很多前端项目了,应该知道在浏览器里,UI 渲染和 JavaScript 逻辑都是在一个线程中执行的? 小赵:这我知道,在同一个线程中,UI 渲染和 JavaScript 逻辑交替执行,JavaScript 也可以通过 DOM 接口来对渲染进行控制。 老李:小程序使用的是一种两个线程并行执行的模式,叫做双线程模型。像我画的这样,两个线程合力完成小程序的渲染:一个线程专门负责渲染工作,我们一般称之为渲染层;而另外有一个线程执行我们的逻辑代码,我们一般叫做逻辑层。这两个线程同时运行,并通过微信客户端来交换数据。在小程序运行的时候,逻辑层执行我们编写的逻辑,将数据通过 setData 发送到渲染层;而渲染层解析我们的 WXML 和 WXSS,并结合数据渲染出页面。一方面,每个页面对应一个 WebView 渲染层,对于用户来说更加有页面的感觉,体验更好,而且也可以避免单个 WebView 的负担太重;另一方面,将小程序代码运行在独立的线程中的模式有更好的安全表现,允许有像 open-data 这样的组件可以在确保用户隐私的前提下让我们展示用户数据。 [图片] 小赵:怪不得所有和页面有关的改动都只能通过 setData 来完成。但是用两个线程来渲染我们平时用单线程来渲染的 Web 页面,会不会有些「浪费」?而且每一个页面有一个对应的渲染层,那页面变多的时候,岂不是会有很大的开销? 老李: 并不浪费,因为界面的渲染和后台的逻辑处理可以在同一时间运行了,这使得小程序整体的响应速度更快了。而在小程序的运行过程中,逻辑层需要常驻,但渲染层是可以回收的。实际上,当页面栈的层数比较高的时候,栈底页面的渲染层是会被慢慢回收的。 小赵: 原来如此。这么说的话,实际的 DOM 树是存在于渲染层的,逻辑层并不存在,所以逻辑层才没有任何的 DOM 接口,我明白了。但是……既然可以实现像 setData 这样的接口,为什么不能直接把 DOM 接口也代理到逻辑层呢?我觉得小程序可以做一个封装,让我们在逻辑层调用 DOM 接口,在渲染层调用接口后再把结果返回给我们呀。 老李:从理论上来说确实是可以的。但是线程之间的通信是需要时间的呀。将调用发送到渲染层,再将 DOM 调用结果发送回来,这中间由于线程通信发生的时间损耗可能会比这个接口本身需要的时间要多得多。如果以此为基础使用基于 DOM 接口的前端框架,大量的 DOM 调用可能会非常缓慢,让这个设计失去意义。 在实际测试中,如果每次 DOM 调用都进行一次线程通信,耗时大约是同等节点规模直接在渲染层调用的百倍以上;如果忽略通信需要的时间,一个实现良好的基于 DOM 代理的框架可以近似地看成一个动态模板的框架,而动态模板和静态模板相比要慢至少 50% 小赵:原来如此,线程通信的时间确实是我没有考虑到的问题。那现在的小程序框架中难道不存在这个问题吗? 老李: 在现在的小程序框架中,这个问题也是存在的,这也是现在的框架基于静态模板渲染的原因。静态模板可以在运行前就做好打包,直接注入到渲染层,省去线程传输的时间。在运行时,逻辑层只和渲染层进行最少的、必要的数据交换:也就是渲染用的数据,或者说 data 。另一方面,静态模板让两个线程都在启动时就拥有模板相关的所有数据,所以框架也充分利用了这一点,进行了很多优化。 小赵: 怪不得我在文档里发现很多和 setData 有关的性能提示,都提醒尽量减少设置不必要的数据,现在总算是知道为什么了。但是具体到实际开发里的时候,还是总觉得很难每次只设置需要的数据啊,像对象里或者数组里的数据怎么办呢? 老李: 如果只改变了对象里或者数组里的一部分数据,可以通过类似 array[2].message , a.b.c.d 这样的 数据路径 来进行「精准设置」。另外,现在自定义组件也支持 纯数据字段 了,只要在自定义组件的选项中设置好名为 pureDataPattern 的正则表达式, data 中匹配这个正则的字段将成为纯数据字段,例如,你可以用 /^_/ 来指定所有 开头的数据字段为纯数据字段。所有纯数据字段仅仅被记录在逻辑层的 this.data 中,而不会被发送到渲染层,也不参与任何界面渲染过程,节省了传输的时间,这样有助于提升页面更新性能。 小赵:小程序还有这样的功能,受教了。不过说来说去,我还是想在小程序里用我顺手的框架来开发,毕竟这样事半功倍嘛。我在网上搜索了一下,发现现在有很多支持用 Web 框架做小程序开发的框架,但好像都是将模板编译成 WXML,最终由小程序来做渲染,但这样的方法好像兼容性也不是很好。我在想,我们能不能在逻辑层仿造一套 DOM 接口,然后在运行时将 DOM 调用适配成小程序调用? 老李: 你的这个脑洞有一些意思。在逻辑层仿造一套 DOM 接口,直接维护一棵 DOM 树,这当然没问题。但是没有代理 DOM 接口,逻辑层的 DOM 树没法反映到渲染层,因为渲染层具体会出现什么样的组件,是运行时才能知道的,这不就没法生成静态模板了? 小赵:静态模板确实是没法生成了,但我看到小程序的框架支持自定义组件,我是不是可以做一个通用的自定义组件,让它根据传入的参数不同,变成不同的小程序内置组件。而且自定义组件还支持在自己的模板中引用自己,那么我只需要一个这个通用组件,然后从逻辑层用代码去控制当前组件应该渲染成什么内置组件,再根据它是否有子节点去递归引用自己进行渲染就可以了。你看这样可行吗? [图片] 老李: 这样的做法确实可行,而且微信官方已经按照这个思路推出小程序和 Web 端同构的解决方案 Kbone 了。Kbone 的原理就像你刚才说的那样,它提供一个 Webpack 插件,将项目编译成小程序项目;同时提供两个 npm 包,分别提供 DOM 接口模拟和你说的那个通用的自定义组件作为运行时依赖。要不你赶紧试试? 小赵:还有这么好的事,那我终于可以用我喜欢的框架开发小程序了!这么好的框架,为什么不直接内置到小程序的基础库里呀? 老李: 因为这样的功能完全可以用现在已有的基础库功能实现出来呀。Kbone 现在是 npm 包的形式,使得它的功能、问题修复可以随着自己的版本来发布,不需要依赖于基础库的更新和覆盖率,不是挺好的吗? 小赵: 好是好,但我担心的是代码包大小限制的问题。除了我们已经写好的业务逻辑之外,现在还得加上 Kbone,会不会装不下呀? 老李: 原来你是担心这个呀,放心,Kbone 现在已经可以在 扩展库 里一键搞定啦。扩展库是帮我们解决依赖的全新功能,只要在配置项中指定 Kbone 扩展库,就相当于引入了 Kbone 相关的最新版本的 npm 包,这样就不占用小程序的代码包体积了,快试试吧! 小赵:哇,那可太爽了,马上就搞起! 最后 如果你对 Kbone 感兴趣或者有相关问题需要咨询, 欢迎加入 Kbone 技术交流 QQ 群:926335938
2020-01-14 - 腾讯位置服务获取城市数据生成城市选择器组件示例
腾讯位置服务获取城市数据生成城市选择器组件示例 代码片段1:https://developers.weixin.qq.com/s/rnfrwpm374lJ 代码片段2:https://developers.weixin.qq.com/s/83dx61mT7opo 修复tabs 文字过长 效果图: [图片] 开发中遇到的问题: https://developers.weixin.qq.com/community/develop/doc/000ca8e45b8e400c862b97d6c51000 知识补充文档: 1、https://segmentfault.com/a/1190000014724227?utm_source=index-hottest 2、https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain 提示: 引用代码请填写 key; https://lbs.qq.com/miniProgram/jsSdk/jsSdkGuide/methodGetdistrictbycityid [图片] // component/city-picker/city-picker.js const QQMapWX = require('./qqmap-wx-jssdk.min.js'); const qqmapsdk = new QQMapWX({ key: 'LTGBZ-...-....-SYPGW-EYYHZ-....' // 请填写 key https://lbs.qq.com/miniProgram/jsSdk/jsSdkGuide/methodGetdistrictbycityid });
2021-03-23 - #小程序 小程序和公众号内长按识别哪些码是有效的
Tip:2021-05-21 测试了小程序图片长按识别个人微信码、群聊码、企业微信码可以直接添加。 须知:以下结果均在微信IOS最新版(8.0.2)测试所得!!! 视频号二维码 公众号内长按识别结果:可以 小程序内长按识别结果:不可以 小程序内webview(公众号文章):不可以 小程序内webview(自定义H5):不可以 小程序客服消息长按识别:可以 [图片] 个人赞赏码 公众号内长按识别结果:可以 小程序内长按识别结果:不可以 小程序内webview(公众号文章):不可以 小程序内webview(自定义H5):不可以 小程序客服消息长按识别:可以 官方回复小程序因策略调整不能识别:https://developers.weixin.qq.com/community/develop/doc/0008ea7edb8f4845c39be413456c00?highLine=%25E8%25B5%259E%25E8%25B5%258F%25E7%25A0%2581%25E8%25AF%2586%25E5%2588%25AB [图片] 个人微信号二维码 公众号内长按识别结果:可以 小程序内长按识别结果:不可以 小程序内webview(公众号文章):不可以 小程序内webview(自定义H5):不可以 小程序客服消息长按识别:可以 [图片] 个人收款二维码 公众号内长按识别结果:可以 小程序内长按识别结果:不可以 小程序内webview(公众号文章):不可以 小程序内webview(自定义H5):不可以 小程序客服消息长按识别:可以 [图片] 公众号(订阅号)二维码 公众号内长按识别结果:可以 小程序内长按识别结果:不可以 小程序内webview(公众号文章):可以 小程序内webview(自定义H5):不可以 小程序客服消息长按识别:可以 [图片] 小程序码 公众号内长按识别结果:可以 小程序内长按识别结果:可以 小程序内webview(公众号文章):可以 小程序内webview(自定义H5):可以 小程序客服消息长按识别:可以 [图片] 小商店码 公众号内长按识别结果:可以 小程序内长按识别结果:可以 小程序内webview(公众号文章):可以 小程序内webview(自定义H5):可以 小程序客服消息长按识别:可以 [图片] 企业微信码 公众号内长按识别结果:可以 小程序内长按识别结果:不可以 小程序内webview(公众号文章):不可以 小程序内webview(自定义H5):不可以 小程序客服消息长按识别:可以 [图片] 普通网址二维码 公众号内长按识别结果:可以 小程序内长按识别结果:不可以 小程序内webview(公众号文章):不可以 小程序内webview(自定义H5):不可以 小程序客服消息长按识别:可以 [图片]
2021-05-21 - 微信小程序新能力:URL Scheme,可从短信跳转小程序
最近小程序上线了一个超级流量的新入口:URL Scheme。通过小程序页面的URL Scheme,可以在短信、邮件或微信外部的网页中打开小程序。 那么如何实现呢?官方文档已经写的很清楚啦,这里简单介绍一下。 首先,获取URL Scheme,通过服务端接口可以获取打开小程序任意页面的URL Scheme,支持生成到期失效和永久有效的URL Scheme。 [图片] 然后,通过短信群发平台将获取的URL Scheme + 营销文案发送到用户的手机上。 最后,用户收到短信后,直接点击URL Scheme唤起微信,跳转到对应小程序页面,就是这么简单。 除此之外,还可以通过邮件或外部浏览器打开跳转小程序。 由于部分操作系统仍不支持直接识别URL Scheme,因此直接将Scheme发送给用户可能存在无法打开小程序的情况。 为此,我们可以先准备一个H5页面,再从H5页面跳转到URL Scheme实现打开小程序。 [代码]location.href = 'weixin://dl/business/?ticket= *TICKET*' [代码] H5的示例代码我已经更新到Github,可以复用起来,基于官方的案例做了些改动,增加PC端打开时生成二维码方便手机扫码使用。 这次新能力的更新将使微信小程序不再局限于微信内部的流量,天花板被掀开啦。 而且短信和邮件营销的触达成本非常低,营销成本的压低也会催生出很多新的流量玩法,我们敬请期待吧。
2021-01-08 - 小程序取消橡皮筋回弹效果解决方案及坑总结
提到ios系统的橡皮筋效果,作为开发者是又爱又恨,有想要这个效果又有不想要的,无奈的是却没有一个简单的开关来设置这个效果是否开启。 最近在开发小程序时也遇到有关于ios橡皮筋回弹的问题,这里分两部分(取消橡皮筋回弹效果和因为这个效果遇到的坑)和大家分享一下。 取消IOS橡皮筋回弹效果的解决方案 1) 页面无滚动区域时,可通过页面json配置文件设置disableScroll:true禁止整个页面滚动,从而取消橡皮筋效果。 [代码]{ "disableScroll":true } [代码] 测试代码:https://github.com/YuniorZen/minicode-debug/tree/master/minicode01/pages/demo1 2) 页面有滚动区域,滚动区域通过view模拟实现,然后在页面json配置文件设置disableScroll:true禁止整个页面滚动,从而取消橡皮筋效果。 [代码]json文件配置 { "disableScroll":true } view元素模拟实现滚动样式 { height: calc(100vh - 120rpx); //高度必须是固定的值 overflow-y: auto; } [代码] 不足之处在于view元素模拟的滚动区域滚动时不够连贯,没有scroll-view那种原生丝滑般的感觉。 测试代码:https://github.com/YuniorZen/minicode-debug/tree/master/minicode01/pages/demo2 3) 页面有滚动区域,滚动区域使用scroll-view,这时通过disableScroll则无法实现,尝试设置一下scroll-view的scroll-y="{{false}}",上拉或下拉时居然不再触发橡皮筋的回弹啦,当然滚动区域也不能滚动。 小脑袋动一动,解决方法有啦! 通过设置一个变量scrollY动态控制滚动区域的滚动从而阻止回弹。 监听bindscrolltoupper\bindscrolltolower当scroll-view区域滚动到顶部或底部时候设置scrollY:false来关闭页面滚动,从而阻止回弹。 监听bindtouchstart\bindtouchmove 当用户反方向滑动的时候设置scrollY:true,再次开启页面滚动。 [代码]wxml滚动区域属性和事件处理,具体实现请点击测试代码链接 <scroll-view scroll-y="{{scrollY}}" class="list" upper-threshold="5" lower-threshold="5" bindscrolltoupper="bindscrolltoupper" bindscrolltolower="bindscrolltolower" bindtouchstart="touchstart" bindtouchmove="touchmove"> <view class="list-item" wx:for="{{list}}" wx:key="{{index}}">{{item}}</view> </scroll-view> [代码] 相对view模拟实现滚动区域,scroll-view滚动更丝滑,不过每次滚动到底部或顶部的时候,再反向滑动时由于再次开启scroll-view滚动会有操作卡顿的感觉,暂时没想到好的解决方法,有解决的大佬希望提供一下想法,一起学习下。 测试代码:https://github.com/YuniorZen/minicode-debug/tree/master/minicode01/pages/demo3 IOS橡皮筋效果遇到的坑 1) 操作左滑删除组件时上下移动,会触发橡皮筋效果导致页面抖动的问题 这个坑的严重程度看设计师的意愿了,反正我们团队目前是需要解决的,方案类似取消橡皮筋解决方案的第三种 在左滑的时候关闭scroll-view的滚动,取消时再次开启滚动 2) 如果页面顶部有置顶的横向滚动区域scroll-view,当页面滚动到底部时继续上拉会导致置顶头部消失,松开回弹后头部又会出现。 坑是社区里的朋友提出来的,我借了个iphone x 一预览,我嚓,还是真是个奇坑! 微信官方回复已复现正在解决中… 不想继续等下去的,暂时解决方法是 监听页面的滚动区域,当滚动到底部时设置顶部横向滚动scroll-view的scroll-x=false来解决。 写在最后 以上便是我在小程序开发中有关于ios橡皮筋回弹效果的分享,示例代码已上传github,可自行下载体验。 https://github.com/YuniorZen/minicode-debug/tree/master/minicode01 目前微信官方虽说已经着手解决(已两年)此类bug,但哪吒说 我命由我不由天,所以还是我们开发者多分享些解决方案自救来的快。 分享方案如有问题还望不吝指出,没有涉及到的坑也欢迎评论提出,一起学习和解决,后续也会基于此篇不断更新总结。
2021-01-14 - 业务域名和第三方文件引用的问题?
现有小程序采用webview模式开发,webview嵌套的是我们的手机网站,里面有引用各种第三方埋点工具的js文件,类似(https://www.google-analytics.com/analytics.js)。这些第三方的js资源文件的域名是否一定要添加到业务域名白名单里。按目前运行看,似乎不添加也能照常工作。 在这个基础上,我进一步问,需要添加业务域名的除了第三方的网页url,像引用的第三方的资源文件js,css,图片,视频,它们的域名是否要设置业务域名。
2020-06-15