- 分页,下拉加载数据问题?
下拉加载数据太大,导致当前页面销毁过慢怎么办
2023-06-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 - 如何实现快速生成朋友圈海报分享图
由于我们无法将小程序直接分享到朋友圈,但分享到朋友圈的需求又很多,业界目前的做法是利用小程序的 Canvas 功能生成一张带有小程序码的图片,然后引导用户下载图片到本地后再分享到朋友圈。相信大家在绘制分享图中应该踩到 Canvas 的各种(坑)彩dan了吧~ 这里首先推荐一个开源的组件:painter(通过该组件目前我们已经成功在支付宝小程序上也应用上了分享图功能) 咱们不多说,直接上手就是干。 [图片] 首先我们新增一个自定义组件,在该组件的json中引入painter [代码]{ "component": true, "usingComponents": { "painter": "/painter/painter" } } [代码] 然后组件的WXML (代码片段在最后) [代码]// 将该组件定位在屏幕之外,用户查看不到。 <painter style="position: absolute; top: -9999rpx;" palette="{{imgDraw}}" bind:imgOK="onImgOK" /> [代码] 重点来了 JS (代码片段在最后) [代码]Component({ properties: { // 是否开始绘图 isCanDraw: { type: Boolean, value: false, observer(newVal) { newVal && this.handleStartDrawImg() } }, // 用户头像昵称信息 userInfo: { type: Object, value: { avatarUrl: '', nickName: '' } } }, data: { imgDraw: {}, // 绘制图片的大对象 sharePath: '' // 生成的分享图 }, methods: { handleStartDrawImg() { wx.showLoading({ title: '生成中' }) this.setData({ imgDraw: { width: '750rpx', height: '1334rpx', background: 'https://qiniu-image.qtshe.com/20190506share-bg.png', views: [ { type: 'image', url: 'https://qiniu-image.qtshe.com/1560248372315_467.jpg', css: { top: '32rpx', left: '30rpx', right: '32rpx', width: '688rpx', height: '420rpx', borderRadius: '16rpx' }, }, { type: 'image', url: this.data.userInfo.avatarUrl || 'https://qiniu-image.qtshe.com/default-avatar20170707.png', css: { top: '404rpx', left: '328rpx', width: '96rpx', height: '96rpx', borderWidth: '6rpx', borderColor: '#FFF', borderRadius: '96rpx' } }, { type: 'text', text: this.data.userInfo.nickName || '青团子', css: { top: '532rpx', fontSize: '28rpx', left: '375rpx', align: 'center', color: '#3c3c3c' } }, { type: 'text', text: `邀请您参与助力活动`, css: { top: '576rpx', left: '375rpx', align: 'center', fontSize: '28rpx', color: '#3c3c3c' } }, { type: 'text', text: `宇宙最萌蓝牙耳机测评员`, css: { top: '644rpx', left: '375rpx', maxLines: 1, align: 'center', fontWeight: 'bold', fontSize: '44rpx', color: '#3c3c3c' } }, { type: 'image', url: 'https://qiniu-image.qtshe.com/20190605index.jpg', css: { top: '834rpx', left: '470rpx', width: '200rpx', height: '200rpx' } } ] } }) }, onImgErr(e) { wx.hideLoading() wx.showToast({ title: '生成分享图失败,请刷新页面重试' }) //通知外部绘制完成,重置isCanDraw为false this.triggerEvent('initData') }, onImgOK(e) { wx.hideLoading() // 展示分享图 wx.showShareImageMenu({ path: e.detail.path, fail: err => { console.log(err) } }) //通知外部绘制完成,重置isCanDraw为false this.triggerEvent('initData') } } }) [代码] 那么我们该如何引用呢? 首先json里引用我们封装好的组件share-box [代码]{ "usingComponents": { "share-box": "/components/shareBox/index" } } [代码] 以下示例为获取用户头像昵称后再生成图。 [代码]<button class="intro" bindtap="getUserInfo">点我生成分享图</button> <share-box isCanDraw="{{isCanDraw}}" userInfo="{{userInfo}}" bind:initData="handleClose" /> [代码] 调用的地方: [代码]const app = getApp() Page({ data: { isCanDraw: false }, // 组件内部关掉或者绘制完成需重置状态 handleClose() { this.setData({ isCanDraw: !this.data.isCanDraw }) }, getUserInfo(e) { wx.getUserProfile({ desc: "获取您的头像昵称信息", success: res => { const { userInfo = {} } = res this.setData({ userInfo, isCanDraw: true // 开始绘制海报图 }) }, fail: err => { console.log(err) } }) } }) [代码] 最后绘制分享图的自定义组件就完成啦~效果图如下: [图片] tips: 文字居中实现可以看下代码片段 文字换行实现(maxLines)只需要设置宽度,maxLines如果设置为1,那么超出一行将会展示为省略号 代码片段:https://developers.weixin.qq.com/s/J38pKsmK7Qw5 附上painter可视化编辑代码工具:点我直达,因为涉及网络图片,代码片段设置不了downloadFile合法域名,建议真机开启调试模式,开发者工具 详情里开启不校验合法域名进行代码片段的运行查看。 最后看下面大家评论问的较多的问题:downLoadFile合法域名在小程序后台 开发>开发设置里配置,域名为你图片的域名前缀 比如我文章里的图https://qiniu-image.qtshe.com/20190605index.jpg。配置域名时填写https://qiniu-image.qtshe.com即可。如果你图片cdn地址为https://aaa.com/xxx.png, 那你就配置https://aaa.com即可。
2022-01-20 - 如何实现一个简单的http请求的封装
好久没发文章了,最近浏览社区看到比较多的请求封装,以及还有在使用原始请求的童鞋。为了减少代码,提升观赏性,我也水一篇吧,希望对大家有所帮助。 默认请求方式,大家每次都这样一些写相同的代码,会不会觉得烦,反正我是觉得头大 😂 [代码]wx.request({ url: 'test.php', //仅为示例,并非真实的接口地址 data: { x: '', y: '' }, header: { 'content-type': 'application/json' // 默认值 }, success (res) { console.log(res.data) } }) [代码] 来,进入正题吧,把这块代码封装下。 首先新建个request文件夹,内含request.js 代码如下: [代码]/** * 网络请求封装 */ import config from '../config/config.js' import util from '../util/util.js' // 获取接口地址 const _getPath = path => (config.DOMAIN + path) // 封装接口公共参数 const _getParams = (data = {}) => { const timestamp = Date.now() //时间戳 const deviceId = Math.random() //随机数 const version = data.version || config.version //当前版本号,自定或者取小程序的都行 const appKey = data.appKey || config.appKey //某个小程序或者客户端的字段区分 //加密下,防止其他人随意刷接口,加密目前采用的md5,后端进行校验,这段里面的参数你们自定,别让其他人知道就行,我这里就是举个例子 const sign = data.sign || util.md5(config.appKey + timestamp + deviceId) return Object.assign({}, { timestamp, sign, deviceId, version, appKey }, data) } // 修改接口默认content-type请求头 const _getHeader = (headers = {}) => { return Object.assign({ 'content-type': `application/x-www-form-urlencoded` }, headers) } // 存储登录态失效的跳转 const _handleCode = (res) => { const {statusCode} = res const {msg, code} = res.data // code为 4004 时一般表示storage里存储的token失效或者未登录 if (statusCode === 200 && (code === 4004)) { wx.navigateTo({ url: '/pages/login/login' }) } return true } /** * get 请求, post 请求 * @param {String} path 请求url,必须 * @param {Object} params 请求参数,可选 * @param {String} method 请求方式 默认为 POST * @param {Object} option 可选配置,如设置请求头 { headers:{} } * * option = { * headers: {} // 请求头 * } * */ export const postAjax = (path, params) => { const url = _getPath(path) const data = _getParams(params) //如果某个参数值为undefined,则删掉该字段,不传给后端 for (let e in data) { if (data[e] === 'undefined') { delete data[e] } } // 处理请求头,加上最近比较流行的jwtToken(具体的自己百度去) const header = util.extend( true, { "content-type": "application/x-www-form-urlencoded", 'Authorization': wx.getStorageSync('jwtToken') ? `Bearer ${wx.getStorageSync('jwtToken')}` : '', }, header ); const method = 'POST' return new Promise((resolve, reject) => { wx.request({ url, method, data, header, success: (res) => { const result = _handleCode(res) result && resolve(res.data) }, fail: function (res) { reject(res.data) } }); }) } [代码] 那么如何调用呢? [代码]//把request的 postAjax注册到getApp()下,调用时: const app = getApp() let postData = { //这里填写请求参数,基础参数里的appKey等参数可在这里覆盖传入。 } app.postAjax(url, postData).then((res) => { if (res.success) { //这里处理请求成功逻辑。 } else { //wx.showToast大家觉得麻烦也可以写到util.js里,调用时:util.toast(msg) 即可。 wx.showToast({ title: res.msg || '服务器错误,请稍后重试', icon: "none" }) } }).catch(err => { //这里根据自己场景看是否封装到request.js里 console.log(err) }) [代码] config.js 主要是处理正式环境、预发环境、测试环境、开发环境的配置 [代码]//发版须修改version, env const env = { dev: { DOMAIN: 'https://dev-api.weixin.com' }, test: { DOMAIN: 'https://test-api.weixin.com', }, pro: { DOMAIN: 'https://api.qtshe.com' } } module.exports = { ...env.pro } [代码] 以上就是简单的一个request的封装,包含登录态失效统一跳转、包含公共参数的统一封装。 老规矩,最后放代码片段,util里内置了md5方法以及深拷贝方法,具体的我也不啰嗦,大家自行查看即可~ https://developers.weixin.qq.com/s/gbPSLOmd7Aft
2020-04-03 - 如何实现一个带图标的actionSheet效果
刚才有童鞋询问如何给actionSheet前加图标,然鹅官方没提供该效果,那么我们自己做一个定制化的actionSheet吧。 还是那句话,有需求,咱们有空就去实现下,也算是能锻炼自己的动手能力,提升点知识面。。 先看看实现后的效果图: [图片] 首先自定义actionSheet组件。 wxml 简单的页面布局。 [代码]<view class="qts-as-mask qts-class-mask {{ visible ? 'qts-as-mask-show' : '' }}" bindtap="handleClickMask" catchtouchmove="preventTouchmove" ></view> <view class="qts-class qts-as {{ visible ? 'qts-as-show' : '' }}" catchtouchmove="preventTouchmove"> <view class="qts-as-header qts-class-header"> <slot name="header"></slot> </view> <view class="qts-as-actions"> <view class="qts-as-action-item" wx:for="{{actions}}" wx:key="name"> <button hover-class="none" bindtap="handleClickItem" data-index="{{index}}" open-type="{{item.openType}}" class="qts-as-btn-qts ptp_exposure" > <image wx:if="{{item.icon}}" src="{{item.icon}}" class="qts-btn-image" /> <view class="qts-as-btn-text">{{item.name}}</view> </button> </view> </view> <view class="qts-as-cancel" wx:if="{{showCancel}}"> <button hover-class="none" class="qts-as-cancel-btn" bindtap="handleClickCancel">取消</button> </view> </view> [代码] js处理: 定制了三种功能: 是否需要隐藏取消按钮 是否需要点击蒙层关闭actionSheet 内容外部组件可配置 [代码]Component({ externalClasses: ['qts-class', 'qts-class-mask', 'qts-class-header'], options: { multipleSlots: true }, properties: { showCancel: { type: Boolean, value: true }, visible: { type: Boolean, value: false }, actions: { type: Array, value: [] }, maskClosable: { type: Boolean, value: true } }, methods: { handleClickMask() { if (!this.data.maskClosable) return; this.handleClickCancel(); }, preventTouchmove() {}, handleClickItem(e) { const dataset = e.currentTarget.dataset || '' this.triggerEvent('click', dataset) this.triggerEvent('cancel'); }, handleClickCancel() { this.triggerEvent('cancel'); } } }) [代码] 应用的页面引用该组件: [代码]<view class="container" bindtap="handleClick">点我弹出actionSheet</view> <!-- visible 弹窗显隐藏 show-cancel 是否显示取消按钮 bind:cancel 取消按钮点击回调 bind:click 单个item点击回调 mask-closable 点击蒙层是否关闭弹窗 --> <action-sheet visible="{{visible}}" actions="{{actions}}" show-cancel bind:cancel="handleClick" bind:click="handleClickItem" mask-closable="{{true}}" /> [代码] [代码]const app = getApp() Page({ data: { //可配置items选项,支持传入button的openType属性 actions: [{ name: '生成图片', icon: 'https://qiniu-image.qtshe.com/201809104.png' }, { name: '转发给好友或群聊天', icon: 'https://qiniu-image.qtshe.com/201809105.png', openType: 'share' } ], visible: false }, //弹窗显隐藏 handleClick() { this.setData({ visible: !this.data.visible }) }, //单个item点击 //actionsheet内的点击方法 handleClickItem({detail}) { if (detail.index === 0) { console.log(111) //第一个选项被点击 } }, }) [代码] 以上就是一个自定义actionSheet的实现方式以及引用方式。。 老规矩,附上代码片段。 https://developers.weixin.qq.com/s/Bhc0Sjmw7AgW
2020-05-26 - 如何使用canvas绘制签名板?
场景分析在小程序业务中如需用户进行手写签名的场景如:寄快递,签约合同时需要在小程序中进行手写签名。 处理方法 实现原理运用 canvas 监听用户 touch 事件,然后在 canvas 上画出与 touch 事件相近的线模仿手写签名效果。 实现方法参考如下代码片段:https://developers.weixin.qq.com/s/MYDTQAmR7EIa [图片]
09-09