个人案例
日语助手
日语初学者的小工具
日语助手扫码体验
猜个动画
看图猜动画
猜个动画扫码体验
- 网站域名(www.lianjiepay.com)已经备案,域名访问还是提示 无法确认该网页的安全性?
[图片]域名已经备案,也已经提交申请恢复,还是这样怎么回事? 这个域名也已经备案 [图片]
2024-07-17 - PHP开发调用msgSecCheck,违规内容也返回无问题?
一开始使用的EasyWechat调用的,errcode=0,后面使用第三方工具直接调用msg_sec_check还是这样提示,参考下图,不知道哪里写错了。 [图片]
2024-07-09 - AI智能体应用发布篇(公众号/小程序)
前言 上一篇《教你 3 分钟搭建 AI 助手(无需编码)》让大家快速搭建了微信云开发的AI智能体Web版和H5版。 如果想在微信生态中快速获取用户,那么公众号和小程序是必须要做的载体,所以这篇主要分享以下 3 点: AI智能体发布到公众号 小程序中集成AI智能体 AI深度合成类目如何申请 步骤 AI智能体发布到公众号 进入云模板 首先我们先进入云模板控制台,在这里再教大家一种快速进入云模版的方式,除了在《教你 3 分钟搭建 AI 助手(无需编码)》中提到的云开发控制台进入的方式之外。 还可以直接在微信开发者工具的代码目录区域右键呼出菜单然后选择「通过云模板或AI配置页面」菜单项。 注:非正式AppId,小游戏,游客态、代开发小程序,不是小程序开发者,看不到该菜单项。 [图片] 授权公众号 从「我的应用」列表进入「AI智能体应用」详情页点击「添加至多个平台」 [图片] 可以选择一个AI智能体进行「配置」支持 3 个平台 微信小程序客服 微信公众号(服务号) 微信公众号(订阅号) [图片] 配置方式非常方便只需要填写AppId即可 [图片] 前往微信公众平台“设置与开发” - “基本配置” - “公众号开发信息”,复制”开发者ID(AppID)”信息 [图片] 获取到AppID填写后点击「下一步」扫码授权即可,授权成功后 未授权 会变为 已授权 状态 [图片] 接下来来看下效果: [图片] 没有认证的公众号需要回复“继续”,已认证公众号无需回复“继续”可直接输出文案 小程序中集成AI智能体 集成应用 回到「添加至多个平台」面板选择「添加至小程序」 [图片] 根据操作指南下载好代码包解压 [图片] 复制到 miniprogram/ 目录下 [图片] 再将下载的 project.config.json 进行替换 [图片] 当以上两步都完成之后可以以下两种方式进行跳转: JS跳转代码 [代码]wx.navigateTo({url: "/$weda_root/packages/mIOXHS1t/pages/chat/index"}); [代码] WXML布局代码 [代码]<navigator url="/$weda_root/packages/mIOXHS1t/pages/chat/index">跳转至智能体</navigator> [代码] 在这里就相当于把整个AI智能体应用集成到小程序中了 [图片] 在这里需要注意,如果要发布小程序上线还需要在小程序管理后台更新域名配置 [图片] 集成API 如果想自定义界面,可以直接集成API即可 回到「AI智能体应用」详情页面切换到「接口展示」 [图片] 可直接复制代码在小程序端进行调用,以查看AI智能体列表接口为例 [代码] wx.cloud.callFunction({ name: 'cloudbase_module', data: { name: 'ai_bot_get_bot_list', data: { filter: { where: { }, }, select: { $master: true, // 常见的配置,返回主表字段 }, }, }, success: (res) => { console.log(res) }, }); [代码] [图片] 每个接口除了有示例代码,还有详细的参数说明: [图片] [图片] AI深度合成类目如何申请 想要上线AI相关的小程序,必须申请深度合成类目,所以这一步至关重要,回到「AI智能体应用」详情页切换到「AI算法备案资料」- 「获取AI算法合作协议」输入小程序主题即可 [图片] 截图证明,在这里需要注意截图一定要露出云模板字样,这样便于类目审核人员区分截图证明来源 [图片] 然后到小程序管理后台添加类目选择【深度合成 - AI问答】选择 2.2 使用第三方技术,上传截图证明即可 [图片] 通过以上方式类目已审核通过 [图片] 总结 本篇主要讲解了AI智能体应用的多平台发布,整体而言从创建到发布非常方便,不管你是公众号运营者还是小程序开发都可以拥有自己AI智能体应用,赶紧去试试吧~
2024-06-28 - 微信小程序分享到朋友圈单页模式适配
微信小程序支持分享到朋友圈,但能力有所限制,为此专门搞了一个单页模式,主要目的是防止滥用于营销、诱导等。 常见问题:1、小程序从朋友圈打开,一片空白 2、没有触发 HTTP 请求 3、页面顶部渲染异常,被挡住 解决方案:问题 1、2,大部分都是配置出了问题。 排查顺序: 1、分享参数正确与否, 2、是否使用了禁用能力相关接口,查看控制台报错 3、调用HTTP接口不能包含用户登陆状态(如 token),兼容访客访问 问题 3:通常这是因为该页面设置自定义[代码]navigationStyle: custom[代码] , 只需要把页面配置调整为 { "singlePage": { "navigationBarFit": "squeezed" } }
2024-06-11 - 很久前注册的微信公众号目前已经完全忘记了, 如何找回或者直接注销?
很久之前注册的微信公众号, 但是现在已经从名称到邮件, 还有ID全都忘记了, 请问如何直接注销? 我已经不准备再用了, 但是只能找到找回公众号的接口. 想从新注册一个公众号却提示个人名下公众号已经满了. 这成死局了. 注册很久的公众号是不是微信能够提供一个直接注销的接口啊? 为什么还非要找回才能注销呢? 目前已经崩溃!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2024-01-30 - Donut 上传应用商店遇到的问题及解决方案
分享我自己碰到的一些上架问题,大家也可以留言补充! 1.安卓端单独微信登入就可以 2.尽量所有《点击事件》都有反馈 3.要提供账号注销的功能 4.软件页面要提供展示入口《隐私协议》/《用户协议》 5.应用宝- icp备案域名 打开后需要有app宣传页面等,页面最好不要带登入入口 6.聊天、社区等需要提供安全报告下面有案例 7.ios端如果不使用苹果支付,ios登入等,在标识符里面不要勾选,描述文件里面也不要有。会被驳回! 8.有wx.openLocation功能的,这个功能暂时不能用,用wx.getLocation被华为驳回了 9.如果APP中未使用微信支付,可在开发者工具project.miniapp.json中勾选不代支付能力的opensdk。 [图片] 一、软件版权 软件版权 1.《计算机软件著作权登记证书》当前最快申请速度为20-30个工作日,不包含材料整理时间; 2.《电子版权认证证书》和《软件著作权认证证书》最快申请速度为3个工作日,最慢申请时间10-15个工作日,在时效方面具有非常大的优势。 [流泪/]花了6个月注册了软著,忘记写简称了,又花了15天办了软件著作权认证证书 其实来说《软件著作权认证证书》就可以上架绝大部分应用商店了,白交了一次学费,并浪费了时间! 软著找第三方申请tb pdd等,不要自己傻傻的申请,要不然很多地方改正驳回 二、ICP备案 备案查询后截图,打印盖公章!!! 感觉是随缘审核,有的时候需要盖公章,有的时候不需要。 三、UI问题 尽量做到UI自适应,UI设计尽量自己设计, 如果UI与其他软件页面一致会有驳回的风险。 四、安全评估报告 登录全国互联网安全服务管理平台(http://www.beian.gov.cn ),请选择主页评估报告登录 按照我这个填即可 服务名称 功能名称 ..... 评估情形:具有舆论属性或社会动员能力的信息服务上线,或者信息服务增设相关功能; 评估方法:自评估 1、安全管理负责人、信息审核人员及安全管理机构设立情况。 安全管理负责人:XXX 审核人员:XXX 2、用户真实身份核验及注册信息留存措施。 建立台账、专人记录留存。 3、对用户账号、操作时间、操作类型、网络源地址和目标地址、网络源端口、客户端硬件特征等日志信息,以及用户发布信息记录的留存措施。 建立台账,专人记录留存备案。 4、对用户账号和通讯群组名称、昵称、简介、备注、标识,信息发布、转发、评论和通讯群组等服务功能中违法有害信息的防范处置和有关记录保存措施。 设专人进行扫描、查找,及时处理,并进行纪律备案。 5、个人信息保护以及防范违法有害信息传播扩散、社会动员功能失控风险的技术措施。 定期组织人员培训,宣传个人信息保护知识,严防社会动员功能失控。 6、建立投诉、举报制度,公布投诉、举报方式等信息,及时受理并处理有关投诉和举报的情况。 在网络的显著位置设置投诉电话,并安排专人接听电话,受理并及时处理各类投诉和举报情况。 7、建立为监管部门和执法部门依法履职提供技术、数据支持和协助的工作机制的情况。 安排专人专责,为监管部门和执法部门依法履职提供技术、数据支持和协助 填完后,会让你打印一份PDF上传,然后等待wang警上门核查,等待通过即可! 上传后,没人审核怎么办?联系当地网络部门催审, 我催审后,第二天就上门解决了。 五、隐私协议 网上复制的只能找那些通用型模板, 软件权限说明,尽量在隐私协议上补充清楚。 开启了推送消息需要在《隐私协议说明》并在软件设置里面设置一个《个性化推荐》开关 有获取用户信息,并推荐给其他人 需要在《隐私协议说明》并在软件设置里面设置一个《把我推荐给可能认识的人》开关 三方SDK列表 为保障相关功能的实现与应用安全稳定的运行,我们可能会接入由第三方提供的软件开发包(SDK)实现相关目的。 我们会对合作方获取信息的软件工具开发包(SDK)进行严格的安全监测,以保护数据安全。 我们对接入的相关第三方SDK在目录中列明。 请注意,第三方SDK可能因为其版本升级、策略调整等原因导致数据处理类型存在一定变化,请以其公示的官方说明为准。 综合运行类 第三方SDK名称:微信 SDK 链接:https://developers.weixin.qq.com/doc/oplatform/Mobile_App/Access_Guide/Android.html/ 收集信息类型:设备标识信息、软件安装列表 使用目的:接入微信开放平台,让你的移动应用支持微信分享、微信收藏和微信支付。 第三方SDK名称:wmpf_demo_external 链接:https://github.com/wmpf/wmpf_demo_external 收集信息类型:设备标识信息、软件安装列表 使用目的:该运行环境能让硬件在脱离微信客户端的情况下运行微信小程序 祝大家上架顺利!!! 先写这么多吧,想到了在补充。
2023-07-11 - Donut ios企业证申请流程及打包过程
企业注册申请苹果证书及打包过程流程 一、注册账号 1.申请ios企业证书首先是需要注册苹果账号,邮箱注册 2.苹果注册地址:https://appleid.apple.com/account 二、苹果开发者账户申请 1.苹果开发者地址:https://developer.apple.com 2.手机或者mac下载应用:Apple Developer App 3.查询是否存在邓白氏D-U-N-S编码 查询地址:https://developer.apple.com/enroll/duns-lookup/#!/search 4.输入你的企业详细信息全部以英文字符 5.查询不存在后,下一步提交注册D-U-N-S编码,全部以英文字符 6.申请D-U-N-S编码大概需要3-7天左右 [图片] 7.Apple Developer App登入-立即注册填写的信息要与你申请的信息一致,最后填入D-U-N-Sb编码,最后付费 [图片][图片] 三、苹果开发者证书申请 主要是证书、标识符、描述文件 [图片] 1.证书申请 ios开发者证书生成(我用的是 Appuploader)去管理https://www.applicationloader.net [图片] 2.标识符 [图片] 下一步======= [图片] 下一步======= [图片] 下一步==== [图片] 开启以下权限: Access WiFi Information Associated Domains Hotspot Wireless Accessory Configuration 可以另外配置苹果登入、苹果支付、消息通知等其他选项 保存后就完成了标识符的申请 [图片] 3.描述文件 [图片] 下一步==== [图片] 下一步==== [图片] 下一步==== [图片] 下一步==== [图片] 现在拥有了p12证书,还有描述文件,就可以去苹果电脑打包ipa了 无苹果电脑 使用VMware虚拟机模拟苹果 mac OS系统最好是13版本以上,具体怎么实现不演示 [图片] 环境安装教程:https://dev.weixin.qq.com/docs/framework/dev/framework/env/mac.html 安装sudo gem install cocoapods 然后输入密码自动隐藏 回车即可 sudo gem install cocoapods 不显示安装流程 sudo gem install cocoapods -V 显示安装流程 双击导入p12证书 可能出现证书无效的情况 删除掉所有证书 [图片] 前往https://developer.apple.com/certificationauthority/AppleWWDRCA.cer 去从新下载一个中级证书. 开发工具去打包ipa 复制证书名称 导入描述文件 [图片] [图片] [图片] 打包完成 有什么地方缺失的地方指正后修改
2023-08-18 - 小程序录音实时波形图实现
[图片] 实现思路:主要使用canvas绘制柱状图,音量大小由微信recorderManager.onFrameRecorded回调的数据通过快速傅里叶转换算法实现转换 <view style="display: flex; position: relative; justify-content: center; width: 100%; background-color: black;"> <canvas id="myCanvas" type="2d" catch:touchstart="onTouchStart" catch:touchmove="onTouchMove" catch:touchend="onTouchEnd" style="width: 100%;height: 220px;"></canvas> <view style="position: absolute; width: 0.5px; height: 220px; background-color: blue;" /> </view>
2023-04-26 - 个人公众号流量主最新的扣税标准是什么?
一个月几百块的流量主,都达不到起征点,怎么能扣一百多的税出去,【累计税前金额】这一项不应该按照单月周期来计算吗,为什么现在时间跨度扩大到2个月了 [图片]
2023-05-05 - 怎么在小程序里面实现点按翻译
首发于公众号 iKeepLearn [图片] #0 English Podcast (原 BBC English Podcast)一直没有怎么维护。最近刚好有时间,就登录后台看看用户反馈。有没有什么值得更新的。其中呼声最高的就是希望加入翻译功能。所以就先实现这一点吧。 #1 确定需求后,就先搜一下其他小程序,看看他们实现的效果。中国日报社和微信研究院联合推出的每日英文电台就刚好有这个功能。试了一下效果不错。所以这个需求点是可实现的。 那怎么实现呢?毕竟小程序里面不像网页和 APP 那样支持长按选择文字并弹出自定义菜单项,官方支持选择文字的就 text 组件。但没有相关的 api 去获取选定的内容? 在搜索了一圈后也没有找到很好的实现,那就只好自己来实现。 #2 思考了一下,只有用常见的支持绑定点击事件的 view 了。思路是先把英文句子按单词分割,然后每一个单词绑定相应的事件。这样就能获取点按的单词了,再调用接口去获取翻译内容。 所以数据结构按这样设计 [图片] 思路确定后,相关编码就很简单了。 wxml文件和wxss文件 [图片] #3 在找翻译接口的时候,有谷歌,必应、百度和有道作为备选。最后思考了一下还是选了微信官方的接口。这样可以避免关键字检测? 本来在微信服务市场找到的英中翻译接口是最适合需求的,因为不需要服务器调用可以直接在小程序客户端里使用。只是按文档接入后提示出错了。只好选择多语言翻译接口。 [图片] #4 最后可以扫码下方的小程序体验点按翻译 [图片]
2022-12-19 - Skyline|小程序吸顶、网格、瀑布流布局都拿下~
在之前的文章中,我们知道了新 scroll-view 可以让小程序的长列表做到丝滑滚动~ 也提到了新 scroll-view 提供了很多新能力 sticky、网格布局、瀑布流布局等,这一篇,我们就来看看这些新能力是怎么使用的~ 新 scroll-view 在原来列表模式(type="list")的基础上,新增了自定义模式(type="custom") 在自定义模式下,新增了以下新组件供开发者调用 list-view:列表布局容器sticky-section / sticky-header:吸顶布局容器grid-view:网格布局容器,可实现网格布局、瀑布流布局等sticky布局sticky 布局即在应用中常见的吸顶布局,与 CSS 中的 position: sticky 实现的效果一致,当组件在屏幕范围内时,会按照正常的布局排列,当组件滚出屏幕范围时,始终会固定在屏幕顶部。 常见的使用场景有:通讯录、账单列表、菜单列表等等。 与 position: sticky 不同的是,position: sticky 很难实现列表滚动需要的交错吸顶效果,而 sticky 组件则可以帮忙开发者轻松实现交错吸顶的效果。 sticky 的使用非常简单: 将 scroll-view 切换到 custom 模式采用 sticky-section 作为 scroll-view 的子元素sticky-header 放置吸顶内容list-view 放置列表内容 {{item.name}} ... 我们来看下采用 sticky 布局做出来的通讯录效果~ [视频] sticky 布局也可以通过给 sticky-section 配置 push-pinned-header 来声明吸顶元素重叠时是否继续上推 像下图输入框和标签列表这种类型,标签列表吸顶时还是希望保留输入框吸顶。 [视频] 网格布局网格布局即将列表切割成格子,每一行的高度固定,常见的视频列表、照片列表等通常都采用网格布局。 在此之前,实现网格布局需要开发者自行实现网格切割,再嵌入到 scroll-view 中。 新 scroll-view 直接提供了 grid-view 组件供开发者使用~ 将 scroll-view 切换到 custom 模式采用 grid-view 类型为 aligned 做为直接子节点grid-view 中直接编写列表 ... 下面是使用网格布局实现的图片列表效果~ [视频] 瀑布流布局瀑布流布局与网格布局类似,不同的是瀑布流布局中每个格子的高度都可以是不一致的,所以在小程序中实现瀑布流布局就比较复杂了。 开发者需要通过计算格子高度,然后再进行瀑布流拼接,当滚动内容过多时还需要处理节点过多导致内存不足等问题。 grid-view 组件直接支持了瀑布流模式供开发者直接使用,grid-view 组件会根据子元素高度自动布局: 将 scroll-view 切换到 custom 模式采用 grid-view 类型为 masonry 做为直接子节点grid-view 中直接编写列表 ... 下面是使用瀑布流布局实现的图片列表效果~ [视频] 想要立即体验?现在通过微信开发者工具导入 代码片段,即可体验新版 scroll-view 组件能力~
2023-08-03 - 小程序scroll-view翻转后 scroll-into-view的替代方案
背景 腾讯云医小程序有医患聊天会话的场景,由于会话场景存在查询历史消息的场景,小程序中按照常规思路加载历史消息时会出现跳动的问题;跳动的原因是由于在’顶部’插入dom,会使得后面的dom被往后面推,然后重新设置scroll-top或者scrol-into-view从而导页面出现跳动;我们尝试采用【 前端开发中聊天场景的体验优化】文章中的方案处理跳动的场景。该文章的核心观点将scroll-view元素通过设置css样式 transform: rotateX(180deg); 进行翻转,这样将历史消对应的dom结构放在尾部,当添加更多的历史消息(dom)时,由于dom是添加在尾部很优雅的绕过了插入历史消息跳动的场景。但是当我们按照这种方式实现后,发现scroll-view元素提供的scroll-into-view属性不好使了。因此有了本文通过计算scrollTop值设置scrollTop来达到相同目的。 复现该问题的小程序代码片段:代码片段 目前已经反馈给官方(官方已确认是内部组件实现暂不支持翻转的场景 基础知识介绍 计算scrollTop涉及到一些web和小程序的基础知识,后面针对这些基础点进行简单介绍 .scroll-into-view 微信小程序提供的scroll-view元素提供了属性 scroll-into-view,该属性的作用是可以将指定dom滚动到scroll-view可见区域内 [图片] 关于boundingClientRect 下图是MDN解释该属性时提供的,从下图中可以看到top/bottom/left/right的值是元素的左上角和右下角相对于视口左上角的水/垂直距离 [图片] 为了更深入理解这些值。给出了一个简易的demo(代码片段),获取实例元素的的boundingClientRect的值后,可以看到这些值是根据元素的border边界进行计算的 [图片] [图片] [图片] 值得注意的是,当元素处于一个滚动区域内部,left/top值是考虑滚动操作的即包含滚动距离的(参考MDN 另外,当我们把容器元素又或者元素自身设置 transform: rotateX/Y(180deg):不会导致top和bottom的值互换(left与right的值互换); 总会有这样的结论,当dom元素的宽度和高度不为0时,top值一定小于bottom值,left值一定小于right值 关于scrollTop 当一个容器的内容的高度大于其容器高度时,overflow不为visible/hidden时,则会出现滚动条。出现滚动条后,内容区域则可以滚动,此时scrollTop的值是容器可视区域的顶部到内容区域顶部的距离,见下面示意图。 [图片] 值得注意的是,滚动条出现在盒模型中的content区域,见下图滚动条不会覆盖padding/border部分。因此上面说到内容区域高度超过容器高度并不严谨,严谨的说法应该是超过容器的content区域的高度。 [图片] 如果此时给容器设置css样式: transform: rotateX(180deg); 即沿垂直方向翻转180度,scrollTop的值会发生变化吗。 下面我们看下实际的对比效果,为了方便查看滚动条的效果,给滚动条轨道(红色部分)以及滑块(黑色部分)添加了背景色,发现整个元素包括滚动条在内一并进行了翻转。 正常情况(左侧),应用翻转css样式(右侧) [图片] [图片] 翻转后的scrollTop值示意图 [图片] 通过计算scrollTop值来模拟scroll-into-view效果(针对scroll-view翻转的场景j) 由于boundingClinetRect的值是包含border边界的,因此当数据项包含padding,border等区域不会影响这里的计算过程,可以认为下面示意图中的数据项部分的边界是border边界; 由于滚动条是出现在content区域,因此容器元素的的border-top/padding-top不为0时,会影响计算流程,因此这里分为两种情况进行介绍: 2.1 假设scroll-view元素的的border-top/padding-top为0 2.2 假设scroll-view元素的的border-top/padding-top不为0 border-top/padding-top为0的情况 为了方便说明计算过程,我定义三种状态,初始态、中间态、最终态 示意图中的区域说明 白色背景的为视口, 绿色背景的是容器(scroll-view)的可视区域, 灰色区域是内容区域,并且内容区域的高度超过了容器的高度, 红色区域是一个数据项 [图片] 现在的目标是将数据项从初始态滚动到最终态即scroll-into-view的效果:border的上边界与可视区域上边界对齐 第一步:从初始态达到中间态 根据上面关于scrollTop的描述,这里如果scrollTop的值是targetDistance即数据项的底部到内容区域的底部的距离,就可以达到中间态,因此现在的目标是求targetDistance 初始状态的已知变量 初始状态下的的scrollTop值:currentScrollTop (由于容器发生翻转,所以scrollTop视觉上指向容器下方) 数据项的boundingClientRect.bottom为 itemBottom 容器的boundingClientRect.bottom为 contianerBottom 通过示意图很容易得出 [代码]targetDistance = currentScrollTop + (containerBottom - itemBottom) [代码] 第二步:从中间到达最终态 已知变量:容器高度:containerHeight、数据项高度:itemHeight 最终态是数据项的顶部距离容器顶部,从示意图中看到中间态到最终态的scrollTop是减少了的,减少的值其实就是cotainerHeight - itemHeight 经过第一步和第二步我们就可以得到scrollTop的计算公式 [代码]let itemScrollTop = currentScrollTop + containerBottom - itemBottom itemScrollTop -= (containerHeight - itemHeight) => itemScrollTop = currentScrollTop + containerBottom - itemBottom - (containerHeight - itemHeight) [代码] border-top/padding-top不为0的情况 [图片] 根据上面第一种情况的介绍的思路,很容易得到下面结果,不再赘述(X 就是容器padding-top + border-top的值) [代码]let itemScrollTop = currentScrollTop + containerBottom - itemBottom - X itemScrollTop -= (containerHeight - itemHeight - X) => itemScrollTop = currentScrollTop + containerBottom - itemBottom - X - (containerHeight - itemHeight - X) => itemScrollTop = currentScrollTop + containerBottom - itemBottom - (containerHeight - itemHeight) [代码] 【结论】两种情况最终的计算过程是一样的,因此在实现的过程中不需要进行区分 代码实现 代码片段见:https://developers.weixin.qq.com/s/y1X11dmr7AqC 视图层代码 [代码]{{item.content}} #scroll-view { position: absolute; top: 50px; bottom: 50px; width: 100%; background-color: rgba(0, 0, 0, 0.1); // 关键case transform: rotateX(180deg); } [代码] 逻辑层核心代码 [代码]scrollTo () { const itemId = '#item_id_50' const containerId = '#scroll-view' Promise.all([this._queryBoundingClient(itemId), this._getScrollInfo(containerId)]) .then((res = [[[{}]], {}]) => { const [[[ { bottom: itemBottom, height: itemHeight }]], { bottom: containerBottom, scrollTop, height: containerHeight }] = res let itemScrollTop = containerBottom - itemBottom + scrollTop itemScrollTop -= (containerHeight - itemHeight) this.setData({ scrollTop: itemScrollTop }) }) }, _queryBoundingClient (selector) { // 获取目标dom的相关位置/尺寸信息 return new Promise(resolve => { const query = this.createSelectorQuery(); query.selectAll(selector).boundingClientRect(); query.exec(resolve); }) }, _getScrollInfo (idSelector) { // 用来获取容器层相关位置/尺寸信息 return new Promise(resolve => { const query = this.createSelectorQuery() query.select(idSelector).boundingClientRect() query.select(idSelector).scrollOffset() query.exec((res = [{}, {}]) => { const [{ top, bottom, height }, { scrollHeight, scrollTop }] = res const scrollInfo = { scrollTop, scrollHeight, top, bottom, height } resolve(scrollInfo) }) }) } [代码]
2023-03-23 - 如何批量下载云开发存储文件到本地
有人说打开云开发,存储点击文件有下载地址,这对于少量资源是可以的,下面的方法是下载上万文件的方法: 通过访问官方:https://docs.cloudbase.net/cli-v1/install [图片] [图片] 第四步、云存储文件路径:/qrcode/20220311 ==》需要下载到本地:如 E:\qrcode 1、首先在本地: E:\qrcode\文件内创建一个名为:cloudbaserc.json 的json文件。 { "envId":"你的云开发环境的id" } 2、通过命令访问E盘: e: 3、访问需要下载到本地文件路径 cd qrcode 4、开始下载云端文件到本地,执行命令,对于云端文件路径有子目录可以通过 / 进行访问。 tcb storage download qrcode/20220311 . --dir 5、等等文件下载中,直至文件全部下载。
2022-03-11 - 考研刷题小程序云开发实战-页面设计与制作(题库首页、排名页、我的)
前言为啥你的UI界面感觉乱?对于小程序开发者来说,特别是对于初阶开发者或者初学者,排版的好坏是这个阶段核心要考虑的问题,也就是细节。但是不少同学总是在这个上面很不注重,总想着能用就行。做出来的界面异常难看,谈何用户体验! 产品好不好看,真的重要吗?你自己仔细思考思考一下。 唯有美观无法构建一款产品,但是打造一个毫无美感可言的产品往往会让情况变得更加糟糕。所以,我设计并制作了这款精美优质的考研题库小程序。 1、创建并配置页面1.1、在pages文件夹中,分别创建三个文件夹home、rank、my,分别对应三个页面题库首页、排行榜页、我的页; 1.2、每个文件夹分别包含这四个文件.js、.json、.wxml、.wxss [图片] 1.3在app.json中配置pages和tabBar,代码如下: { "pages": [ "pages/home/home", "pages/rank/rank", "pages/my/my" ], "tabBar": { "color": "#aaa", "selectedColor": "#ffa517", "borderStyle": "black", "backgroundColor": "#ffffff", "list": [ { "pagePath": "pages/home/home", "iconPath": "/image/sy2.png", "selectedIconPath": "/image/sy2-a.png", "text": "题库" }, { "pagePath": "pages/rank/rank", "iconPath": "/image/zxly2.png", "selectedIconPath": "/image/zxly2-a.png", "text": "排名" }, { "pagePath": "pages/my/my", "iconPath": "/image/wd2.png", "selectedIconPath": "/image/wd2-a.png", "text": "我的" } ] }, "window": { "backgroundTextStyle": "light", "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "考研刷题小博士", "navigationBarTextStyle": "black" } } [图片] 2、题库首页2.1、场景是往往会有考研相关资讯或者答题优惠兑换活动,需要有丰富的轮播广告作为展示。使用了swiper组件实现轮播图效果,里面使用了image标签展示图片,并设置mode='aspectFill'达到宽度100%满屏效果,代码如下: <swiper class="screen-swiper" autoplay="true" interval="5000" duration="500"> <swiper-item> <image src="/image/b2-y.jpg" mode='aspectFill'></image> </swiper-item> </swiper> 2.2、专项考试或者专项练习,按四个科目分类,我这里使用了样式grid实现基本布局,col-2实现两个一行的排版效果,靓丽抢眼的颜色搭配,外加一些样式进行修饰,整体页面效果呈现为简洁美观,符合个人极简主义的风格。 <view class='grid col-2 padding-left-sm padding-right-sm'> <view class='padding-sm' bindtap="goToAnswer" data-category="马克思原理"> <view class='bg-yellow padding radius shadow-warp'> <view class="text-lg">马克思原理</view> <view class='margin-top-sm text-Abc'>共390题</view> </view> </view> <view class='padding-sm' bindtap="goToAnswer" data-category="毛中特"> <view class='bg-orange padding radius shadow-warp'> <view class="text-lg">毛中特</view> <view class='margin-top-sm text-Abc'>共210题</view> </view> </view> <view class='padding-sm' bindtap="goToAnswer" data-category="思修"> <view class='bg-olive padding radius shadow-warp'> <view class="text-lg">思修</view> <view class='margin-top-sm text-Abc'>共260题</view> </view> </view> <view class='padding-sm' bindtap="goToAnswer" data-category="近代史"> <view class='bg-orange padding radius shadow-warp'> <view class="text-lg">近代史</view> <view class='margin-top-sm text-Abc'>共230题</view> </view> </view> </view> 3、排名页和我的3.1、排名页排版布局演示(源码见仓库) [图片] 3.2、我的页排版布局演示(源码见仓库) [图片] 总结这期的考研刷题小程序云开发实战,主要演示了整个页面的开发流程与配置,并对关键的地方进行了讲解,细枝末节可以详细看看代码即可,其实并不难。难就难在创意、设计与实现等一系列。价值区别在于,能看与好看、能用与好用。
2022-02-18 - 新版开发者工具设置文件忽略无依赖白名单无效?
开发者工具版本: Stable 1.05.2201240 开发环境:uni-app 电脑环境:window 10 64位 问题描述: 新版中默认启用了 “无依赖文件过滤能力” [图片] 由于使用到了 “导出到插件”的功能,该JS文件并没有在页面中引用,会被忽略掉 [图片] 将“上传时过滤无依赖文件”去掉勾选 [图片] [图片] 开发工具中,没有问题,但在真机中,提示文件找不到,Android和iOS都是如此 即使设置忽略白名单也是无效 [图片] [图片] 更坑的是,开发工具回退到不能再回退,依然是如此 最后实在没办法,使用了半年前的旧版本 Stable 1.05.2107090 才正常
2022-02-15 - 云函数设置TZ 为 Asia/Shanghai无效的解决方案(云函数时区问题)
[图片] 官方文档表明Node10以及Node15+版本可用环境变量:TZ 为 Asia/Shanghai,方式获取北京时间。其他Node版本需要借助第三方包,现给出第三方包方案。 云函数: //1.安装 moment-timezone npm install moment-timezone //2.编写云函数 const cloud = require('wx-server-sdk') const moment = require("moment-timezone") exports.main = async (event, context) => { let formatTime=moment().tz("Asia/Shanghai").format()//北京时间 2022-01-24T14:14:50+08:00 let hour=moment().tz("Asia/Shanghai").get('hour') //获取北京时间小时数 let minute=moment().tz("Asia/Shanghai").get('minute') //获取北京时间分数 let second=moment().tz("Asia/Shanghai").get('second') //获取北京时间秒数 return formatTime //result:{} 小程序中以result为载体 } //构建完毕重新部署上传云函数 js: //调用云函数 wx.cloud.callFunction({ name: "云函数名称", }).then(res => { //res 是云函数调用成功后return出来的值 console.log('云函数调用', res) }).catch(res => { console.log(res) })
2022-01-24 - 前端架构之路:小程序 Log 日志
前言 后续我会在 [代码]github[代码] 开放源码,并打包至 [代码]npm[代码] ,开发者后续可自行 [代码]install[代码] 调用。 后续 源码地址 及 npm安装方法 将会在该页面更新。 开放时间基于大家需求而定。 通常情况下,日志系统是开发中重要的一环。 但出于种种原因,在前端开发中做日志打印和上报系统却不常见。 但有些特定情况下,日志系统往往有奇效。 比如一个聊天系统中遇到了以下问题: 语音通话中,用户听不到声音 即时通讯中,部分场景用户反馈,消息发送不出去 即时通讯中, A 回复 B 消息时,偶尔对话框不显示 即时通讯中, A 给 B 连续发送两条消息后, B 接收不到第二条的提示 即时通讯中,发送语音消息发送时,用户以为语音已经发送,但实际上录音还在继续。这时用户以为是网络卡了,最后发现自己和其他人说话的声音被录制进去 但是以上几种错误,在后台接口中并没有体现。再加上部分用户手机型号的问题,导致问题很难被定位。 如果我们这里有 [代码]log[代码] ,我们就能很快定位到出问题的代码。 如果不是代码问题,也更有底气回复用户不是我们系统的问题。 如何使用小程序 Log 日志系统 小程序侧提供了两种小程序 Log 日志接口: LogManager ( 普通日志 ) RealtimeLogManager ( 实时日志 ) 官方并没有介绍两者的具体区别,只是强调了 Realtime 的实时性质。 在我看来他们的最大区别就是: [代码]LogManager[代码] 可以让用户有种心安的感觉,因为 [代码]LogManager[代码] 是用户手动反馈的问题。 [代码]RealtimeLogManager[代码] 则对开发者更友好,可以在用户不知情的情况下收集到问题信息,并在用户无感的情况下对问题进行修复。 LogManager 小程序提供的 [代码]Log[代码] 日志接口,通过 [代码]wx.getLogManager()[代码] 获取实例。 注意: 最多保存5M的日志内容,超过5M后,旧的日志内容会被删除。 对于 小程序 ,用户可以通过使用 [代码]button[代码] 组件的 [代码]open-type="feedback"[代码] 来上传打印的日志。 对于 小游戏 ,用户可以通过使用 [代码]wx.createFeedbackButton[代码] 来创建上传打印的日志的按钮。 开发者可以通过小程序管理后台左侧菜单 反馈管理 页面查看相关打印日志。 创建 LogManager 实例 你可以通过 [代码]wx.getLogManager()[代码] 获取日志实例。 括号中可以传参 [代码]{ level: 0 | 1 }[代码] 来决定是否写入 [代码]Page[代码] 的生命周期函数, [代码]wx[代码] 命名空间下的函数日志。 0: 写入 1: 不写入 [代码]const logger = wx.getLogManager({ level: 0 }) [代码] 使用 LogManager 实例 [代码]const logger = wx.getLogManager({ level: 0 }) logger.log({str: 'hello world'}, 'basic log', 100, [1, 2, 3]) logger.info({str: 'hello world'}, 'info log', 100, [1, 2, 3]) logger.debug({str: 'hello world'}, 'debug log', 100, [1, 2, 3]) logger.warn({str: 'hello world'}, 'warn log', 100, [1, 2, 3]) [代码] 用户反馈上传 LogManager 记录的日志 当日志记录后, 用户可以在小程序的 [代码]profile[代码] 页面,单击 反馈与投诉 ,在点击 功能异常 进行日志上传。 开发者处理用户反馈及和用户沟通 开发者可以在小程序后台 管理 -> 用户反馈 -> 功能异常 查看用户反馈的信息。 开发者可以在 功能 -> 客服 下绑定客服微信,绑定后可以在 48小时 内通过微信和反馈用户沟通。 注:沟通需要用户反馈时勾选:允许开发者在 48 小时内通过客服消息联系我。 RealtimeLogManager 小程序提供的 [代码]实时Log[代码] 日志接口,通过 [代码]wx.getRealtimeLogManager()[代码] 获取实例。 注意: [代码]wx.getRealtimeLogManager()[代码] 基础库 2.7.1 开始支持 官方给出实时日志每条的容量上限是 [代码]5kb[代码] 官方对每条日志的定义:在一个页面 onShow -> onHide 之间,会聚合成一条日志上报 开发者可从小程序管理后台: 开发 -> 运维中心 -> 实时日志 进入小程序端日志查询页面 为了定位问题方便,日志是按页面划分的,某一个页面,在onShow到onHide(切换到其它页面、右上角圆点退到后台)之间打的日志,会聚合成一条日志上报,并且在小程序管理后台上可以根据页面路径搜索出该条日志 创建 RealtimeLogManager 实例 你可以通过 [代码]wx.getRealtimeLogManager()[代码] 获取实时日志实例。 [代码]const logger = wx.getRealtimeLogManager() [代码] 使用 RealtimeLogManager 实例 [代码]const logger = wx.getRealtimeLogManager() logger.debug({str: 'hello world'}, 'debug log', 100, [1, 2, 3]) logger.info({str: 'hello world'}, 'info log', 100, [1, 2, 3]) logger.error({str: 'hello world'}, 'error log', 100, [1, 2, 3]) logger.warn({str: 'hello world'}, 'warn log', 100, [1, 2, 3]) [代码] 查看实时日志 与普通日志不同的是,实时日志不再需要用户反馈,可以直接通过以下方式查看实例。 登录小程序后台 通过路径 开发 -> 开发管理 -> 运维中心 -> 实时日志 查看实时日志 如何搭建小程序 Log 日志系统 上面我们知道了小程序的 [代码]Log[代码] 日志怎么使用,我们当然可以不进行封装直接使用。 但是我们直接使用起来会感觉到十分的别扭,因为这不符合我们程序员单点调用的习惯。 那么接下来让我们对这套 Log 系统进行初步的封装以及全局的方法的日志注入。 后续我会在 github 开放源码,并打包至 npm ,需要的开发者可自行 install 调用。 封装小程序 Log 方法 封装 Log 方法前,我们需要整理该方法需要考虑什么内容: 打印格式:统一打印格式有助于我们更快的定位问题 版本号:方便我们清晰的知道当前用户使用的小程序版本,避免出现旧版本问题在新代码中找不到问题 兼容性:我们需要考虑用户小程序版本不足以支持 [代码]getLogManager[代码] 、 [代码]getRealtimeLogManager[代码] 的情况 类型:我们需要兼容 [代码]debug[代码] 、 [代码]log[代码] 、 [代码]error[代码] 类型的 [代码]log日志[代码] 版本问题 我们需要一个常量用以定义版本号,以便于我们定位出问题的代码版本。 如果遇到版本问题,我们可以更好的引导用户 [代码]const VERSION = "1.0.0" const logger = wx.getLogManager({ level: 0 }) logger.log(VERSION, info) [代码] 打印格式 我们可以通过 [代码][version] file | content[代码] 的统一格式来更快的定位内容。 [代码]const VERSION = "1.0.0" const logger = wx.getLogManager({ level: 0 }) logger.log(`[${VERSION}] ${file} | `, ...args) [代码] 兼容性 我们需要考虑用户小程序版本不足以支持 [代码]getLogManager[代码] 、 [代码]getRealtimeLogManager[代码] 的情况 [代码]const VERSION = "0.0.18"; const canIUseLogManage = wx.canIUse("getLogManager"); const logger = canIUseLogManage ? wx.getLogManager({ level: 0 }) : null; const realtimeLogger = wx.getRealtimeLogManager ? wx.getRealtimeLogManager() : null; export function RUN(file, ...args) { console.log(`[${VERSION}]`, file, " | ", ...args); if (canIUseLogManage) { logger.log(`[${VERSION}]`, file, " | ", ...args); } realtimeLogger && realtimeLogger.info(`[${VERSION}]`, file, " | ", ...args); } [代码] 类型 我们需要兼容 [代码]debug[代码] 、 [代码]log[代码] 、 [代码]error[代码] 类型的 [代码]log日志[代码] [代码]export function RUN(file, ...args) { ... } export function DEBUG(file, ...args) { ... } export function ERROR(file, ...args) { ... } export function getLogger(fileName) { return { DEBUG: function (...args) { DEBUG(fileName, ...args) }, RUN: function (...args) { RUN(fileName, ...args) }, ERROR: function (...args) { ERROR(fileName, ...args) } } } [代码] 完整代码 以上都做到了,就完成了一套 [代码]Log[代码] 系统的基本封装。 [代码]const VERSION = "0.0.18"; const canIUseLogManage = wx.canIUse("getLogManager"); const logger = canIUseLogManage ? wx.getLogManager({ level: 0 }) : null; const realtimeLogger = wx.getRealtimeLogManager ? wx.getRealtimeLogManager() : null; export function DEBUG(file, ...args) { console.debug(`[${VERSION}] ${file} | `, ...args); if (canIUseLogManage) { logger.debug(`[${VERSION}]`, file, " | ", ...args); } realtimeLogger && realtimeLogger.info(`[${VERSION}]`, file, " | ", ...args); } export function RUN(file, ...args) { console.log(`[${VERSION}]`, file, " | ", ...args); if (canIUseLogManage) { logger.log(`[${VERSION}]`, file, " | ", ...args); } realtimeLogger && realtimeLogger.info(`[${VERSION}]`, file, " | ", ...args); } export function ERROR(file, ...args) { console.error(`[${VERSION}]`, file, " | ", ...args); if (canIUseLogManage) { logger.error(`[${VERSION}]`, file, " | ", ...args); } realtimeLogger && realtimeLogger.error(`[${VERSION}]`, file, " | ", ...args); } export function getLogger(fileName) { return { DEBUG: function (...args) { DEBUG(fileName, ...args) }, RUN: function (...args) { RUN(fileName, ...args) }, ERROR: function (...args) { ERROR(fileName, ...args) } } } [代码] 全局注入 Log 通过该章节的名称,我们就可以知道全局注入。 全局注入的意思就是,不通过手动调用的形式,在方法写完后自动注入 [代码]log[代码] ,你只需要在更细节的地方考虑打印 [代码]log[代码] 即可。 为什么要全局注入 虽然我们实现了全局 [代码]log[代码] 的封装,但是很多情况下,一些新同学没有好的打 [代码]log[代码] 的习惯,尤其是前端同学(我也一样)。 所以我们需要做一个全局注入,以方便我们的代码书写,也避免掉手动打 [代码]log[代码] 会出现遗漏的问题。 如何进行全局注入 小程序提供了 [代码]behaviors[代码] 参数,用以让多个页面拥有相同的数据字段和方法。 需要注意的是, [代码]page[代码] 级别的 [代码]behaviors[代码] 在 2.9.2 之后开始支持 我们可以通过封装一个通用的 [代码]behaviors[代码] ,然后在需要 [代码]log[代码] 的页面进行引入即可。 [代码]import * as Log from "./log-test"; export default Behavior({ definitionFilter(defFields) { console.log(defFields); Object.keys(defFields.methods || {}).forEach(methodName => { const originMethod = defFields.methods[methodName]; defFields.methods[methodName] = function (ev, ...args) { if (ev && ev.target && ev.currentTarget && ev.currentTarget.dataset) { Log.RUN(defFields.data.PAGE_NAME, `${methodName} invoke, event dataset = `, ev.currentTarget.dataset, "params = ", ...args); } else { Log.RUN(defFields.data.PAGE_NAME, `${methodName} invoke, params = `, ev, ...args); } originMethod.call(this, ev, ...args) } }) } }) [代码] 总结 连着开发带整理,林林总总的也有了 [代码]2000+[代码] 字,耗费了三天的时间,整体感觉还是比较值得的,希望可以带给大家一些帮助。 也希望大家更重视前端的 [代码]log[代码] 一点。这基于我自身的感觉,尤其是移动端用户。 在很多时候由于 手机型号 、 弱网环境 等导致的问题。 在没有 [代码]log[代码] 时,找不到问题的着力点,导致问题难以被及时解决。
2022-01-17 - 论公众号搜一搜机制
一.搜一搜在哪里? 首先,我们打开微信在聊天页面上面即可进入搜一搜。 '搜一搜'是帮助用户快速查找内容或服务的工具。众所周知搜索项目包含朋友圈、文章、公众号、外部网页、小说和表情等;当然本身的公众号 文章 小程序会展示到前面,因为是自家产品,这个入口不只是应用内搜索,最后可能会成为整个移动互联网的入口,有网友说,这就像在微信植入了百度,现在的微信用户多少亿,这块的流量肯定要抓住!对做这块的玩家来说,如何抓住流量就是学问了 二.排名的影响因素 1.关键词的匹配程度 一般来说匹配度越贴和排名就越高,所以你的名称最好要包含关键词甚至就是关键词(亲身体会,有个好名称涨粉的速度胜过精心运营) 2.微信认证 这是平台本身就有的功能,氪金总比空手扒拉好 3.粉丝活跃 阅读量和阅读率的高低 不仅仅是粉丝数,粉丝活跃度、阅读量和阅读率的高低也会影响到权重高低,所以不但要增加粉丝数,还要提高公众号的质量,多创作质量高的文章,多和粉丝互动,这些数据也往往反应了公众号的质量,微信明显要扶持高质量公众号。 4.粉丝互动 微信本身就是社交软件,肯定要鼓励社交属性,粉丝不活跃证明你账号不够优质,看能否用手段来增加和粉丝之间的互动 5.注册时间 这个具体就不用细说了,其他平台甚至域名年限都有权限,多少有些影响 6.粉丝增长量 粉丝增长越快权重越高,可能很多人觉得粉丝到了就行,其实这个过程也是个重要的影响因素,不过这项权重在整个排名里影响可能不是很大 7.功能介绍 要含有关键词,能和名称 文章内容匹配上。用户搜索时也会搜索到,虽然影响效果比较小,但如果都是很冷门的词,多少还是会影响些 8.推送频率 公众号本身就是发文推送,如果长期不推送或者推送时间不定会被平台判定僵尸号或者运营不走心,所以一定要制定好内容和时间频率,让平台判断机制认为你是精心运营玩家(优质内容和时间频率)
2022-01-10 - 小程序app.onLaunch与page.onLoad异步问题的最佳实践
场景: 在小程序中大家应该都有这样的场景,在onLaunch里用wx.login静默登录拿到code,再用code去发送请求获取token、用户信息等,整个过程都是异步的,然后我们在业务页面里onLoad去用的时候异步请求还没回来,导致没拿到想要的数据,以往要么监听是否拿到,要么自己封装一套回调,总之都挺麻烦,每个页面都要写一堆无关当前页面的逻辑。 直接上终极解决方案,公司内部已接入两年很稳定: 1.可完美解决异步问题 2.不污染原生生命周期,与onLoad等钩子共存 3.使用方便 4.可灵活定制异步钩子 5.采用监听模式实现,接入无需修改以前相关逻辑 6.支持各种小程序和vue架构 。。。 //为了简洁明了的展示使用场景,以下有部分是伪代码,请勿直接粘贴使用,具体使用代码看Github文档 //app.js //globalData提出来声明 let globalData = { // 是否已拿到token token: '', // 用户信息 userInfo: { userId: '', head: '' } } //注册自定义钩子 import CustomHook from 'spa-custom-hooks'; CustomHook.install({ 'Login':{ name:'Login', watchKey: 'token', onUpdate(token){ //有token则触发此钩子 return !!token; } }, 'User':{ name:'User', watchKey: 'userInfo', onUpdate(user){ //获取到userinfo里的userId则触发此钩子 return !!user.userId; } } }, globalData) // 正常走初始化逻辑 App({ globalData, onLaunch() { //发起异步登录拿token login((token)=>{ this.globalData.token = token //使用token拿用户信息 getUser((user)=>{ this.globalData.user = user }) }) } }) //关键点来了 //Page.js,业务页面使用 Page({ onLoadLogin() { //拿到token啦,可以使用token发起请求了 const token = getApp().globalData.token }, onLoadUser() { //拿到用户信息啦 const userInfo = getApp().globalData.userInfo }, onReadyUser() { //页面初次渲染完毕 && 拿到用户信息,可以把头像渲染在canvas上面啦 const userInfo = getApp().globalData.userInfo // 获取canvas上下文 const ctx = getCanvasContext2d() ctx.drawImage(userInfo.head,0,0,100,100) }, onShowUser() { //页面每次显示 && 拿到用户信息,我要在页面每次显示的时候根据userInfo走不同的逻辑 const userInfo = getApp().globalData.userInfo switch(userInfo.sex){ case 0: // 走女生逻辑 break case 1: // 走男生逻辑 break } } }) 具体文档和Demo见↓ Github:https://github.com/1977474741/spa-custom-hooks 祝大家用的愉快,记得star哦
2023-04-23 - 为什么图片链接可正常访问但image组件加载不出来图片?
因为 image 控件的图片拉取本质上是 web 上的 backgroundImage,很多时候是由于图片不规范(content-type / length / 是否302跳转等 )导致拉取不成功,最终表现为加载不出图片。关于这一块我们在持续优化中
2021-12-17 - 云开发短信跳小程序(自定义开发版)教程
写在前面如果你想要自主开发,但没有云开发相关经验,可以采用演示视频来学习本教程: [视频] 一、能力介绍境内非个人主体的认证的小程序,开通静态网站后,可以免鉴权下发支持跳转到相应小程序的短信。短信中会包含支持在微信内或微信外打开的静态网站链接,用户打开页面后可一键跳转至你的小程序。 这个链接的网页在外部浏览器是通过 URL Scheme 的方式来拉起微信打开主体小程序的。 总之,短信跳转能力的实现分为两个步骤,「配置拉起网页」和「发送短信」。本教程将介绍如何执行操作完成短信跳转小程序的能力。 如果你想要无需写代码就能完成短信跳转小程序的能力,可以参照无代码版教程进行逐步实现。 二、操作指引1、网页创建首先我们需要构建一个基础的网页应用,在任何代码编辑器创建一个 html 文件,在教程这里命名为 index.html 在这个 html 文件中输入如下代码,并根据注释提示更换自己的信息: window.onload = function(){ window.web2weapp.init({ appId: 'wx999999', //替换为自己小程序的AppID gh_ID: 'gh_999999',//替换为自己小程序的原始ID env_ID: 'tcb-env',//替换小程序底下云开发环境ID function: { name:'openMini',//提供UrlScheme服务的云函数名称 data:{} //向这个云函数中传入的自定义参数 }, path: 'pages/index/index.html' //打开小程序时的路径 }) } 以上引入的 web2weapp.js 文件是教程封装的有关拉起微信小程序的极简应用,我们直接引用即可轻松使用。 如果你想进一步学习和修改其中的一些WEB展示信息,可以前往 github 获取源码并做修改。 有关于网页拉起小程序的更多信息可以访问官方文档 如果你只想体验短信跳转功能,在执行完上述文件创建操作后,继续以下步骤。 2、创建服务云函数在上面创建网页的过程中,需要填写一个UrlScheme服务云函数。这个云函数主要用来调用微信服务端能力,获取对应的Scheme信息返回给调用前端。 我们在示例中填写的是 openMini 这个命名的云函数。 我们前往微信开发者工具,定位对应的云开发环境,创建一个云函数,名称叫做 openMini 。 在云函数目录中 index.js 文件替换输入以下代码: const cloud = require('wx-server-sdk') cloud.init() exports.main = async (event, context) => { return cloud.openapi.urlscheme.generate({ jumpWxa: { path: '', // 打开小程序时访问路径,为空则会进入主页 query: '',// 可以使用 event 传入的数据制作特定参数,无需求则为空 }, isExpire: true, //是否到期失效,如果为true需要填写到期时间,默认false expire_time: Math.round(new Date().getTime()/1000) + 3600 //我们设置为当前时间3600秒后,也就是1小时后失效 //无需求可以去掉这两个参数(isExpire,expire_time) }) } 保存代码后,在 index.js 右键,选择增量更新文件即可更新成功。 接下来,我们需要开启云函数的未登录访问权限。进入小程序云开发控制台,转到设置-权限设置,找到下方未登录,选择上几步我们统一操作的那个云开发环境(注意:第一步配置的云开发环境和云函数所在的环境,还有此步操作的环境要一致),勾选打开未登录 [图片] 接下来,前往云函数控制台,点击云函数权限,安全规则最后的修改,在弹出框中按如下配置: [图片] 3、本地测试我们在本地浏览器打开第一步创建的 index.html ;唤出控制台,如果效果如下图则证明成功! 需要注意,此处本地打开需要时HTTP协议,建议使用live server等扩展打开。不要直接在资源管理器打开到浏览器,会有跨域的问题! [图片] 4、上传本地创建好的 index.html 至静态网站托管将本地创建好的 index.html 上传至静态网站托管,在这里静态托管需要是小程序本身的云开发环境里的静态托管。 如果你上传至其他静态托管或者是服务器,你仍然可以使用外部浏览器拉起小程序的能力,但会丧失在微信浏览器用开放标签拉起小程序的功能,也不会享受到云开发短信发送跳转链接的能力。 如果你的目标小程序底下有多个云开发环境,则不需要保证云函数和静态托管在一个环境中,无所谓。 比如你有A、B两个环境,A部署了上述的云函数,但是把 index.html 部署到B的环境静态托管中了,这个是没问题的,符合各项能力要求。只需要保证第一步 index.html 网页中的云开发环境配置是云函数所在环境即可。 部署成功后,你便可以访问静态托管的所在地址了,可以通过手机外部浏览器以及微信内部浏览器测试打开小程序的能力了。 5、短信发送云函数的配置在上面创建 openMini 云函数的环境中再来一个云函数,名字叫 sendsms 。 在此云函数 index.js 中配置如下代码: const cloud = require('wx-server-sdk') cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV, }) exports.main = async (event, context) => { try { const config = { env: event.env, content: event.content ? event.content : '发布了短信跳转小程序的新能力', path: event.path, phoneNumberList: event.number } const result = await cloud.openapi.cloudbase.sendSms(config) return result } catch (err) { return err } } 保存代码后,在 index.js 右键,选择增量更新文件即可更新成功。 6、测试短信发送能力在小程序代码中,在 app.js 初始化云开发后,调用云函数,示例代码如下: App({ onLaunch: function () { wx.cloud.init({ env:"tcb-env", //短信云函数所在环境ID traceUser: true }) wx.cloud.callFunction({ name:'sendsms', data:{ "env": "tcb-env",//网页上传的静态托管的环境ID "path":"/index.html",//上传的网页相对根目录的地址,如果是根目录则为/index.html "number":[ "+8616599997777" //你要发送短信的目标手机,前面需要添加「+86」 ] },success(res){ console.log(res) } }) } }) 重新编译运行后,在控制台中看到如下输出,即为测试成功: [图片] 你会在发送的目标手机中收到短信,因为短信中包含「退订回复T」字段,可能会触发手机的自动拦截机制,需要手动在拦截短信中查看。 需要注意:你可以把短信云函数和URLScheme云函数分别放置在不同云开发环境中,但必须保证所放置的云开发环境属于你操作的小程序 另外,出于防止滥用考虑,短信发送的云调用能力需要真实小程序用户访问才可以生效,你不能使用云端测试、云开发JS-SDK以及其他非wx.cloud调用方式(微信侧WEB-SDK除外),会提示如下错误: [图片] 如果你想在其他处使用此能力,可以使用服务端API来做正常HTTP调用,具体访问官方文档 7、查看短信监控图表进入 云开发控制台 > 运营分析 > 监控图表 > 短信监控,即可查看短信监控曲线图、短信发送记录。 [图片] 三、总结短信跳转小程序核心是静态网站中配置的可跳转网页,外部浏览器通过URL Scheme 来实现的,这个方式不适用于微信浏览器,需要使用开放标签才可以URL Scheme的生成是云调用能力,需要是目标小程序的云开发环境的云函数中使用才可以。并且生成的URL Scheme只能是自己小程序的打开链接,不能是任意小程序(和开放标签的任意不一致)短信发送能力的体验是每个有免费配额的环境首月100条,如有超过额度的需求可前往开发者工具-云开发控制台-对应按量付费环境-资源包-短信资源包,进行购买。如当前资源包无法满足需求也可通过云开发 工单 提交申请[图片]短信发送也是云调用能力,需要真实小程序用户调用才可以正常触发,其他方式均报错返回参数错误,出于防止滥用考虑云函数和网页的放置可以不在同一个环境中,只需要保证所属小程序一致即可。(需要保证对应环境ID都能接通)如果你不需要短信能力,可以忽略最后两个步骤CMS配置渠道投放、数据统计可参考官方文档
2021-04-07 - 未完成微信认证的组织类型小程序怎么注销?
目前小程序组织类型的帐号仅支持有对公账户的注销,用户需要继续完成认证后操作注销。 更多小程序注销相关内容(包含个人类型、组织类型、政府无对公账户类型)可参考:https://kf.qq.com/faq/181226yieaEv181226r6nuMr.html
2019-10-25 - 小程序导航栏出现返回首页按钮
目前返回首页按钮出现的条件为(需同时满足): 1. 使用了默认导航栏样式(非 custom) 2. 不是首页或 tabbar 页面(在 app.json 中定义的) 3. 是页面栈最底层页面 如果是开发者自己手写的 tabbar 导致的问题,需要在页面的 onShow 中调用 wx.hideHomeButton() https://developers.weixin.qq.com/miniprogram/dev/api/ui/navigation-bar/wx.hideHomeButton.html手动隐藏返回首页按钮。
2019-09-27 - 小程序搜索优化指南(SEO)
2019年上半年微信发布了基于小程序页面的搜索,为了让我们更好地发现及理解小程序的页面,结合过去一段时间来我们遇到的各种情况,我们强烈建议各位开发者花一些宝贵的时间认真阅读本文:) 爬虫访问小程序内页面时,会携带特定的 user-agent "mpcrawler" 及场景值:1129 1. 小程序里跳转的页面 (url) 可被直接打开。 小程序页面内的跳转url是我们爬虫发现页面的重要来源,且搜索引擎召回的结果页面 (url) 是必须能直接打开,不依赖上下文状态的。特别的:建议页面所需的参数都包含在url 2. 页面跳转优先采用navigator组件。 小程序提供了两种页面路由方式: a.navigator 组件 b. 路由 API,包括 navigateTo / redirectTo / switchTab / navigateBack / reLaunch 建议使用 navigator 组件,若不得不使用API,可在爬虫访问时屏蔽针对点击设置的时间锁或变量锁。 3.清晰简洁的页面参数。 结构清晰、简洁、参数有含义的 querystring 对抓取以及后续的分析都有很大帮助,但是将 JSON 数据作为参数的方式是比较糟糕的实现。 4. 必要的时候才请求用户进行授权、登录、绑定手机号等。 建议在必须的时候才要求用户授权(比如阅读文章可以匿名,而发表评论需要留名)。 5. 我们不收录 web-view 中的任何内容。 我们暂时做不到这一点,长期来看,我们可能也做不到。 6. 利用 sitemap 配置引导爬虫抓取,同时屏蔽无搜索价值的路径。 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html 7. 设置一个清晰的标题和页面缩略图。 页面标题和缩略图对于我们理解页面和提高曝光转化有重要的作用。 通过wx.setNavigationBarTitle或 自定义转发内容onShareAppMessage对页面的标题和缩略图设置,另外也为 video、audio 组件补齐 poster /poster-for-crawler属性。 8. 使用页面路径推送能力 可极大丰富微信可以收录的内容,进而提高小程序内容的曝光机会。请参考: https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/search/search.submitPages.html
2020-01-14