- 超简单集成:原生小程序使用原子化css框架windicss开发
如果你也喜欢用原子化css,并想在原生小程序里使用的话,那就按下面4个步骤试试。 1) 在小程序目录下新建windi.wxss空文件 2)在app.wxss引入windi.wxss // app.wxss @import 'windi.wxss' 3)全局安装windicss依赖(安装过后,后续无需再次安装) cnpm i -g windicss 4)在小程序目录下执行生成windi内容 windicss '**.wxml' -o windi.wxss -d 然后就可以开始使用 classes 工具类啦。 效果图:[图片] 如果你是使用tailwindcss,建议试试windicss,你会爱上它,如果对你有帮助的话,点赞支持一下。 官网:Windi CSS 是下一代工具优先的 CSS 框架。
2022-01-28 - InnerAudioContext.seek在跳转到指定位置后 currentTime没更新
InnerAudioContext.seek在跳转到指定位置后 currentTime没更新 [图片]
2020-04-24 - 教你怎么监听小程序的返回键
更新:2020年7月28日08:51:11 基础库2.12.0起,可以调用wx.enableAlertBeforeUnload监听原生右上角返回、物理返回以及wx.navigateBack时弹框提示 AIP详情请看: https://developers.weixin.qq.com/miniprogram/dev/api/ui/interaction/wx.enableAlertBeforeUnload.html //======================================== 怎么监听小程序的返回键? 应该有很多人想要监听用户的这个动作吧,但是很遗憾,小程序不会给你这个API的,那是不是就没辙了? 幸好我们还可以自定义导航栏,这样一来我们就可以监听用户的这一动作了。 什么?这你已经知道啦? 那好咱们就不说自定义导航栏的返回监听了,说一下物理返回和左滑?右滑?(不管了,反正是滑)返回上一页怎么监听。 监听物理返回 首先说一下这个监听方法的缺点,虽说是监听,但是还是无法真正意义上的监听并拦截来阻止页面跳转,页面还是会返回上一页,而后重新载入刚刚的页面,如果这不是你想要的,那可以不用往下看了 其次说一下用到什么东西: wx.onAppRoute、wx.showModal 最后是一些主要代码: 重写wx.showModal,主要是加个confirmStay参数和使wx.showModal Promise化 [代码]const { showModal } = wx; Object.defineProperty(wx, 'showModal', { configurable: false, // 是否可以配置 enumerable: false, // 是否可迭代 writable: false, // 是否可重写 value(...param) { return new Promise(function (rs, rj) { let { success, fail, complete, confirmStay } = param[0] param[0].success = (res) => { res.navBack = (res.confirm && !confirmStay) || (res.cancel && confirmStay) wx.setStorageSync('showBackModal', !res.navBack) success && success(res) rs(res) } param[0].fail = (res) => { fail && fail(res) rj(res) } param[0].complete = (res) => { complete && complete(res) (res.confirm || res.cancel) ? rs(res) : rj(res) } return showModal.apply(this, param); // 原样移交函数参数和this }.bind(this)) } }); [代码] 使用wx.onAppRoute实现返回原来的页面 [代码]wx.onAppRoute(function (res) { var a = getApp(), ps = getCurrentPages(), t = ps[ps.length - 1], b = a && a.globalData && a.globalData.pageBeforeBacks || {}, c = a && a.globalData && a.globalData.lastPage || {} if (res.openType == 'navigateBack') { var showBackModal = wx.getStorageSync('showBackModal') if (c.route && showBackModal && typeof b[c.route] == 'function') { wx.navigateTo({ url: '/' + c.route + '?useCache=1', }) b[c.route]().then(res => { if (res.navBack){ a.globalData.pageBeforeBacks = {} wx.navigateBack({ delta: 1 }) } }) } } else if (res.openType == 'navigateTo' || res.openType == 'redirectTo') { if (!a.hasOwnProperty('globalData')) a.globalData = {} if (!a.globalData.hasOwnProperty('lastPage')) a.globalData.lastPage = {} if (!a.globalData.hasOwnProperty('pageBeforeBacks')) a.globalData.pageBeforeBacks = {} if (ps.length >= 2 && t.onBeforeBack && typeof t.onBeforeBack == 'function') { let { onUnload } = t wx.setStorageSync('showBackModal', !0) t.onUnload = function () { a.globalData.lastPage = { route: t.route, data: t.data } onUnload() } } t.onBeforeBack && typeof t.onBeforeBack == 'function' && (a.globalData.pageBeforeBacks[t.route] = t.onBeforeBack) } }) [代码] 改造Page [代码]const myPage = Page Page = function(e){ let { onLoad, onShow, onUnload } = e e.onLoad = (() => { return function (res) { this.app = getApp() this.app.globalData = this.app.globalData || {} let reinit = () => { if (this.app.globalData.lastPage && this.app.globalData.lastPage.route == this.route) { this.app.globalData.lastPage.data && this.setData(this.app.globalData.lastPage.data) Object.assign(this, this.app.globalData.lastPage.syncProps || {}) } } this.useCache = res.useCache res.useCache ? reinit() : (onLoad && onLoad.call(this, res)) } })() e.onShow = (() => { return function (res) { !this.useCache && onShow && onShow.call(this, res) } })() e.onUnload = (() => { return function (res) { this.app.globalData = Object.assign(this.app.globalData || {}, { lastPage: this }) onUnload && onUnload.call(this, res) } })() return myPage.call(this, e) } [代码] 在需要监听的页面加个onBeforeBack方法,方法返回Promise化的wx.showModal [代码]onBeforeBack: function () { return wx.showModal({ title: '提示', content: '信息尚未保存,确定要返回吗?', confirmStay: !1 //结合content意思,点击确定按钮,是否留在原来页面,confirmStay默认false }) } [代码] 运行测试,Oj8K 是不是很简单,马上去试试水吧,效果图就不放了,静态图也看不出效果,动态图懒得弄,想看效果的自己运行代码片段吧 代码片段 https://developers.weixin.qq.com/s/hc2tyrmw79hg
2020-07-28 - 云开发http请求的两种写法
对于简单的GET表单请求 可以直接将参数封装在url中 [代码]// 云函数入口文件 const cloud = require('wx-server-sdk') var request = require('request') // 云函数入口函数 exports.main = async (event, context) => { //qz return new Promise((resolve, reject) => { request({ url: event.URL, method: "POST",//GET json: true, headers: { "content-type": "application/json", "token": event.token }, }, function (error, response, body) { if (!error && response.statusCode == 200) { try { resolve(body) } catch (e) { reject() } } }) }) } [代码] 对于POST请求 参数不好封装的 [代码]// 云函数入口文件 const cloud = require('wx-server-sdk') var request = require('request') cloud.init() // 云函数入口函数 exports.main = async (event, context) => { //这里写普通话成绩查询方式 return new Promise((resolve, reject) => { request({ url: event.url, method: "POST", json: true, headers: { "content-type": "application/json", "token":event.token }, body: event.body }, function (error, response, body) { if (!error && response.statusCode == 200) { try { resolve(body) } catch (e) { reject() } } }) }) } [代码] body中填写需要的参数 body是json形式 [代码]{ xxx:xxx } [代码] 请求头可以根据自己的需要进行修改。
2019-05-28 - 关于云开发新服务“实时数据推送”,你需要了解的全在这了!
“微信小程序工程师邓坤力带你了解如何利用千呼万唤始出来的云开发实时数据推送服务打造生动的小程序和小游戏!” 在数据库在小程序·云开发中的应用一文中,我们了解到实时数据推送作为云开发即将上线的一项新能力,主要指客户端使用官方SDK发起socket连接建立对一个集合的监听,目标集合中如果有符合过滤条件的数据发生变更,将会直接推送到建立监听的客户端。 [图片] 简单来说,使用实时数据推送可以更有效率的拉取数据,帮你把你的应用变成实时有状态,场景会非常有用,比如可以用来做弹幕,做实时排名更新,做实时刷新,或者实时推送一些通知给到用户。 那么,实时数据推送具体是如何为小程序与小游戏赋能,提升开发效率的?让我们跟随微信小程序工程师邓坤力一起,深入了解这项新服务诞生的来龙去脉。 为什么要做实时数据推送? 介绍实时数据推送服务之前,弄懂一个直击灵魂问题将有助于我们的理解,那就是“为什么要做实时数据推送?” 想要更回答这个问题,需要从即时通信服务说起。 [图片] 我们都知道建立一个简单、常规的即时通信服务需要长连作为实现实时性的基础,需要足够的存储来保证消息与文件的持久化,还需要实时推送功能来实现主动同步客户端的能力。在此过程中,开发者往往需要面临: (1)需从零自建完整服务,无法聚焦在原型和核心业务开发上。 (2)开发成本高。由于前后端逻辑复杂,开发者往往需要经历设计基础设施搭建,长连管理、数据库开发、安全管理等琐碎繁杂的步骤。 (3)维护成本高。开发者还需负责维护,完成基础设施管理、异常处理等。 (4)微信能力集成。自建服务器的开发者如要基于微信用户登录态进行操作并让小程序安全运行,就不可避免地需要接入微信鉴权体系,整合accesstoken和 sessionkey流程并保证其安全性。 看到这里,可能有很多读者已经想到了具有开箱即用、集成原生微信能力、自带云数据库、云函数、云存储的云开发,那么云开发的这些优势能否有效解决开发者在建立即时通信服务中常常会遇到的难题呢? 答案是不完全能,由于云开发不支持长连,并且不具备主动同步客户端的能力,因此只能通过短轮询以次级长连和推送的次级替代方案,在即时通讯服务构建时往往需要面临短轮询带来的资源浪费、成本与体验难平衡以及实时性差等问题。 [图片] 可能又有小伙伴要问了,让云开发支持长连不就可以弥补这些缺陷?答案也是否定的,因为若云开发支持长连,整个即时通讯服务的实现仍避免不了对长连的开发和管理,并且需要接受和处理消息,导致流程仍较为复杂,而这恰恰有悖于云开发作为高效率、轻量级解决方案的理念。 由此,云开发的实时推送服务应运而生,它将即时通讯服务所需的能力与云开发独有的优势串联起来,让开发者可以更便捷地使用并快速实现需求。 [图片] 实时数据推送有哪些能力? 能力概述 实时数据推送是云开发数据库新增的服务,通过这项服务,小程序端可实时监听数据库变更,即它支持根据开发者给定的查询语句进行监听,每当查询语句的结果发生变化时,小程序端就会收到包含更新内容的推送,并对实时数据变化做出响应。 总体来说,使用云开发的实时数据推送能力相比起自建服务可以享受以下便利,从而使其更专注于业务逻辑的设计: 原生能力,开箱即用 无需管理长连 无需编写服务端代码 无需搭建和管理基础设施 自动收到更新推送 丰富的应用场景 实时数据推送的应用场景十分丰富。 在即时通信方面,实时数据推送支持小程序直播聊天室、弹幕等以及小游戏的区服聊天、房间聊天、私信等功能的实现。 在状态同步方面,小程序可以使用实时数据推送来保持应用最新状态的同步,以信息流为例,可以支持实时提示有新的文章、评论、点赞,从而达到更好的用户体验;对小游戏来说,可以支持使用状态同步的模型开发的小游戏,比如棋牌类小游戏。 而在实时协作方面,实时数据推送可以为在线共享文档、项目管理协作工具等提供支持。 [图片] 简单易用的API 实时数据推送提供简洁易用的API,调用方便,并且可以完整描述整个维度的数据变化,以便开发者对具体业务逻辑做出响应。 [图片] 自动处理异常 SDK在异常时会尽可能自动恢复状态,并且此恢复为开发者无感知,开发者仅需处理 SDK 无法自动恢复的错误。具体来说: 实时数据推送在断网、网络切换、NAT 地址刷新等情况时均能自动检测异常和恢复连接,并且在更新事件推送失败或丢失时有机制保障会成功拉取,而在更新事件乱序时有机制保障开发者收到的是顺序事件。 [图片] 云开发新能力矩阵 云调用:云函数免鉴权调用微信服务端开放接口,获取微信开放数据,接收微信服务端消息推送。 HTTP API:小程序外访问云开发资源。 数据库聚合:分组查询、统计查询、流水线批处理。 控制台数据库高级查询:控制台中批量数据库增删查改。 云开发Network面板:小程序Network面板支持展示云开发请求。 实时数据推送
2019-08-28 - 云开发实时数据推送制作小游戏匹配玩家功能
下面是功能介绍: 小程序·云开发新增实时数据推送能力,可以实时监听数据库中的数据变更。该功能有效地解决了即时通信以及实时更新和推送数据的问题,极大地降低在此类场景下的开发成本。 基于是实时数据推送能力,在给定查询条件的情况下,每当数据库更新而导致查询条件对应的查询结果发生变更时,小程序可收到一个更新事件,其中可获取更新内容和更新后的查询结果快照。 许多对战类型的小游戏需要一个匹配玩家界面,下面就从制作一个匹配玩家界面入手,简单介绍一下云开发实时数据推送功能。 1.首先打开微信开发者工具里云开发,在数据库中新建一个集合,集合名称:rooms,权限设置:所有用户可读,仅创建者可读写。2.我们用一个两人对战的例子,来介绍如何实现匹配玩家。当玩家进入匹配状态有两个情况,一是当前已经有队列玩家只需进入队列即可,二是当前没有队列玩家要创建队列。这里定义一下创建队列的人叫做newMen,加入队列的人叫做addMen。如何判定当前是否有队列,下面用一段代码说明下: [代码]const db = wx.cloud.database();[代码][代码]const $ = db.command.aggregate;[代码][代码]db.collection([代码][代码]'rooms'[代码][代码])[代码][代码].aggregate()[代码][代码].match({[代码][代码] [代码][代码]people: $.eq(1)[代码][代码]})[代码][代码].sort({[代码][代码] [代码][代码]createTimestamp: -1[代码][代码]})[代码][代码].limit(1)[代码][代码].end().then(res =>{[代码][代码] [代码][代码]console.log([代码][代码]'聚合查询结果rooms'[代码][代码],res.list);[代码][代码] [代码][代码]this[代码][代码].initRoom(res.list);[代码][代码]})[代码]这里用的是聚合查询,对集合rooms进行查询,只要当前people字段值为1就说明已经队列,如果查询不到结果就是没有队列需要创建队列,下面就是initRoom()方法进行判断,代码如下: initRoom(rooms){ [代码] if[代码] [代码](!rooms.length) {[代码] [代码] [代码][代码]this[代码][代码].createEmptyRoom();[代码] [代码] [代码][代码]} [代码][代码]else[代码] [代码]{[代码] [代码] [代码][代码]console.log([代码][代码]'进入队列成功'[代码][代码]);[代码] [代码] [代码][代码]this[代码][代码].nowPlayer = [代码][代码]'addMen'[代码][代码];[代码] [代码] [代码][代码]this[代码][代码].docid = rooms[0]._id;[代码] [代码] [代码][代码]this[代码][代码].roomid = rooms[0].roomid;[代码] [代码] [代码] this.updatePeopleField(); [代码][代码] [代码] [代码][代码]};[代码] } 从上面代码可以看出,如果查询结果为空就要创建队列。不为空就进入队列,然后执行更新字段操作,后面会详细介绍。下面介绍创建队列createEmptyRoom()方法,代码如下: [代码]createEmptyRoom(){[代码][代码] [代码][代码]const db = wx.cloud.database();[代码][代码] [代码][代码]const roomid = Date.now().toString();[代码][代码][代码][代码] let room = {[代码][代码] [代码][代码]roomid,[代码][代码] [代码][代码]createTimestamp: Date.now().toString(),[代码][代码] [代码][代码]people: 1,[代码][代码] [代码][代码]};[代码][代码] [代码][代码]db.collection('rooms').add({ data: room })[代码][代码] [代码][代码].then(res =>{[代码][代码] [代码][代码]this[代码][代码].nowPlayer = [代码][代码]'newMen'[代码][代码];[代码][代码] [代码][代码]this[代码][代码].docid = res._id;[代码][代码] [代码][代码]this[代码][代码].roomid = roomid;[代码][代码] [代码][代码]this[代码][代码].waitJionGame();[代码][代码] [代码][代码]})[代码][代码][代码][代码] [代码][代码]},[代码]这里向集合rooms添加一个新记录,即创建队列,当前玩家即nowPlayer为newMen。创建队列完成后,我们要监听是否有玩家进入队列,就是有没有addMen进来。这里就要用到上面说的云开发实时数据推送功能了,相关代码如下: [代码]waitJionGame(){[代码][代码] [代码][代码]let docid = [代码][代码]this[代码][代码].docid;[代码][代码] console.log('正在匹配对手...');[代码][代码] [代码][代码]const db = wx.cloud.database();[代码][代码] [代码][代码]this[代码][代码].player = db.collection('rooms')[代码][代码] [代码][代码].where({[代码][代码] [代码][代码]_id: docid[代码][代码] [代码][代码]})[代码][代码] [代码][代码].watch({[代码][代码] [代码][代码]onChange: snapshot => {[代码][代码] [代码][代码]const docChange = snapshot.docChanges[0];[代码][代码] [代码][代码]const doc = snapshot.docs[0];[代码][代码] [代码][代码]console.log([代码][代码]'监听玩家进入'[代码][代码], snapshot);[代码][代码] [代码][代码]if[代码] [代码](docChange.dataType === [代码][代码]'update'[代码] [代码]&& doc.people === 2) {[代码][代码] console.log('匹配成功');[代码][代码] [代码][代码]this[代码][代码].player.close();[代码][代码] [代码][代码]}[代码][代码] [代码][代码]},[代码][代码] [代码][代码]onError: error => {[代码][代码] [代码][代码]console.log(error);[代码][代码] [代码][代码]}[代码][代码] [代码][代码]})[代码][代码] [代码][代码]},[代码]通过对刚才创建的记录进行监听,只要dataType === 'update'即记录有更新操作,并且doc.people === 2,就说明有玩家进入即addMen进入队列,此时就可以关闭监听,执行close()。这时队列创建者即newMen,匹配阶段所有工作都完成了。对于加入队列者即addMen还有一个工作,告诉newMen我已经进入队列了,很简单就是把记录里的people字段更新为2。相关代码如下: [代码]updatePeopleField() {[代码] [代码] let docid = this.docid;[代码] [代码] [代码][代码]wx.cloud.callFunction({[代码][代码] [代码][代码]name: [代码][代码]'updateDoc'[代码][代码],[代码][代码] [代码][代码]data: {[代码][代码] [代码][代码]collection: 'rooms',[代码][代码] [代码][代码]docid: docid,[代码][代码] [代码][代码]people: 2,[代码][代码] [代码][代码]}[代码][代码] [代码][代码]}).then(res => {[代码][代码] [代码][代码]console.log([代码][代码]'更新人数成功'[代码][代码],res);[代码][代码] [代码][代码]}).[代码][代码]catch[代码][代码](err => {[代码][代码] [代码][代码]console.log(err);[代码][代码] [代码][代码]})[代码][代码] [代码][代码]},[代码]更新队列创建者newMen创建的记录里的字段是一个越权操作,所以要调用云函数。通过云函数更新完成字段后,addMen所有使命都已经完成了。 这就是整个匹配玩家阶段的流程,相关效果可以参考本人开发的游戏--圣兵棋盘。 [图片] 圣兵棋盘
2019-09-05 - 效能提升100%? 云开发开源「前后端一体化部署工具」CloudBase Framework
背景和介绍 云开发(CloudBase)是云端一体化的云服务平台,采用 serverless 架构,开发者无须关心服务器搭建和管理,只需要编写业务代码和调用原生提供的云能力,就可以快速搭建完整的小程序/小游戏、H5、Web、移动 App 等应用。云开发是国内 Serverless 理念的领先实践,服务了超过 50 万开发者。 在开发者使用云开发的过程中,我们收集到如下场景的反馈和需求: 存量业务如网站、后端服务希望能托管在云开发平台,但存在不小的改造成本 无法覆盖各种开发语言、框架和现有的应用交付方式 应用中存在前后端使用多种云开发资源时,希望能降低发布成本,同时实现持续交付 应用中添加其他云能力需要手动在控制台配置 基于以上的场景,我们希望设计一个工具来解决上述问题,希望具备以下的特性: 支持应用的无缝托管:用户不需要改变开发习惯,不需要修改代码适配云函数等云资源,而是可以直接将应用托管在云开发平台上 引入支持自定义的底层资源层:引入容器化的部署方案来承载各种开发语言、框架和现有的应用交付方式 支持声明式描述云资源:将应用内各个部分最终都能描述成统一的描述语言,支持前后端的统一部署 使用简单:使用者无须关心底层资源和底层声明文件等细节,只需要有限的业务参数,即可将应用一键托管到云开发平台 核心的思想就是希望让开发者使用一体化的方式来开发和部署应用 [图片] CloudBase Framework 是云开发基于上述一体化的思想开发的前后端一体化部署工具,开发者无需改动业务代码,支持前后端一键托管部署在云开发平台,享受加速访问和弹性免运维的优势,具有以下特点: 1. 云开发出品 由云开发推出,核心代码已在 Github 开源 https://github.com/TencentCloudBase/cloudbase-framework (欢迎给我们的项目点个 Star,支持我们做得更好~) [图片] 2. 云原生,一体化 前后端一体化部署在 Serverless 架构的云环境上,弹性可扩展 3. 降低成本 资源按使用自动弹性扩缩容,按照使用计费,极大节约资源成本 4. 高效快速 简单易用,并内置大量强大后端能力,只需要开发业务逻辑即可 亮点 1: 一键部署 CloudBase Framework 的第一个核心亮点是可以实现一键部署,常见的应用,不需要改动业务代码,即可“零配置”部署到云开发上。 [图片] [图片] 例如,图中所示的基于 Vue CLI 工具创建的项目,在执行 CloudBase Framework 的部署命令时,会自动检测项目框架和语言,交互式确认并保存项目配置,实现应用的一键发布。一条命令实现了应用部署,自动配置 COS 对象存储和 DNS、域名等,自带 HTTPS 安全访问、CDN 访问加速等能力。 支持常见框架和语言 [图片] [图片] CloudBase Framework 目前支持了 Vue、React 等前端框架,也支持 Nuxt 等 SSR 框架,基于 Node 开发的应用如 Express、Koa 等也可以一键托管。除此之外,借助底层 Serverless 云应用的能力,也可以部署其他后端的应用(PHP、Java、Go 等),值得一提的是可以部署 Dart Server,可以配合 Flutter 实现 Dart 语言的云端一体化,这也是国内云厂商对 Dart 语言和生态的一大补充。 自动检测框架 在降低用户使用门槛方面,我们实现了自动检测的功能,针对常见前端框架无需编写配置,可以实现自动识别项目的构建和发布默认配置 无需复杂适配 不需要学习复杂的服务器配置和更改代码,只需要输入业务参数即可部署 可配合 CI/CD 可以与您的现有工作流完美配合,可搭配 CI/ CD 工具实现持续部署,例如只需要几行代码就可以实现 Github 自动推送时自动部署应用前后端,同时也可以在 CI/CD 过程中增加手动确认步骤来 Review 发布过程。 [代码] - name: Deploy to CloudBase run: | npm i @cloudbase/cli cloudbase login --apiKeyId ${{secrets.SECRETID}} --apiKey ${{secrets.SECRETKEY}} cloudbase framework:deploy [代码] 亮点 2: 一体化,易扩展 平台一体化 云开发(CloudBase)是云端一体化的云服务平台,采用 serverless 架构,开发者无须关心服务器搭建和管理,原生提供了很多开箱即用的云能力 项目一体化 使用 CloudBase Framework 开发的项目前端、后端等都可以在同一个项目内开发和维护,这一点和小程序开发非常类似,可以在 IDE 内通过一体化的方式开发和发布。 [图片] 前后端一体化部署 如上面的例子所示,一个具备前端代码、云函数和服务端代码的一体化应用,只需要调用 CloudBase Framework 的一条命令,即可将完整应用部署在云端,统一管理和维护。 开箱即用的原生云能力 云开发一体化平台提供了开箱即用的原生的云能力,无需学习底层资源配置,无需运维和管理。 例如,在云开发平台上,我们需要部署静态网站,无须关心对象存储和 CDN 的管理;需要部署 HTTP 服务,无须关心网关层和计算资源的配置;需要使用云数据库时,我们也不用担心数据库实例的容灾。 轻松添加更多后端能力 可轻松引入更多开箱即用的后端能力 登录鉴权:通过 SDK 实现登录鉴权 云数据库:内置的 NoSQL 数据库,可通过声明式的方式来创建集合和索引 云接入:引入 HTTP 访问的支持 云调用:几行代码实现微信开放能力的调用 云函数:轻量级的计算能力 云存储:实现文件的存储和下载 Serverless 云应用:极简方式使用 Kubenetes 容器 扩展能力:可以免开发安装 CMS 内容管理系统等扩展能力 快速开始 安装 CloudBase CLI 首先需要安装 CloudBase 最新版命令行工具 [代码]npm install -g @cloudbase/cli@latest [代码] 登录命令行工具 然后调用命令行进行登录,会跳转到腾讯云控制台进行账号的授权,如果没有账号,可以在控制台进行开通 [代码]cloudbase login [代码] 初始化一个应用 通过 CloudBase 命令行工具我们可以非常方便地创建一个应用,如果在现有应用中使用,可以执行 [代码]cloudbase init --without-template[代码] [代码]cloudbase init [代码] 通过交互式地创建环境和选择模板来初始化应用 [图片] 也可以直接指定模板 id 创建对应的项目,例如 [代码]cloudbase init --template nuxt-ssr [代码] 目前支持的一体化应用模板如下: 名称 应用示例介绍 模板 id Vue 应用 Vue + 云函数 + 静态网站部署 [代码]vue[代码] React 应用 React + 云函数 + 静态网站部署 [代码]react-starter[代码] React 全栈应用 React + 云函数 + 静态网站部署+ 云数据库 [代码]react-demo[代码] Nuxt SPA 应用 Nuxt SPA + 云函数 + 静态网站部署 [代码]nuxt-spa[代码] Nuxt SSR 应用 Nuxt SSR + 服务端部署 + 静态网站部署 [代码]nuxt-ssr[代码] Koa 应用 Koa + 服务端部署 [代码]koa-starter[代码] Express 应用 Express + 服务端部署 [代码]express-starter[代码] Nest 应用 Nest + 服务端部署 [代码]nest-starter[代码] Node.js 云函数示例 Node.js 云函数 [代码]node-starter[代码] PHP 云函数示例 PHP 云函数 [代码]php-starter[代码] Java 云函数示例 Java 云函数 [代码]java-starter[代码] VuePresss 网站应用 VuePresss + 静态网站部署 [代码]vuepress[代码] Node.js 云应用 Node.js + Serverless 云应用部署 [代码]node[代码] Aqueduct (Dart Server) 云应用 Aqueduct (Dart Server) + Serverless 云应用部署 [代码]dart[代码] 部署应用 接下来,只需要进入到项目目录中调用命令进行部署 [代码]cloudbase framework:deploy [代码] [图片] 部署成功后,就可以通过命令行提示的地址进行访问了: https://framework.service.tcloudbase.com/express-starter/ CloudBase Framework 降本增效 CloudBase Framework 通过提供一体化的开发和部署功能,将应用轻松迁移到一体化的云开发平台上来。企业和个人开发者可以借助这套方案,提升业务效率,节省业务成本。 开发更快 集成云开发多端 SDK 开箱即用的后端能力 部署更快 一键部署,声明式创建云资源 自动、快速弹性扩缩容 访问更快 更多节点覆盖 高性能,高可用 云开发平台具备了免运维,全托管,按量付费的特点,通过 CloudBase 部署应用的成本相比传统方式部署应用的成本,节省了运维成本、闲置租用成本以及多角色沟通的成本。 [图片] 例如微信读书团队借助“小程序·云开发”带来了很大的效能提升,微信读书小程序上线 10 个月累计发布 349 次版本,开发效率分别是对应的 APP 和 H5 的 4 倍与 2 倍。 云开发还让其团队的分工和成员能力发生了显著变化。以前其团队按照前端开发、Node.js 开发和运维人员进行分工,现在前端负责全栈开发。 生态和插件 CloudBase Framework 具有开放性的特点,通过微内核、插件化的方式来设计这套方案。内核层面解决插件化、构建生命周期等问题,针对具体的场景则通过插件的方式来实现。 例如,针对不同技术栈的网站的托管,设计了 website 插件来处理这一类问题,可以解决前端页面构建、静态资源的部署以及域名的处理。 开发者也可以根据插件的规范来开发不同的插件发布到 NPM 上,使用时只需要指定其 npm 包名即可。 目前 CloudBase Framework 官方提供的插件有: 插件 最新版本 插件介绍 @cloudbase/framework-plugin-website [图片] 一键部署网站应用 @cloudbase/framework-plugin-node [图片] 一键部署 Node 应用(支持底层部署为函数或者 Serverless 云应用) @cloudbase/framework-plugin-nuxt [图片] 一键部署 Nuxt SSR 应用 @cloudbase/framework-plugin-function [图片] 一键部署函数资源 @cloudbase/framework-plugin-container [图片] 一键部署云应用容器服务 @cloudbase/framework-plugin-dart [图片] 一键部署 Dart 云应用 @cloudbase/framework-plugin-database [图片] 一键声明式部署云开发 NoSQL 云数据库 愿景 CloudBase Framework 致力于打造一体化框架,目前已实现了一体化的部署工具,未来会引入一体化运行时库和一体化 CI/CD 工作流,帮助业务更快更简单地将业务部署在面向未来的云开发平台上,提高效率,节省成本。 一体化思想 一体化平台 一体化部署工具 一体化运行时库:通过运行时框架简化开发流程,以更少的代码实现强大的功能 一体化 CI/CD 工作流:结合代码仓库推送,实现内置的自动化云端构建和部署 [图片] 开源贡献 我们非常欢迎各位开发者为 CloudBase Framework 贡献一份力量,让这个项目能够更好地帮助开发者提升效率。 Github 地址:https://github.com/TencentCloudBase/cloudbase-framework 参与贡献 积极参与 Issue 的讨论,如答疑解惑、提供想法或报告无法解决的错误 撰写和改进项目的文档 提交补丁优化代码 认领待办任务中的事项 目前已有 12 名 Contributors https://github.com/TencentCloudBase/cloudbase-framework#contributors- CloudBase Framework 近期上线新功能 支持使用 buildCommand 自定义构建命令 支持 Egg 、Next 等约定目录而不是直接导入文件的 Node 框架 cloudbaserc 配置文件支持模板变量,可以支持一份配置,支持多种变量注入 支持指定模式 [代码]mode[代码] 来选择不同的配置,例如 cloudbase framework:deploy --mode production 提升插件安装和依赖安装速度,部署速度更快 🚀 支持自动检测 Dockerfile 项目生成云应用配置 云应用插件支持注入环境变量 支持自动检测 Hexo 、Gatsbyjs 项目 功能预告 CloudBase Framework 支持在线一键云端部署 GitHub 项目 CloudBase Framework 部署错误日志细化,支持更加明确的日志输出 CloudBase Framework 支持新增 PHP 插件 CloudBase Framework Node 插件支持日志查看功能 小调查 你希望下一步 CloudBase Framework 提供怎样的功能升级或者优化?
2020-07-29 - 「笔记」订阅消息-订阅次数维护
前言 距离1月10日模板消息下架只有2天了,在社区里经常能看到有帖子在问关于怎么记录订阅次数的问题,这里在这里介绍一下自己用的简单方案,仅供参考。 误区一 [图片] 上面这个图大家应该都比较熟悉了,很多人总是误以为勾选“总是保持以上选择,不再询问”,就可以无限发送订阅消息,这个是错误的想法,勾选和不勾选唯一的区别就是每次触发订阅的时候会不会弹授权窗口而已。 误区二 订阅消息不能通过bindsubmit的方式触发,必须通过bindtap的方式触发。 误区三 触发订阅窗口后,不管用户点击了允许还是取消,都会进入订阅消息的success回调中,所以通过这个来判断用户是否订阅是错误的。 订阅次数的维护 先看下官方的文档: [图片] 那么我们该如何使用呢? 我们通过 wx.requestSubscribeMessage 接口发送的时候是知道需要让用户订阅哪几个模板的,就是 tmplIds 这个参数填的数组。那么根据官方文档的回调内容,我们就可以直接在success内去获取对应的key所返回的状态。把获取到的状态分别存入自己的数据库里。发送的时候去数据库里查询需要发送的模板并且状态为accept的去发送,如果发送成功则删除一条记录(因为没有过期一说,所以随便删除哪一条记录都不影响)。 参考代码 [图片] 查询模板订阅状态 需要基础库大等于2.10.0才支持。 wx.getSetting({ withSubscriptions: true, success (res) { console.log(res) } }) 官方文档 补充 如果用户选择了不再接收消息会清空之前的订阅次数,但是这个不会主动告诉开发者,所以发送订阅消息失败后,需要根据返回内容自行清空记录,重新计算。 相关文章 「笔记」订阅消息-订阅次数维护(2020年3月更新改动) 「笔记」订阅消息体验踩坑
2020-03-06 - ✨【进阶技能】小程序内wxParse读取的富文本中插入小程序商品链接,直接在文章中跳转商品详情,商品可插入文章任意位置
今天说一个进阶技能,怎么用wxParse读取的富文本中插入商品链接,首先你得懂得使用wxParse 和后台网页的富文本编辑器,这篇文章并不是基础讲解这俩个插件的使用方法,这里只作概述,如需详细了解,还请搜索这俩个插件的详细使用方法,弄懂之后再看本文,会比较容易理解 最终效果: 1.后台文本编辑器,添加商品链接效果: [图片] 2。小程序内文章中自动转为商品模块效果: [图片] *其中小程序的富文本页面的商品模块可以直接点击跳转到商品详情界面 实现流程: 一 插件简介及下载地址 1.wxParse:小程序中的HTML解析器,可以将HTML代码直接转换为小程序可以显示的代码,一般用于后台传入HTML富文本,小程序中直接显示文章 GitHub地址:https://github.com/icindy/wxParse 使用简介: [图片] 解压出来后,直接复制到小程序项目的根级目录, 在需要解析HTML的页面中加入代码 wxml:(除了目录地址,其他都是固定格式,不需要修改) import src="../../wxParse/wxParse.wxml" /> js:(这里的res.data.content就是我们后台传过来的HTML富文本代码,其他参数都不需要改) const WxParse = require('../../wxParse/wxParse.js'); onLoad: function (options) { WxParsewxParse('article', 'html', resdatacontent, that, 0); }, 2.Ueditor:网页的富文本编辑器插件,下载地址某度搜Ueditor官网就出来了,这种编辑器很多,关键不是TX的,就不发使用说明和下载地址了,怕给我文章封了,嘿嘿,自行查找吧 二 后台富文本编辑器修改 本文以Ueditor为例子,使用其他编辑器插件,可以看看实现原理 1.修改link插件文件:(说明:Ueditor有添加自定义按钮的方法,不过呢,因为我这里用的编辑器都是给小程序传的HTML编码,添加A标签的功能用不上,就直接修改了,有兴趣的可以额外添加一个按钮) [图片] 下面是完整代码,修改一下你的AJAX 调用接口地址后,直接复制,替换截图中的link.html文件就可以使用了 htmlhead title> scripttype"text/javascript"src"../internal.js"> --> tr td> 原title --> tr tdcolspan"2" labelfor"target"> ";// }else{// $G("msg").innerHTML = "";// } //这里的AJAX请求地址,需要改成你的接口地址 createRequest('你的AJAX接口地址.html?id='+$G('href').value.replace(/^\s+|\s+$/g, ''),getgoodinfo); //提示:这里的这个请求接口,用户用F12是可以看到的,所以调用的时候,一定要作加密认证,不要只传ID }; functionhrefStartWith(href,arr){ href = href.replace(/^\s+|\s+$/g, ''); forvar i=,ai;ai=arr[i++];){ if(href.indexOf(ai)==){ returntrue; } } returnfalse; } /获取ajax回传数据 unction getgoodinfo(){ if(http_request.readyState == ){ if(http_request.status==200){ if(http_request.responseText==){ alert("该ID商品不存在"); document.getElementById('title').value=; }else{ document.getElementById('text').value="商品链接:" + http_request.responseText.split(",")[]; //这里我是以 商品ID,商品名称,商品图标地址,商品价格 以‘,’英文逗号链接成的字符串,可以根据你的业务需要修改, document.getElementById('title').value=http_request.responseText; } }else{ alert("您请求的页面发生错误"); } } ar http_request = false; /生成ajax unction createRequest(url,func){ //Mozilla 等其他浏览器 if(window.XMLHttpRequest){ http_request = new XMLHttpRequest(); if(http_request.overrideMimeType){ http_request.overrideMimeType("text/xml"); } }elseif(windows.ActiveXObject){ try{ http_request = new ActiveXObject("Msxml2.XMLHTTP"); }catch(e){ try{ http_request = new ActiveXObject("Microsoft.XMLHTTP"); }catch(e){} } } if(!http_request){ alert("浏览器不支持访问"); returnfalse; } http_request.onreadystatechange = func; //发出http请求 http_request.open("GET",url,true); http_request.send(null); } 三 小程序端wxParse插件代码修改 1.修改html2json.js文件: [图片] 在该文件的146行添加如下代码:(这里我是以 商品ID,商品名称,商品图片地址,商品价格以‘,’英文逗号隔开组成字符串传过来的,可以根据你的业务需求更改识别方式) 如图: [图片] //将A标签的title转为商品信息 if (nodetag === 'a' && nodeattr.title!=) { //console.log(nodenode.attr.title) var title = nodeattr.title.split(",") nodeattr.title.split(",") nodegoodname = title[] nodegoodicon = title[] nodegoodprice = title[] } 2.修改wxParse.wxml文件: [图片] 在文件177行找到<!--a类型--> 进行修改,如图:[图片] 代码如下:(注释掉的是原本插件的代码,这里的商品模块CSS就自行设计编写吧,直接写到要调用wxParse的页面wxss文件中就行) blockwx:elif{{item.tag == 'a'}}viewbindtap"wxParseTagATap"class"wxParse-inline {{item.classStr}} wxParse-{{item.tag}}data-src{{item.attr.href}}style{{item.styleStr}}viewclass"goodbg row"imageclass"goodimg"src{{item.goodicon}}> 3.修改wxParse.js文件: 这个主要是修改一下点击跳转标签的路径,因为我这里是直接是把商品的ID传了过来,如果直接传了绝对路径这一步可以省略 [图片] [图片] 这里涂抹的地方换成你的小程序路径 到此,修改结束,就可以使用了! 后记 1.该方法可以改为跳转其他的页面路径也可以,稍微修改一下就行 2.后台的编辑器我没弄成可视化的商品跳转组件,这个如果有兴趣的同学搞出来了,给大家分享一下
2021-04-15 - ✨5G时代来了,电商小程序商品视频播放解决方案,利用腾讯视频插件,好处多多,不占自己服务器空间和带宽
今天给大家介绍一下电商小程序商品加视频的解决方案 样例小程序: 各种好处: 空间节约:5G时代来临,视频播放为基本要求,还在为视频的存储空间发愁么,用腾讯视频插件,视频直接上传到腾讯服务器,无任何服务器空间消耗.带宽节约:空间不是问题的话,如何保证视频的播放流畅度?用腾讯视频插件播放,不占用自己服务器带宽,还省了CDN的钱,至于速度,你觉得腾讯视频的服务器会卡么?技术成本:视频的增删改查,代码都不用写,视频文件的地址直接用VID不到20个字符代替,开发方便,维护简单资质问题:用原生video标签,视频多了,上线审核的时候会要求文娱资质,有官方正面回答用腾讯视频播放,无需资质[图片] 视频审核:视频上传腾讯服务器的时候,腾讯自己就会审核好视频合法性 好处多多,我们来看下实现方法 一 添加插件: [图片] 进入小程序后台:设置->第三方设置->添加插件 输入APPID: wxa75efa648b60994b 腾讯视频插件官网地址:https://developers.weixin.qq.com/community/servicemarket/detail/00066e5ce0ce503bd9d837c1456415 二 小程序代码: 在app.json中加入代码,引用插件,版本号如果不是最新,开发工具上会有提示最新版版本号 [代码]"plugins": {[代码] [代码] "tencentvideo": {[代码] [代码] "version": "1.3.7",[代码] [代码] "provider": "wxa75efa648b60994b"[代码] [代码] }[代码] [代码]}[代码] 在需要播放视频的小程序页面的json中加入代码: [代码]{[代码] [代码] "navigationBarTitleText": "商品详情",[代码] [代码] "usingComponents": {[代码] [代码] "txv-video": "plugin://tencentvideo/video"[代码] [代码] }[代码] [代码]}[代码] 需要播放视频页面的wxml中加入代码: [代码]<!-- 商品轮播图开始 -->[代码] [代码]<swiper autoplay="{{autoplay}}"[代码] [代码]indicator-dots='{{indicator}}'[代码] [代码]indicator-active-color='#f54000'[代码] [代码]class='swiper'>[代码] [代码]<swiper-item wx:if="{{good.video}}">[代码] [代码] <txv-video vid="{{good.video}}"[代码] [代码]playerid="txv1"[代码] [代码]width="750rpx"[代码] [代码]height="720rpx"[代码] [代码]bindplay="videoplay"[代码] [代码]bindpause='videopause'[代码] [代码]bindpause='videoended'[代码] [代码]isHiddenStop="true"></txv-video>[代码] [代码]</swiper-item>[代码] [代码]<block wx:for="{{good.img}}"[代码] [代码]wx:key=''>[代码] [代码] <swiper-item>[代码] [代码] <image src="{{item}}"[代码] [代码]class='swiperimg'[代码] [代码]bindtap='previewImage'[代码] [代码]data-current='{{item}}'/>[代码] [代码] </swiper-item>[代码] [代码]</block>[代码] [代码]</swiper>[代码] [代码]<!-- 商品轮播图结束 -->[代码] 我这里是放到轮播图的第一张,做了判断 如果该商品无视频则不显示 讨论几个问题,视频播放的时候轮播图自动滚动了,页面下滑,视频继续播放,影响用户体验 所以增加三个方法和一个设置 视频播放时,设置轮播图为不自动轮播,消除轮播图位置点 binplay:视频播放时触发,设置轮播图为不自动播放,不显示位置点 [代码]//视频播放方法[代码] [代码]videoplay:function(){[代码] [代码] this.setData({[代码] [代码] autoplay:false,[代码] [代码] indicator: false,[代码] [代码] })[代码] [代码]},[代码] bindpause:视频暂停时触发,设置轮播图为自动播放,显示位置点 [代码]//视频暂停方法[代码] [代码] videopause:function(){[代码] [代码] this.setData({[代码] [代码] autoplay: true,[代码] [代码] indicator: true,[代码] [代码] })[代码] [代码] },[代码] bindended:视频播放结束时触发,设置轮播图为自动播放,显示位置点 [代码]//视频播放结束方法[代码] [代码]videoended:function(){[代码] [代码] this.setData({[代码] [代码] autoplay: true,[代码] [代码] indicator: true,[代码] [代码] })[代码] [代码]},[代码] 设置页面滑动,使视频不在可见范围时自动停止播放视频,isHiddenStop:ture 样例如图: [图片] 三 后台代码: 前端用VID播放了,可是后台客户怎么在后台网页上预览他上传的视频呢?------引用腾讯视频H5播放器插件 <div id="txvideo"></div> <input id="vid" name="video" class="inputl" placeholder="请输入腾讯视频vid" value='{$vid}'/> [代码]<script type="text/javascript"[代码] [代码]src="//vm.gtimg.cn/tencentvideo/txp/js/iframe/api.js"></script>[代码] [代码]<script>[代码] [代码] // 点播[代码] [代码] var[代码] [代码]vid = document.getElementById("vid").value//获取输入框元素[代码] [代码] var[代码] [代码]player = new[代码] [代码]Txp.Player({[代码] [代码] containerId: 'txvideo',[代码] [代码] vid: vid[代码] [代码] });[代码] [代码]</script>[代码] 效果如图: [图片] 四 获取腾讯视频vid方法: 进入腾讯视频.找到要播放的视频 ,鼠标放到分享那里,点击复制通用代码 [图片] 复制出来的代码如下: <iframe frameborder="0" src="https://v.qq.com/txp/iframe/player.html?vid=y3033v5o6ru" allowFullScreen="true"></iframe> 其中的vid=y3033v5o6ru 就是该视频的vid码 五 通过腾讯视频地址,盗播获取真实播放地址对比 用腾讯视频插件播放视频,是有前置广告的,可以花钱去广告,具体费用看该网站:https://v.qq.com/open 网上也有通过腾讯的视频地址盗播获取该视频真实播放地址的方法,将地址直接写到video标签就行.而且播放时没有广告,怎么说这种方法试过,毕竟上面的Q&A截图里人家说了,这种方法弊端,毕竟违规.仁者见仁吧 我没用这个方法主要是这个方法是有时效的,腾讯视频的地址是动态生成的,等token有效期一过,你的盗播地址就要跟着换,视频少还好,我这个是给电商加的视频播放,那么多商品,得换死... 六 槽点 1.视频广告,哎,不多说了 2.本来我得视频占比是750rpx:750rpx 结果这样得话下面得播放控制条显示不全,所以成了750x720 3.放到轮播图里广告结束时,跳过广告那个按钮会显示到其他轮播图上 七 建议 这个插件是真的好,算是官方得良心产品了,建议是开放视频上传接口,你说说这么好用得东西,唯一让客户不买单的就是我上传个视频还要到腾讯视频里上传.毕竟你有上传接口,共享出来,资质得话可以和小程序得APPID绑定啊 用token验证,毕竟能上线小程序得都能通过实名认证么 ,如果开放了上传接口,基本以后小程序根本不需要为播放视频开发任何东西了,你可以广告收费啊,毕竟现在也是收费去广告,大不了多收点,这点钱比起我们开发代码,买服务器空间,增加带宽,增加CDN得钱,根本不算什么
2021-04-15 - 微信小程序订阅消息汇总,持续跟进中
最近在搞微信小程序订阅消息,遇到不少的坑,这篇文章的初衷就是帮忙开发者少踩坑,业务能快速对接订阅消息。 也欢迎开发者私聊我,咱们一起维护这个列表。 下面有部分内容是从@拾忆和@Jianbo摘取的,如有侵权,联系我,我来删除。 官方文档 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/subscribe-message.html 订阅消息体验踩坑@拾忆 https://developers.weixin.qq.com/community/develop/article/doc/000e22321b8ef0b9bc491ae9c53c13 小程序订阅消息开发指南@Jianbo https://developers.weixin.qq.com/community/develop/article/doc/00026407d58cf07bb96941b0e5b813 开发者需要关注的点 1.如果不勾选红色方框内的内容,用户每次触发订阅消息功能都会弹出授权窗口,如果用户勾选了则不会出现弹窗。 2.微信不会为开发者保存订阅次数,需要自己在后台记录用户触发的次数。超过次数调用接口下发订阅消息会返回失败。 3.发送模板格式和原来的模板消息格式不一致,特别是data内的内容,订阅消息的字段key是和数据类型有关,value的参数需要严格按照设置的类型提交,具体使用参考后台的模板详情。 4.长期订阅消息只针对特定行业开放,所以普通开发者并无法使用。 5.用户是否勾选总是保持以上选择,不再询问,这个对开发者透明 6.测试环境如果勾选总是保持以上选择,就不会在弹出来,如果进入设置页关闭,也不会弹出来。有一个骚操作,就是去后台将订阅消息模板删除,重新新建一个,就会生成一个新的模板id,就能进行测试了 7.允许和拒绝的回调返回errMsg是一样的 低版本说明 1.基础库2.8.2 版本才开始支持,用户发生点击行为或者发起支付回调后,才可以调起订阅消息界面。 2.微信版本:一次调用最多可订阅3条消息(注意:iOS客户端7.0.6版本、Android客户端7.0.7版本之后的一次性订阅/长期订阅才支持多个模板消息,iOS客户端7.0.5版本、Android客户端7.0.6版本之前的一次订阅只支持一个模板消息)消息模板id在[微信公众平台(mp.weixin.qq.com)-功能-订阅消息]中配置 使用的两种方式 1.点击行为,不能嵌套在form组件 2.支付回调,可以wx.requestPayment回调里使用 可参考的产品 1.luckin微信小程序,在支付之前体验 2.青柠单车小程序,扫码就能体验 bug 错误码 1.43101用户拒绝接受消息,如果用户之前曾经订阅过,则表示用户取消了订阅关系 changeLog 1.2019-12-31 20:00:目前订阅消息不支持跳开发版,我们会尽快优化解决 2.2020-01-02 12:55:微信开放平台,向非api方式注册的小程序添加订阅消息,小程序类目不符合订阅消息类目,添加不了,需要手动到微信后台设置类目 3.2020-01-02 19:00 新版订阅消息IOS手机bug,直接返回之后就不会在弹窗了,微信7.0.9版本已解决https://developers.weixin.qq.com/community/develop/doc/00008a645500e88023b9341fc51c 4.2020-01-06 15:00 小程序订阅消息弹出样式是系统默认的,目前开发者不允许修改 5.2020-01-071510 小程序订阅消息的相关接口频次上限是多少(当前每个账号的模板消息的日调用上限为10万次,单个模板没有特殊限制。当账号粉丝数超过10W/100W/1000W时,模板消息的日调用上限会相应提升,以公众号MP后台开发者中心页面中标明的数字为准。https://developers.weixin.qq.com/community/develop/doc/00084455e7c068058ab9db8d656800 6.2020-01-08 11:30 微信支付成功从A页面进入B页面,微信版本 7.0.8,页面切换时,订阅消息弹窗不显示了。微信版本7.0.9没有这个问题;后续会修复
2020-02-16 - 实战分享: 小程序云开发玩转订阅消息(二)
[图片]这是实战分享: 小程序云开发玩转订阅消息的第二部分 第一部分链接 《实战分享: 小程序云开发玩转订阅消息(一)》 将订阅消息存入云开发数据库接下来我们创建一个云函数 [代码]subscribe[代码] ,这个云函数的作用是将用户的订阅信息存入云开发数据库的集合 [代码]messages[代码] 中,等待将来需要通知用户时进行调用。 在微信开发者工具的云开发面板中创建数据库集合 [代码]messages[代码] [图片]微信开发者工具新增数据库集合 创建一个 [代码]subscribe[代码] 云函数,在云函数中我们将小程序端发送过来的课程订阅信息,存储在云开发数据库集合中,开发完成后,在微信开发者工具中右键上传并部署云函数。 cloudfunctions/subscribe/index.js [代码]const cloud = require('wx-server-sdk'); cloud.init(); const db = cloud.database(); exports.main = async (event, context) => { try { const {OPENID} = cloud.getWXContext(); // 在云开发数据库中存储用户订阅的课程 const result = await db.collection('messages').add({ data: { touser: OPENID, // 订阅者的openid page: 'index', // 订阅消息卡片点击后会打开小程序的哪个页面 data: event.data, // 订阅消息的数据 templateId: event.templateId, // 订阅消息模板ID done: false, // 消息发送状态设置为 false }, }); return result; } catch (err) { console.log(err); return err; } }; [代码]利用定时触发器来定期发送订阅消息接下来我们需要实现一个定时执行的云函数[代码]send[代码],来检查数据库中是否有需要发送给用户的订阅消息。如果有需要发送的订阅消息,会通过云调用 [代码]cloud.openapi.subscribeMessage.send[代码] 将订阅消息发送给用户。 创建一个名叫 [代码]send[代码] 的云函数,首先要配置云函数,在 [代码]config.json[代码] 的 [代码]permissions[代码] 中新增 [代码]subscribeMessage.send[代码]的云调用权限,然后新增一个 [代码]sendMessagerTimer[代码] 的定时触发器,定时触发器的语法和 [代码]linux[代码] 的 [代码]crontab[代码] 类似,比如,我们配置的 [代码]"0 * * * * * *"[代码] 代表每分钟执行一次云函数。 cloudfunctions/send/config.json [代码]{ "permissions": { "openapi": ["subscribeMessage.send"] }, "triggers": [ { "name": "sendMessagerTimer", "type": "timer", "config": "0 * * * * * *" } ] } [代码]接下来是实现发送订阅消息的云函数,这个云函数会从云开发数据库集合[代码]messages[代码]中查询等待发送的消息列表,检查数据库中是否有需要发送给用户的订阅消息,发送条件可以根据自己的业务实现,比如开课提醒可以根据课程开课日期来检查是否需要发送订阅消息,在我们下面的代码示例里做了简化,筛选条件只检查了状态为未发送。 查询到待发送的消息列表之后,我们会循环消息列表,依次发送每条订阅消息,发送成功后将数据库中消息的状态改为已发送。 cloudfunctions/send/index.js [代码]const cloud = require('wx-server-sdk'); exports.main = async (event, context) => { cloud.init(); const db = cloud.database(); try { // 从云开发数据库中查询等待发送的消息列表 const messages = await db .collection('messages') // 查询条件这里做了简化,只查找了状态为未发送的消息 // 在真正的生产环境,可以根据开课日期等条件筛选应该发送哪些消息 .where({ done: false, }) .get(); // 循环消息列表 const sendPromises = messages.data.map(async message => { try { // 发送订阅消息 await cloud.openapi.subscribeMessage.send({ touser: message.touser, page: message.page, data: message.data, templateId: message.templateId, }); // 发送成功后将消息的状态改为已发送 return db .collection('messages') .doc(message._id) .update({ data: { done: true, }, }); } catch (e) { return e; } }); return Promise.all(sendPromises); } catch (err) { console.log(err); return err; } }; [代码]最终效果 [图片]开课提醒订阅消息截图 源代码https://github.com/binggg/tcb-subscribe-demo[3] 参考资料 [1]注册小程序帐号: https://tencentcloudbase.github.io/2019-09-03-wx-dev-guide-register/ [2]开通云开发服务: https://tencentcloudbase.github.io/2019-09-03-wx-dev-guide-service/ [3]https://github.com/binggg/tcb-subscribe-demo: https://github.com/binggg/tcb-subscribe-demo
2019-10-23 - 实战分享: 小程序云开发玩转订阅消息(一)
[图片] 微信官方为提升小程序模板消息能力的使用体验,对模板消息的下发条件进行了调整。原有的小程序模板消息接口于 2020 年 1 月 10 日下线,届时将无法使用旧的小程序模板消息接口发送模板消息,取而代之的是新的一次性订阅消息和长期订阅消息。 订阅消息给小程序开发者带来了更好的触达用户的能力,在具体实施过程中,开发者如何把模板消息换成新的订阅消息,是否需要购买服务器来实现服务器鉴权,怎样才能在用户订阅之后一段时间后,给用户发送长期或一次性订阅消息呢? 小程序·云开发最近支持了通过云调用免 access_token 发送订阅消息,还新增支持了在定时触发器中实现云调用,这些能力可以帮助开发者轻松玩转小程序订阅消息。 我们今天会利用小程序·云开发进行一个小程序中实现订阅开课提醒的实战,帮助大家了解如何基于小程序·云开发快速接入小程序订阅消息。 [图片]整体时序图[图片]开课提醒订阅消息时序图环境准备注册小程序帐号[1]开通云开发服务[2]获取订阅消息模板 ID在微信小程序管理后台中,新增一个订阅消息的模板,这里我们新增了一个开课提醒的模板。 [图片]新增模板引导用户订阅微信小程序提供了[代码]wx.requestSubscribeMessage[代码] 接口来发起申请订阅权限界面。 [图片]微信申请订阅权限界面在 "订阅开课提醒" 的按钮上绑定 tap 事件,事件处理器我们这里用的 [代码]onSubscribe[代码] index.wxml [代码]<button class="btn" data-item="{{ item }}" bindtap="onSubscribe" hover-class="btn-hover" > 订阅开课提醒 </button> [代码]在 [代码]onSubscribe[代码] 函数内,我们会调用微信 API [代码]wx.requestSubscribeMessage[代码] 申请发送订阅消息权限,当用户在弹窗同意订阅之后,我们会收到 [代码]success[代码] 回调,将订阅的课程信息调用云函数 [代码]subscribe[代码] 存入云开发数据库,云函数 [代码]subscribe[代码] 的实现在下文会讲。 index.js [代码]onSubscribe: function(e) { // 获取课程信息 const item = e.currentTarget.dataset.item; // 调用微信 API 申请发送订阅消息 wx.requestSubscribeMessage({ // 传入订阅消息的模板id,模板 id 可在小程序管理后台申请 tmplIds: [lessonTmplId], success(res) { // 申请订阅成功 if (res.errMsg === 'requestSubscribeMessage:ok') { // 这里将订阅的课程信息调用云函数存入云开发数据 wx.cloud .callFunction({ name: 'subscribe', data: { data: item, templateId: lessonTmplId, }, }) .then(() => { wx.showToast({ title: '订阅成功', icon: 'success', duration: 2000, }); }) .catch(() => { wx.showToast({ title: '订阅失败', icon: 'success', duration: 2000, }); }); } }, }); [代码][代码] },[代码] 文章字数超出 50000 字,后半部分链接 《实战分享: 小程序云开发玩转订阅消息(二)》
2019-10-23 - 【云开发】用云开发实现订阅消息
背景 10月12日微信官方发布了小程序模板消息能力调整的通知 https://developers.weixin.qq.com/community/develop/doc/00008a8a7d8310b6bf4975b635a401 相比之前的有了较大的调整,主要的调整就是从开发者主动下发消息改为用户自主订阅,也就是说必须要用户手动订阅才行,而订阅消息又分为了一次性订阅消息和长期性订阅消息,长期性订阅消息需要有特定公共服务业务这里就不介绍了,本文主要讲的是一次性订阅消息。 开发准备 如果还没有开通订阅消息的要在小程序后台里开通订阅消息后添加需要的模板,添加完后的红框中的变量就是订阅消息接口要用到的data了 [图片] [图片] 编写云函数 新建云函数,appid跟secret填你自己的即可, 由于订阅消息需要access_token,所以在使用订阅消息接口前要先获取access_token,这里我把他们都放在一个云函数里了 新建好后要安装依赖,这里用到了[代码]request-promise[代码]模块,所以要在该目录下[代码]npm install request-promise[代码] 代码如下 [图片] [图片] 页面调用 [图片] 传入对应的参数即可 返回结果 [图片] [图片] 总结 总的来说并不难,只是有个地方要注意一下,由于之前没怎么用过云开发,不知道它返回的数据结构会有差异,比如在获取access_token的时候发现一个特别之处,在小程序里进行调用的时候,成功的话返回是下图这种格式的 [图片] 但是本地调试的时候返回又是这种格式的 [图片] 少了外面一层object,导致我判断access_token一直报错,调试了好久才发现,好在最后是可以成功获取到。 再来说这次调整,作为用户的我来说我觉得是很ok的,起码我可以选择不接收订阅消息,不像之前那样莫名其妙的就收到了一个订阅消息还不知道是哪个程序的,我是很反感这种的。但是对于一些企业来说可能就不是那么友好了,降低了触达用户的机会。但是不管怎样,身为开发者的可是有得忙了。 代码就不放了,都在图片里,自己动手敲一遍比较好 相关接口 订阅接口 获取access_token接口 下发消息接口
2019-10-14 - 小程序插件-生成二维码海报
通过简单的参数传入就可以生成分享海报,图片会根据设定的宽度和高度进行裁剪(不会压缩图片)
2018-08-26 - 订阅消息的文档太不清晰了...有多处错误???!!!
1.订阅消息删除模板 https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.deleteTemplate.html 文档就是一坨屎啊..示例中明明说参数格式是application/json,但就是不行,试了一圈发现priTmplId参数是在URL里面传的!! WTF?? 请问腾讯的开发是外包出去的吗? 有这么不规范的传参方式吗?? 2.订阅消息添加模板 https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.addTemplate.html 这个接口就更牛逼了..根本调不通...参数无论放到哪里都不行!!提示就是缺少tid之类的参数...WTF?马上10号就要切换到新接口了..但实际上却不可用,为什么???!!!!
2020-01-05 - 小程序订阅消息开发指南
2019年10月12日微信开放了小程序订阅消息的功能。按官方的说法,目前的模板消息在实现小程序服务闭环上存在缺陷: 1. 部分开发者在用户无预期或未进行服务的情况下发送与用户无关的消息,对用户产生了骚扰;2. 模板消息需在用户访问小程序后的 7 天内下发,不能满足部分业务的时间要求模板消息确实存在上述的硬伤,不利于小程序的用户留存和用户体验。为了解决这些问题,微信官方推出了用户订阅消息功能。我在微慕专业版上加了订阅消息的功能,并验证了这个功能。这个功能是否能都达到官方的预期,这个我感觉不那么乐观。这里我先说我的感受:目前的订阅消息还不完善,后续还有很大的优化空间。 目前,官方只开放了“一次性订阅消息”,尚未开放“长期性订阅消息”,因此我只尝试了“一次性订阅消息”。 一次性订阅消息:用于解决用户使用小程序后,后续服务环节的通知问题。用户自主订阅后,开发者可不限时间地下发一条对应的服务消息;每条消息可单独订阅或退订。 订阅消息推送位置:服务通知 订阅消息下发条件:用户自主订阅 订阅消息卡片跳转能力:点击查看详情可跳转至该小程序的页面 以下我简单说明订阅消息的开发过程和使用体验。 一.订阅消息的开发1.获取订阅消息的模板ID 在微信小程序的管理后台,在左侧“功能”菜单,选择“订阅消息”,然后点击“添加” [图片] 然后选择你需要的消息模板,并配置关键词。 [图片] 配置完成后,如下图所示。 [图片] 值得关注的是,在配置好的模板详情页面里的“详细内容”很重要,这个就是开发订阅消息时需要遵循的消息格式,这个格式和模板消息有细微的差别 根据微慕小程序的需要,我选用了“新的评论提醒”和“内容更新提醒”这两个消息模版。前者用于提醒发表话题或文章的作者,有新的话题或文章评论,增强作者与读者之间的交流互动;后者是提醒订阅用户,小程序有新的文章发布,引导用户回归小程序。 订阅消息申请模板的时候,需要选择所属类目,只能选择当前小程序相关的类目模板,对于模板消息不需要选择对应类目。如果删除小程序类目,就会把订阅消息模板一起删除。因此删除类目要小心谨慎。 [图片] 2.触发用户订阅,获取下发的权限 触发用户订阅,微信小程序提供的api是: [代码]wx.requestSubscribeMessage[代码],用户发生点击行为或者发起支付回调后,才可以调起订阅消息界面。 注意:微信小程序开发工具尚不支持此功能,在开发工具触发订阅的api,会提示: requestSubscribeMessage:fail 开发者工具暂时不支持此 API 调试,请使用真机进行开发 调用api的代码示例如下: [代码]wx.requestSubscribeMessage({[代码] [代码]tmplIds: ["模板A","模板B"],[代码] [代码]success: function (res) {[代码] [代码]//成功[代码] [代码]},[代码] [代码]fail(err) {[代码] [代码]//失败[代码] [代码]console.error(err);[代码] [代码]}[代码] [代码]})[代码] wx.requestSubscribeMessage(Object object) 的回调函数[代码]object.success [代码]参数有两个:errMsg和TEMPLATE_ID; 接口调用成功时errMsg值为’requestSubscribeMessage:ok’。TEMPLATE_ID是动态的键,即模板id,值包括’accept’、’reject’、’ban’。’accept’表示用户同意订阅该条id对应的模板消息,’reject’表示用户拒绝订阅该条id对应的模板消息,’ban’表示已被后台封禁。例如 { errMsg: “requestSubscribeMessage:ok”, zun-LzcQyW-edafCVvzPkK4de2Rllr1fFpw2A_x0oXE: “accept”} 表示用户同意订阅zun-LzcQyW-edafCVvzPkK4de2Rllr1fFpw2A_x0oXE这条消息。 个人觉得这个动态键不是特别合理,代码处理起来有些麻烦,如果改成静态键的json格式比较方便处理,例如: [代码]{[代码] [代码] errMsg:"requestSubscribeMessage:ok",[代码] [代码] result: [[代码] [代码] { templateId:"zun-LzcQyW-edafCVvzPkK4de2Rllr1fFpw2A_x0oXE",[代码] [代码]status:"accept"[代码] [代码]}[代码] [代码] ][代码] [代码]}[代码] 在手机上调用此api方法会调出订阅消息的界面,如下图所示: [图片] 关于这个订阅消息的授权有几点要注意: 1) 在确认提示框里,如果用户选择“取消”表示拒绝(取消)订阅消息,选择“允许”表示用户订阅一次消息。 2) 如果用户不勾选“总是保持以上选择,不再询问”,那么每次用户触发都会弹出提示框。 3) 如果用户勾选“总是保持以上选择,不再询问”,那么将再也不会唤起这个对话框。同时,如果选择“取消”,那么以后每次调用这个api的时候,都会自动拒绝;如果选择“允许”,那么以后每次调用此api,都会自动允许授权。 目前小程序没有提供获取用户是否授权订阅消息的方法。通过wx.openSetting 方法无法获取用户是否授权消息订阅的信息,scope 列表没有订阅消息的内容。 如果想从自动拒绝转换到自动自动运行,需要打开小程序的设置去配置。设置方法:点击小程序右上角的三个点,打开如下对话框 [图片] 然后选择“设置”,在设置项里选择“订阅消息” [图片] [图片] 4)对于同一种消息,用户可以订阅多次,订阅多少次,就会收到多少次订阅消息,这个订阅次数是否有上限,官方没有说明,初步判断是不限的。但是,微信不会提供订阅的次数,因此需要在小程序的后端服务里存储用户订阅的次数。因此,我在微慕小程序专业版里,提供了一个给用户多次订阅的设置,并记录用户订阅的次数。 [图片] 如果用户需要某个消息服务,可以订阅多次,当然也可以在点击“订阅”的对话框里选择“取消”,“取消”一次也就减少一次订阅。 5)对于支付的场景,也需要用户确认是否订阅,这个我觉得不合理,支付后给用户一个订单推送消息应该是刚性需求,不需要再询问一遍用户是否订阅。 2.调用接口下发订阅消息 订阅消息下发的接口是小程序后台服务端调用:subscribeMessage.send,此方法类似下发模板消息的方法,详细调用说明见参考官方的链接: https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.send.html 订阅消息的下发接口方法和模板消息稍有不同, 模板消息的json格式如下 [代码]"data": {[代码] [代码]"keyword1": {[代码] [代码]"value": "内容1",[代码] [代码]"color": "#000"[代码] [代码]},[代码] [代码]"keyword2": {[代码] [代码]"value": "内容2",[代码] [代码]"color": "#000"[代码] [代码]}[代码] [代码]}[代码] 而订阅消息的json格式如下: [代码]"data": {[代码] [代码]"thing1": {[代码] [代码]"value": "内容"[代码] [代码]},[代码] [代码]"number2": {[代码] [代码]"value": 20[代码] [代码]}[代码] 订阅消息的字段key是和数据类型有关,value的参数需要严格按照设置的类型提交,如果不按类型提交,会导致发送失败。同时如果是文本型的内容,字数也有限制,超过限制也会发送失败,但具体字数是多少,官方没有给出,同时中英文混合计算的长度也有差异,据我目前测试25个中文字符是可以的。希望官方能给出具体的字符长度限制的明确数字。 如果调用下发的次数大于用户的订阅次数,调用接口下发订阅消息会返回失败。报如下错误 [图片] 二.订阅消息使用心得1.订阅消息虽然把订阅的授权的交给了用户,但是也增加了用户使用难度,同时,一次性订阅只能收到一次,操作起来比较繁琐,如果不是刚需用户可能会首次就拒绝了这个服务,要想重新获取授权,需要用户自己打开小程序设置里去配置,颇为麻烦,小程序没有提供更简便的方法去唤起。 2.小程序的服务商为了获得更多给用户发送订阅消息的次数,肯定会想方设法去埋点引诱用户去点击订阅,这种诱导估计也是违规。 3.用户使用门槛和学习比较高,比如某个预约的服务,原来的场景是用户只要有提交表单,小程序就可以推送消息给用户,但是现在需要用户主动去订阅,无形中多了一步,如果用户不熟悉订阅消息或者直接点了“取消”,小程序就没法通知到用户了,用户可能因此错失服务,对商家和用户都是损失。 4.微信小程序将采用订阅消息,并逐步取消模板消息,虽然微信官方试图在方便用户和不打扰用户这两种选择里去寻求平衡,但订阅消息目前的模式恐怕无法达到这个期望,至少在我看来,无论对小程序的服务商,还是小程序的用户,都感到不方便。 update:2020年5月18日,日前订阅消息已经支持微信小程序开发工具。
2020-05-18 - 背景音频无法定时关闭问题?
需求:小程序背景音频用户可以设置一个播放时长,到时间自动关闭背景音频 小程序切换后台运行后时,背景音频无法通过定时器实现定时关闭功能。 想问各路大神有没有什么好的实现办法?谢谢!
2019-09-05 - 小程序切换到后台后,如何实现定时关闭背景音频的功能?
小程序切换后台后,应用被挂起,无法使用setInterval实现定时关闭功能,请问有什么好的解决方法嘛?或者需要配置什么东西嘛?
2019-09-06 - FileSystemManager.access如何在回调中获得文件名称
- 需求的场景描述(希望解决的问题) - 希望提供的能力 FileSystemManager.access的回调如何才能访问path或者得到操作的文件名
2018-05-15 - getSavedFileList返回fileList为空
1、在手机上调试,调用 wx.getFileSystemManager().saveFileSync 保存图片失败,才发现我存储了过多的本地图片,超过了10M。 [图片] 2、为了解决该问题,我试着去获取已经保存过的图片地址列表,但是fileList里面是个空数组。截图如下: [图片] 3、本来如果能获取到已存储的图片地址列表,可以调用unlinkSync接口删除;但是目前我不清楚我之前保存了哪些图片,所以该问题就卡住了。 [图片]
2019-03-15 - 为何正常的自动横屏页放入分包后就不能自动横屏了呢?
"pageOrientation""landscape" 配置文件的代码片段如下: { "enablePullDownRefresh": false, "navigationBarTitleText": "我是标题", "backgroundTextStyle": "light", "navigationBarBackgroundColor": "#0099FF", "backgroundColor": "#000000", "navigationStyle": "custom", "pageOrientation": "landscape" } 如上,自动横屏页面已配置基于单页面的json文件测试没问题,点击进入页面时可以自动变成横向展示,但一旦放入分包中就失效,不能自动横屏了,微信开发者工具、微信安卓版、微信ios版都有错,望修复,谢谢。 开发者工具为:1.02.19 微信版本号:7.0.6
2019-12-23 - 小打卡 | 如何基于微信原生构建应用级小程序底层架构(上)
[图片] 大家好,我是小打卡的前端负责人金轩正,今天分享的主题是如何基于微信原生构建应用级小程序底层架构,这个命题看上去好像有些大,不过不要紧,这次分享我把它拆一下,大致从 小程序原生开发面临的问题 小打卡整体架构演进 开发中摸索与实践 这三个方面来看这个讲一下 [图片] 小程序原生开发面临的问题[图片] ok,首先第一个方面原生开发遇到的问题 小程序从17年诞生2年来一直处于互联网风口,不过对于开发者而言的整个开发体验不是特别友好,在17-18年之间我和很多开发小程序的小伙伴们聊过,大多数的反馈可能分为下面大致几类,当然还有更多: 没有父类,无法使用继承挂载全局方法,扩展生命周期没有父类,无法使用继承挂载全局方法,扩展生命周期 不支持跨页面/多页面通讯 setData的性能瓶颈 代码包大小限制 1/2/4/8 M,没有npm包 代码发布流程繁琐 其根本原因是将刚刚诞生的小程序与已经非常成熟的React,vue,angular作对比,而没有将小程序作为一个新的生态来看待,当然这个是一种看待事物的进步,并不是倒退,我在这里说这句话的意思是有更多的问题需要我们开发者主动去解决问题,推动整个生态的前进与发展 [图片] 其实这里可能有些朋友会问,已经有很多优秀的框架已经解决了这些问题,那么为什么还要使用原生开发? 确实在这段时间内出现了很多优秀的解决方案,我们不用并不是因为情怀哈(当然还是有那么一丢丢) 更多的是下面几点: 历史包袱,改造成本过高 小打卡在小程序刚出现的时候就进入开发了,当时框架还不成熟,而且对创业公司来说时间和迭代效率高于一切,在人手不足,业务模式尚未形成,还处于探索阶段的情况下花费大量时间去做对产品影响较小, 甚至delay迭代速度事情不是很赚 减少与第三方沟通成本 高速迭代的情况下,将时间尽可能的覆盖于业务上,避免在整个开发-上线闭环上增加节点 避免开发黑盒,控制风险 虽然整个社区是非常活跃的,fixed一个问题同样是需要花费一定时间,但是很多时候需求是不会等你bug fixed 如非必要,勿增实体 即“简单有效原理”,这句话还是我去年刚来公司的时候和阿赖聊他所说过的 放在项目开发上我的理解是在架构层面要做的尽可能的薄,避免过度设计 这样才有足够的扩展性,灵活性,容错性 这些框架虽好,但是对我们当前业务来说可能过于复杂,比如跨端在之前的阶段还没有这方面需求,而像组件化小程序已经支持,自动化构建我们自己也是可以搭建的并不复杂 相信微信小程序团队 是真正的想把这件事情做好,而且做的是一个生态,不论是小程序对于反馈响应速度,和迭代速度非常给力,还是对开发者社区运营,比如是社区活跃与审核速度挂钩,社区周刊,优质个人和优质企业 对齐web标准,并且更加开放 [图片] 小打卡整体架构演进其实小打卡整个架构并非一蹴而就的,就像前面所说的如非必要,勿增实体,而是大量的实际开发中遇到的共同问题解决方案的集合题 [图片] 常规架构这个是微信小程序给出的快速开发模版的一个开发模式: server模块提供数据,App作为全局对象直连所有的业务模块,工具函数提供api处理业务模块的需求 优点: 整个模型非常简单,上手快,学习成本 低结构清晰,在业务不复杂的情况下可以快速开发 不瞒大家其实小打卡在最初的半年内基本都是这套模式。 当然是在业务不复杂的情况下,复杂情况下会出现哪些问题呢? App作为全局对象在有大量业务模块连接的情况下,代码很容易膨胀,在多人开发的时候问题非常明显,无论是fixed bug还是正常的业务开发都会造成麻烦 页面之间独立,缺少公共模块,唯一的工具函数又要尽可能保持单一职责来提供服务(小打卡当时就是因为这个问题导致很多工具函数内部存储直接修改外部状态,导致大量强耦函数合无法拆分) 业务层直连server层,未拆分数据层的情况下,基本不存在复用性 上面所述的问题,从我接手这个项目到真正的调整持续了挺长一段时间,主要是缺乏一个契机来进行优化 优化的转折点 [图片] 然后突然有一天产品同学跑过来说: 我们要有自己的核心数据仓库,我们要看实时数据 ok,涉及到数据采集的问题了,我这边从浅到深大概列了几项: 最基础的多个页面pv,uv如何监控,不可能每个页面都要手动收集 为了统计页面和事件的分享和回流的数据,需要在分享事件携带大量的参数 微信的wx.previewImage, wx.chooseImage 等api对于用户session的收集造成很大麻烦 我们先解决第一个问题,如何收集页面pv,uv 容易陷入的误区 [图片] 在解决问题之前,我们先说一下开发小程序容易进入的误区 App 和 Page 等函数工厂是微信原生提供,不可修改 小程序项目结构是基于App, Page, 工具函数三个模块构建的 小程序的全局存储只有globalData和本地缓存 其实产生这些误区最根本的原因是小程序没有提供在复杂业务逻辑下的开发范式,比如vue,react有自己的通用开发模版 如果保持这些观念来进行开发的话,很容易将路子走窄,并且难以解决一些实际上的问题, 其实不论小程序和传统web有多少不同, 本质上还是在js环境下开发 小打卡架构图解 [图片] 为了更好的方便理解后面的具体实现,我提前放了一张目前小打卡的架构图 首先很熟悉的server这一边垫了一个数据层,主要将数据层和业务层解耦,提高复用性,并且提供一些通用功能,比如返回格式化数据问题,参数校验,日志监控... 在App对象和业务层同样增加了一个全局模块,提供独立于业务和工具类,只提供api之间双向通讯的渠道 工具模块的话其实就是对业务层的增强,比如常见的请求模块,上传模块,路由拦截等等 业务模块的话基本除了增加Component和中间层外没有太大变化 这个图上可能有两块可能大家觉得比较怪异,一个是global里面的函数重载,还有一个是业务模块的中间层是什么? 函数重载其实就是修改微信提供的App, Page, Component函数,使其更符合我们的业务场景, 业务模块的中间层就是依赖于函数重载的扩展 其实小打卡的整套架构都是基于这两个模块,这两个模块赋予了更多的可能性,然而实现却十分的简单 点击查看:小打卡 | 如何基于微信原生构建应用级小程序底层架构(下)
2019-04-22 - swordsIM聊天插件
本插件主要是做为平台内客户之间的交流工具,也可做为客服工具,包含了聊天、联系人列表、实时消息通知、查看历史记录、个人设置等,个人设置可以设置自己的联系方式、在线自动回复、离线自动回复等,还可以发送语音、图片、视频消息等,消息及时、信息不丢失等,对接简单易用 [图片] [图片] [图片] [图片] 如有兴趣可扫描下方小程序码体验哦! [图片] [图片]
2019-01-10 - 各位保护好代码
微信小游戏可以被反编译的问题怎么解决. 和小程序一样,单机版的小游戏可以被直接反编译,并且上架. 这里给出两个游戏的试玩视频,一个是我的,一个是别人的 引力怪[我的] https://v.youku.com/v_show/id_XMzc0NDE4OTIyMA==.html?spm=a2h3j.8428770.3416059.1 观看密码:123456 无尽黑洞[盗版]试玩视频: https://v.youku.com/v_show/id_XMzc0NDE5MDY1Ng==.html?spm=a2h3j.8428770.3416059.1 观看密码:123456 附上一个横向对比图: [图片] 两次投诉结果: [图片]
2018-07-26 - 小程序如何识别是不是刘海屏?
使用了navigationStyle为custom设置屏幕为自定义导航条,现在有一个问题,如何识别此设备是不是刘海屏,因为需要针对刘海屏做特殊? - 预期表现 希望通过getSystemInfo接口能够拿到是不是刘海屏,已经刘海屏的尺寸
2018-12-14 - 小程序构建骨架屏的探索
首屏 一般情况下,在首屏数据未拿到之前,为了提升用户的体验,会在页面上展示一个loading的图层,类似下面这个 [图片] 其中除了菊花图以外网上还流传这各种各样的loading动画,在PC端上几乎要统一江湖了,不过最近在移动端上面看到不同于菊花图的加载方式,就是这篇文章需要分享的Skeleton Screen,中文称之为"骨架屏" 概念 A skeleton screen is essentially a blank version of a page into which information is gradually loaded. 在H5中,骨架屏其实已经不是什么新奇的概念了,网上也有各种方案生成对应的骨架屏,包括我们经常使用的知乎、饿了么、美团等APP都有应用骨架屏这个概念 图片来源网络,侵删 [图片] 方案 先从H5生成骨架屏方案开始说起,总的来说H5生成骨架屏的方案有2种 完全靠手写HTML和CSS方式给每个页面定制一套骨架屏 利用预渲染的方式生成静态骨架屏 第一套方案,毫无疑问是最简单最直白的方式,缺点也很明显,假如页面布局有修改的话,那么除了修改业务代码之外还需要额外修改骨架屏,增加了维护的成本。 第二套方案,一定程度上改善了第一套方案带来的维护成本增加的缺点,主要还是使用工具预渲染页面,获取到DOM节点和样式,保留页面结构,覆盖样式,生成灰色块盖在原有文本、图片或者是canvas等节点上面,最后将生成的HTML和CSS打包出来,就是一个带有骨架屏的页面。最后再利用webpack工具将生成的骨架屏插入到HTML里面,详细的话可以看看饿了么的分享,这里就不多描述了。 调研了下H5生成骨架屏的方案,对于小程序生成骨架屏的方案也有了一个大致的想法,主要有2个难点需要实现 预渲染 获取节点 预渲染 再说回饿了么提供的骨架屏的方案,使用 puppeteer 渲染页面(或者使用服务端渲染,vue或者react都有提供相应的方案),拿到DOM节点和样式,这里有一点需要注意的是,页面的渲染是需要初始化的数据,数据的来源可以是初始化的data(vue)或者mock数据,当然小程序是无法直接使用 puppeteer 来做预渲染(有另外的方案可以实现),需要利用小程序初始化的 data + template 渲染之后得到一个初始化结构作为骨架屏的结构 [代码]//index.js Page({ data: { motto: 'Hello World', userInfo: { avatarUrl: 'https://wx.qlogo.cn/mmopen/vi_32/SYiaiba5faeraYBoQCWdsBX4hSjFKiawzhIpnXjejDtjmiaFqMqhIlRBqR7IVdbKE51npeF6X1cXxtDQD2bzehgqMA/132', nickName: 'jay' }, lists: [ 'aslkdnoakjbsnfkajbfk', 'qwrwfhbfdvndgndghndeghsdfh', 'qweqwtefhfhgmjfgjdfghaefdhsdfgdfh', ], showSkeleton: true }, onLoad: function () { const that = this; setTimeout(() => { that.setData({ showSkeleton: false }) }, 3000) } }) //index.wxml <view class="container"> <view class="userinfo"> <block> <image class="userinfo-avatar skeleton-radius" src="{{userInfo.avatarUrl}}" mode="cover"></image> <text class="userinfo-nickname skeleton-rect">{{userInfo.nickName}}</text> </block> </view> <view style="margin: 20px 0"> <view wx:for="{{lists}}" class="lists"> <icon type="success" size="20" class="list skeleton-radius"/> <text class="skeleton-rect">{{item}}</text> </view> </view> <view class="usermotto"> <text class="user-motto skeleton-rect">{{motto}}</text> </view> <view style="margin-top: 200px;"> aaaaaaaaaaa </view> </view> [代码] 有了上面的 data + template 之后,就有了一个初始化的页面结构,接下来就需要拿到节点信息 节点 小程序基础库1.4.0之后小程序基础库提供了一组新的API,可用于获取节点信息,具体API戳这里。 跟H5方式一样,根据class或者id获取节点信息,不同的是只能获取到当前的节点信息,无法获取到其父或者子节点信息,所以只能手动给需要渲染骨架屏的节点添加相应的class或者id [代码]<view class="container"> <view class="userinfo"> <block> <image class="userinfo-avatar skeleton-radius" src="{{userInfo.avatarUrl}}" mode="cover"></image> <text class="userinfo-nickname skeleton-rect">{{userInfo.nickName}}</text> </block> </view> <view style="margin: 20px 0"> <view wx:for="{{lists}}" class="lists"> <icon type="success" size="20" class="list skeleton-radius"/> <text class="skeleton-rect">{{item}}</text> </view> </view> <view class="usermotto"> <text class="user-motto skeleton-rect">{{motto}}</text> </view> <view style="margin-top: 200px;"> aaaaaaaaaaa </view> </view> [代码] 约定2个特殊的class作为获取节点信息的标记[代码]skeleton-rect[代码]和[代码]skeleton-radius[代码],在页面中获取相应的[代码]top[代码]、[代码]left[代码]、[代码]width[代码]、[代码]height[代码]进行骨架屏的绘制 结果 [图片] 具体的调用方式和源码,请看 github ,最后求start 总结 上文有说到小程序也可以使用 page-skeleton-webpack-plugin 方式一样生成骨架屏,最重要的一点就是需要将小程序跑在chrome上面,后面的流程就一样了,至于怎么将小程序跑在chrome上面呢?可以利用 wept ,缺点就是目前作者已经停止维护这个工具了,不支持新版小程序的API。 说回来我这个生成骨架屏的方案,其实跟 page-skeleton-webpack-plugin 有点相似,不同的是,page-skeleton-webpack-plugin 采用离线渲染的方式生成静态骨架屏插入路由中,而我采用运行时先渲染页面默认结构,然后根据默认结构再绘制骨架屏。从性能角度出发确实不如 page-skeleton-webpack-plugin,但是也差不了多少了,主要还是小程序并没有提供类似服务端渲染的方案。目前从使用上来讲,还是有点小麻烦,需要默认数据撑开页面结构,需要给相应的节点添加class,后面有时间再研究下有没有更好的方案吧~~~
2019-02-20 - 小程序中瀑布流布局太棘手?这款插件不仅貌美还「能屈能伸」
BrickLayout 晓瀑布流是知晓云为小程序开发者提供的第 3 款插件 BrickLayout 晓瀑布流为使用者提供开箱即用的瀑布流布局的一种可行性的方案,使用者仅需要按照对应所需的字段传入瀑布流组件,即可快速实现瀑布流布局。未来的瀑布流组件将会提供更多样式、适用更多场景的瀑布流模板,敬请期待!希望有更多场景推荐,希望有更多内容定制,欢迎留言或者告诉我们 g-emoji class="g-emoji" alias="clap" fallback-src="https://assets-cdn.github.com/images/icons/emoji/unicode/1f44f.png" style="box-sizing: border-box; font-family: "Apple Color Emoji", "Segoe UI", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 1.4em; line-height: 20px; vertical-align: middle;">👏/g-emoji> How BrickLayout g-emoji class="g-emoji" alias="sparkles" fallback-src="https://assets-cdn.github.com/images/icons/emoji/unicode/2728.png" style="box-sizing: border-box; font-family: "Apple Color Emoji", "Segoe UI", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 1.4em; font-weight: 400; line-height: 20px; vertical-align: middle;">✨/g-emoji>由于小程序的诸多限制,导致在 web 上很多常规实现瀑布流的方式大多受到不同程度的影响,小程序中,实现瀑布流组件大抵有两种思路:采用纯粹的 css 来实现,或者通过数据处理配合 css 来实现瀑布流。 采用纯粹的 css 采用纯粹的 css 可以用 multi-column 利用 css3 属性实现多列布局、flex 布局、grid 布局等等。但是结合每个布局的特性,我们率先排除了 grid 布局,因为 grid 布局是实现相对有规则的网格布局,瀑布流布局中,grid 布局不适用。其次,我们排除了 multi-column 这个 css3 属性。在呈现效果上看,multi-column 的确很好地满足了我们对于瀑布流布局的样式布局要求,但是,multi-column 本质上是将文档流分为多列,也就是我们在杂志、报刊常见的多列布局,最后呈现效果(如下图)实际上不满足我们对有序数据的展现要求,因此而排除。 最后我们的考虑范围只剩下 flex 布局,flex 布局在初始状态下的确很好地满足了我们对于数据的呈现效果,但是如果不加以数据干预,在默认非展开的情况下展开单个卡片,极端情况下会导致两列高度差过大,破坏了我们对于瀑布流的要求。 css 配合数据处理 综上所述,我们采用了 flex 布局加之对于使用者所传入的数据进行处理,达成了我们想要的效果。前端展现方面,我们还是通过 flex 布局,达成实际的瀑布流呈现效果,对于数据变化亦或是卡片展开时,我们再对数据进行进一步的处理,只有在初始化的时候,或者卡片状态发生改变的时候,对两列高度进行计算,保证两列保持较为稳定的高度差,进而实现瀑布流布局。 why BrickLayout g-emoji class="g-emoji" alias="sparkles" fallback-src="https://assets-cdn.github.com/images/icons/emoji/unicode/2728.png" style="box-sizing: border-box; font-family: "Apple Color Emoji", "Segoe UI", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 1.4em; font-weight: 400; line-height: 20px; vertical-align: middle;">✨/g-emoji>通过 BrickLayout 晓瀑布流使用者无须在关心实际的瀑布流布局实现,也无需关心前端的实际样式布局,更加专注于业务逻辑开发。未来的 BrickLayout 晓瀑布流将为使用者提供更加多样的模板,适用于不同场景之下的瀑布流布局。 [代码][代码] 插件使用案例 [图片]
2018-09-27 - 小程序中如何使用Crypto进行加解密
该插件完全前端化,无任何服务器端调用,请放心使用。如果不放心可用fiddler截取插件包查看相关源码。 登录微信公众平台 https://mp.weixin.qq.com,输入小程序账号密码。 [图片] 点击设置,打开第三方服务,点击添加插件。 [图片] 搜索 Crypto 或者 wxf25d506ff81e19fb [图片] 搜索结果出来后选中 Crypto ,点击添加。 [图片] 配置小程序app.json 加入 "plugins":{ "crypto":{ "version":"0.0.003", "provider":"wxf25d506ff81e19fb" } } 注: version填0.0.002也可使用,0.0.002没有 PBKDF2 加密方式及 RSA 非对称加解密方式 在小程序代码中声明引用 const crypto = requirePlugin("crypto"); 使用MD5加密 new crypto["MD5"]("布包云").toString(); 使用AES 进行加解密 const mi = new crypto.AES().encrypt('布包云', "BubaoCloud", { iv: 8, mode: crypto.Mode.CBC, padding: crypto.Padding.Pkcs7 }); console.log('encrypt:', mi.toString()); const v = new crypto.AES().decrypt(mi.toString(), "BubaoCloud", { iv: 8, mode: crypto.Mode.CBC, padding: crypto.Padding.Pkcs7 }); console.log('decrypt:', v.toString(crypto.Utf8));
2018-11-07 - 3D环物展示
小程序模拟3D环物展示效果 这是今年过年时正月初九制作,每年正月十一、十五、十六是我们揭阳的特色民俗,行头桥摸石狮。 那天正好有朋友回深圳,就做了这个小程序让其摸摸。 后来微信插件出来了,就在五月份整理成插件方便使用 [图片] [图片] [图片]
2019-03-01