- 2020-04-23
- input组件处于聚焦时,修改value导致触发bindinput的解决方案在安卓机型下,input组件处于聚焦时,修改value会导致触发bindinput 解决思路如下(不是具体代码) // 定义一个loading变量 var loading = false // 修改value时 changeValue() { loading = true //... } // 触发bindinput时,限制其执行 bindInput() { if (loading) return //... } // 触发bindfocus时,重置loading bindfocus() { loading = false } 2019-12-27
- [开盖即食]小程序Canvas官方新版API实战[图片] [图片] 最近本人在开发一个新项目的时候,注意到官方在2.9.0开始支持了一个canvas 2D的新API,同时对webGL上支持也有了很大的改进,相信很多人用canvas的组件做一些分享海报,战绩和新闻帖功能。 [图片] 这里是新的引入方式。 官方文档地址: https://developers.weixin.qq.com/miniprogram/dev/component/canvas.html 那么新的canvas2D API有啥好处呢? 原本的API微信有做一定的修改,现在全面支持源生H5 JS的写法,迁移H5的老代码变成更加容易,学习成本更低 修复了一些诡异的BUG,例如原本在IOS早期版本写法顺序会导致clip()图片裁切失效等~ 性能上的优化和提升,复杂动画上帧数明显 举例写法上的一些改变: 1、设置font的写法: [代码]//原本(传值的写法) ctx.setFontSize(20); ctx.fillText('MINA', 100, 100) ctx.draw() //现在(和源生H5写法一致,赋值) ctx.font = "16px"; ctx.fillStyle = 'blue'; //可以直接写颜色,原本的不支持 //不需要 ctx.draw() [代码] 2、获取并添加图片写法: [代码]//原本 //使用的是 wx.getImageInfo的方法 wx.getImageInfo({ src: mainImg,//服务器返回的图片地址 success: function (res) { console.log(res); ctx.drawImage(res.path, 0, 0); ctx.draw(true); }, fail: function (res) { //失败回调 } }); //现在 //可以直接img.onload调用 const headerImg = canvas.createImage(); headerImg.src = headImage;//微信请求返回头像 headerImg.onload = () => { ctx.save(); ctx.beginPath()//开始创建一个路径 ctx.arc(38, 288, 18, 0, 2 * Math.PI, false)//画一个圆形裁剪区域 ctx.clip()//裁剪 ctx.drawImage(headerImg,0,0); ctx.closePath(); ctx.restore(); } [代码] 3、将canvas生成虚拟地址便于下载(重点): [图片] 由于官方文档没有写清楚,误导了挺多人的。这里canvas对象必须通过选择器获取,并获得对应的node节点。 [代码]async saveImg() { let self = this; //这里是重点 新版本的type 2d 获取方法 const query = wx.createSelectorQuery(); const canvasObj = await new Promise((resolve, reject) => { query.select('#posterCanvas') .fields({ node: true, size: true }) .exec(async (res) => { resolve(res[0].node); }) }); console.log(canvasObj); wx.canvasToTempFilePath({ //fileType: 'jpg', //canvasId: 'posterCanvas', //之前的写法 canvas: canvasObj, //现在的写法 success: (res) => { console.log(res); self.setData({ canClose: true }); //保存图片 wx.saveImageToPhotosAlbum({ filePath: res.tempFilePath, success: function (data) { wx.showToast({ title: '已保存到相册', icon: 'success', duration: 2000 }) // setTimeout(() => { // self.setData({show: false}) // }, 6000); }, fail: function (err) { console.log(err); if (err.errMsg === "saveImageToPhotosAlbum:fail auth deny") { console.log("当初用户拒绝,再次发起授权") } else { util.showToast("请截屏保存分享"); } }, complete(res) { wx.hideLoading(); console.log(res); } }) }, fail(res) { console.log(res); } }, this) }, [代码] 分享个canvas海报的代码片段: [图片] 片段名: PoCf4emw7TgE 片段link: https://developers.weixin.qq.com/s/PoCf4emw7TgE [图片] [图片] 总结,相对之前还要看官方文档的canvas自定义API,现在写起来更加的方便,老代码迁移起来得心应手,只要你之前会canvas,那么各种效果和动画,拿来就怼,没什么大问题~ 一些奇怪的问题(注意!!!) canvas 2d 目前(2020年4月3日)还不支持真机调试,会报错!!! IDE工具 1.02.2003190 直接保存新版本canvas的API图片是打不开的,但是直接用手机保存在相册是没问题的,请更新到1.02.2003250 最新版即可解决~ 一些老款手机用新的API保存图片会有报错问题,如华为NOTE10,请更新系统到能支持的最新,且微信也是,即可解决~ 部分Android设备诡异的闪退和报错 [图片] 这种有可能是代码写法的问题,比如: [代码]//缺省写法 会导致部分Android机器 闪退 ctx.font = "bold 16px"; ctx.fillStyle = "#000" //在canvas 2D的写法中,所以写法必须规范且完整 ctx.font = "normal bold 12px sans-serif"; ctx.fillStyle = '#707070'; [代码] 所以在canvas 2D 的环境,所以写法必须原始且规范,不能用缺省写法,不然就会有诡异的闪退/报错。 后续:官方在7.0.13的Android版本已修复。 https://developers.weixin.qq.com/community/develop/doc/00088c13e1437890692afd8d85ec00 看完觉得有帮助记得点个赞哦~ 你的赞是我继续分享的最大动力!^-^ 2020-05-09
- 教你怎么监听小程序的返回键更新: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