- 微信公众号授权的redirect_url中有#,但是为什么在重定向回来的时候#后的内容到参数中去了?
授权地址 https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx60277b2a075ec3b9&redirect_uri=http%3A%2F%2Fwap2.papasportdev.net%2F%23%2Fpages%2Fbase%2Flogin&response_type=code&scope=snsapi_userinfo&state=gotoUrl%3Dhttp%5C%3A%2F%2Fwap2.papasportdev.net%2F%5C%23%2Fpages%2Fbase%2Flogin%3Fnull%0A&uin=NDM3MzE5Mjc1&key=3f1564dfc265cd440443ed667f2333174c4fd48cf6b64b995318f390c720511594cbc96f87270d1747f004376a0ae4e1&pass_ticket=+FDtGw6S8kVFikFhGzL1EPUh3/a0f4/QVT/wgYmIdKLVdKwySeNMLv7/plWHqq+4CTk07n+FDvy2463chd6LNw== 重定向回来之后的地址 http://wap2.papasportdev.net/?code=071vu2mh2tu5rD0Z5aih2gOGlh2vu2mc&state=gotoUrl%3Dhttp%5C%3A%2F%2Fwap-api2.papasportdev.net%2Fweb%2Fexterface%2Fexecute%2Fuser%2FuserLoginInit%3Fnull%0A#/pages/base/login 正常的应该是 http://wap2.papasportdev.net/#/pages/base/login?code=071vu2mh2tu5rD0Z5aih2gOGlh2vu2mc&state=gotoUrl%3Dhttp%5C%3A%2F%2Fwap-api2.papasportdev.net%2Fweb%2Fexterface%2Fexecute%2Fuser%2FuserLoginInit%3Fnull%0A 请问这个要怎么配置
2020-05-20 - 关于小程序文件下载并保存到本地的功能?
目前小程序要做保存excel、pdf等文件的功能, 我调用了wx.downFile,然后再调用saveFile,直接是走进了saveFile的success函数,但是保存的文件去哪里打开呢,还是说这个保存并不是保存到手机上? 还是说,现在的小程序并不支持保存文件到手机上(不是临时保存,是可以在退出小程序后再次在手机中找到并且打开) wx.downloadFile({ url: item.url, // filePath: wx.env.USER_DATA_PATH + '/' + item.fullName, success (res) { if (res.statusCode === 200) { wx.hideLoading() // let tempFilePath = res.filePath // 如果设置了filePath参数,则不会有tempFilePath let tempFilePath = res.tempFilePath wx.saveFile({ tempFilePath, success (res) { // 可以进行到这里 console.log(res); const savedFilePath = res.savedFilePath wx.showToast({ title: '下载成功', icon: 'none', mask: true }) }, fail (err) { console.log(err); wx.showToast({ title: '下载失败,请重新尝试', icon: 'none', mask: true }) } }) } } })
2020-04-01 - 注册小程序使用的营业执照公司名称变更了,怎么同步小程序主体?
准备相关资料,提单同步主体即可。 1、小程序帐号 2、帐号的营业执照或者组织机构代码证: 3、法人/运营者/提交人的手持身份证照 4、变更后的主体名称: 5、变更后的相关营业执照或者组织机构代码证: 6、工商局变更证明: 手机微信端提单链接:https://kf.qq.com/touch/bill/171208selfqaa5952b5e.html
2019-08-30 - 小程序转让
乐店蜂抢社交电商小程序,四川省成都市武侯区品牌代理权以及小程序一起转让,图片是公司的西安站点,本地运营的话有公司总部帮忙,现在小程序已经接入了全国的加油站,电影院以及肯德基,价格有绝对优势,平台可以自己售卖全国包邮的商品,入驻的商家也可以售卖自己店铺的商品,商家在平台也可以做外卖,跟美团有合作的,商家可以自己选择自己配送或者让外卖员配送,因为在山东还有其它事情要做,顾不上这边,现将品牌代理权和小程序一起转让,有意私聊[图片][图片][图片][图片]
2021-01-13 - 如何主动退出小程序
有没有点击按钮可以退出小程序的api?
2017-01-12 - 短信验证框
效果图 [图片] 1.组件 js Component({ properties: { // 输入框的数量 inputLength: { type: Number, value: 4 }, // 单个输入框的宽度 inputWidth: { type: String, value: '58rpx' }, inputHeight: { type: String, value: '58rpx' }, // 是否显示输入的值,默认隐藏 showValue: { type: Boolean, value: false }, //提示文字 tipText: { type: String, value: '请输入验证码' }, //手机号码 phone: { type: String, value: '' }, //手机号码提示 phoneTip: { type: String, value: '已发送到:' }, //是否显示倒计时 showMask:{ type:Boolean, value:false }, //倒计时 countDown:{ type:Number, value:5 }, //是否已发送验证码 alreadySend:{ type:Boolean, value:false } }, data: { // input是否获取焦点 inputFocus: true, // 初始input值为空 currentValue: '', }, methods: { //请稍后再试 pleaseWait:function(){ wx.showToast({ title: '请稍后再试', }) }, //重新发送验证码 reSendCode:function(){ this.triggerEvent('reSendCode',{value:true}) }, closeMask: function () { this.setData({ showMask: false,currentValue:'' }) this.triggerEvent('closeMask',{value:false},{bubbles:true,composed:true}) }, showView({ phone }) { var mPhone = phone.substr(0, 3) + '****' + phone.substr(7); this.setData({ phone: mPhone, }) }, // 设置当前的值 _setCurrentValue(e) { // 在此处判断满6(inputLength)位,把值返回给上级父组件或页面 let currentValue = e.detail.value // 改变时,派发一个事件,如果父组件或页面中需要实时获取改变后的值,可以监听这个事件。 this.triggerEvent('change', e.detail.value) this.setData({ currentValue }) if (currentValue.length >= this.data.inputLength) { this._complate() return } }, // 点击伪装的input时,让隐藏的input获得焦点 _focusInput() { this.setData({ inputFocus: true }) console.log(this.data.inputFocus) }, _complate() { this.triggerEvent('inputComplate', this.data.currentValue) }, // 提供给外部调用的方法,显示/隐藏密码。接收一个参数,可以显性修改展示的状态。 toggleValue(state) { this.setData({ showValue: state != undefined ? state : !this.data.showValue }) }, // 清除input当前的值 clearCurrentValue() { this.setData({ currentValue: '' }) }, //确认按钮 tapConfirm() { let value = this.data.currentValue if (value.length < this.data.inputLength) { return } this.triggerEvent('confirm', value) this.closeMask() }, }, ready: function (e) { var phone = this.data.phone; this.setData({ phone: phone.substr(0, 3) + '****' + phone.substr(7) }) } }) json { "component": true } wxml {{tipText}} {{phoneTip}}{{phone}} {{currentValue.length>=index+1?currentValue[index]:''}} 重新发送({{countDown}}s) 重新发送 确定 wxss .password-box .password-wrapper { margin-top: 20rpx; display: flex; justify-content: center; align-items: center; } .password-box .password-item { position: relative; display: flex; justify-content: center; align-items: center; } .password-box .password-item::after { display: block; content: ''; position: absolute; top: 0; left: 0; border: 1px solid #D8D8D8; box-sizing: border-box; width: 200%; height: 200%; border-radius: 4rpx; transform: scale(0.5); transform-origin: left top; } .password-box .password-item + .password-item { margin-left: 44rpx; } .password-box .password-wrapper .hidden { width: 14rpx; height: 14rpx; border-radius: 50%; background: #999; } .password-box .password-wrapper .show { color: #1a88f9; } .password-box .hidden-input { width: 1px; height: 0; min-height: 0; } .mask{ position: fixed; top: 0; left: 0; display: flex; justify-content: center; background: rgba(0, 0, 0, 0.4); height: 100vh; width: 100vw; z-index: 1000; } .set-password { position: absolute; top:35vh; display: flex; flex-direction: column; align-items: center; width: 540rpx; padding-bottom: 20rpx; height: auto; background: #ffffff; border-radius: 10rpx; } .tip { position: relative; top: -80rpx; text-align: center; height: 43rpx; font-size: 32rpx; font-family: MicrosoftYaHeiSemibold; font-weight: 800; text-align: center; color: #333333; line-height: 43rpx; } .close_view_reverse{ width:100%; display: flex; flex-direction: row-reverse; } .close_view{ display: flex; flex-direction: row-reverse; height: 100rpx; width: 100rpx; padding:10rpx 10rpx 0 0; } .divider_line{ position: relative; top:-20rpx; width: 540rpx; height: 1px; background-color: #f0f1f1; } .btn-next { background: #1a88f9; border-radius: 110rpx; box-shadow: 0px 4rpx 10rpx 0rpx rgba(0,0,0,0.1); box-sizing: border-box; margin: 0 auto 0; width: 260rpx; height: 70rpx; line-height: 70rpx; text-align: center; color: #fff; background: #d8d8d8; } .btn-next-active { background: #1A88F9; } .verify-content{ position: relative; top: -70rpx; text-align: center; height: 30rpx; font-size: 24rpx; color: #C5C5C5; } .text_countDown{ position: relative; top: -50rpx; height: 30rpx; font-size: 22rpx; text-decoration: underline; text-align: center; color: #999999; line-height: 30rpx; } .c_flex{ display: flex; align-items:center; } 组建中用到的图片 ---------图片在中间------------ [图片] -----------图片在中间----------- 2.页面调用组件 index.js //index.js //获取应用实例 const app = getApp() Page({ data: { showMask: false, countDown: 60,//倒计时时间s alreadySend: false,//验证码是否发送 clearInterval: false,//释放interval重置倒计时 }, onLoad: function () { }, onShow: function () { this.dialogVCode = this.selectComponent('#dialogVCode') }, //显示验证码提示框 getVCode: function () { //显示验证码框 this.setData({ showMask: true, countDown: 60, alreadySend: true, clearInterval: false }) //开启倒计时 this.timer() //传入手机号码 this.dialogVCode.showView({ phone: '18855556666' }) }, //验证码倒计时 timer: function () { if (!this.data.showMask) return let promise = new Promise((resolve, reject) => { let setTimer = setInterval( () => { this.setData({ countDown: --this.data.countDown }) if (this.data.countDown <= 0) { this.setData({ countDown: 60, alreadySend: false }) resolve(setTimer) } else { //关闭验证码框后重新点击按钮时,释放上一个正在执行的setInterval if (this.data.clearInterval) { resolve(setTimer) } } }, 1000) }) promise.then((setTimer) => { clearInterval(setTimer) }) }, //重新发送 reSendCode: function (e) { console.log('重新发送验证码', e.detail.value) wx.showToast({ title: '验证码已发送', }) this.setData({ alreadySend: e.detail.value, countDown: 60 }) this.timer() //调用发送验证码接口 }, //自定义验证码弹框的确定 verifyCodeConfirm(e) { console.log('验证码弹框的确定', e.detail) //确定后重新计时 this.setData({ countDown: 60, clearInterval: true, alreadySend: false }) }, //关闭验证码提示框 closeMask: function (e) { console.log('验证码关闭按钮', e.detail.value) this.setData({ showMask: e.detail.value, clearInterval: true }) }, }) index.json { "usingComponents": { "dialog-vccode":"/component/dialog-vccode/dialog-vccode" } } index.wxml 点击获取验证码 index.wxss .c_flex_center{ display: flex; justify-content: center; align-items: center; width: 100vw; height: 100vh; }
2020-12-30 - 小程序内解析富文本的几种方案
小程序内解析富文本的几种方案 ~ 1)mp-hml https://github.com/ixiaofeiyang/mp-html 2)wxparse https://github.com/icindy/wxParse 3)html2wxml 参考文档 1)如何在小程序内部展示富文本? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/00060a0c9e0070ae970aa1d605b013 2)请问小程序怎么解析一个完整的H5页面?? - 微信开放社区 https://developers.weixin.qq.com/community/develop/doc/000c44e36187d8e2787b9480b59400
2020-12-28 - rich-text解析富文本无法添加事件解决办法
官方rich-text解析富文本无法添加节点事件[图片] 偶然间发现大哥写的一个插件 => https://github.com/jin-yufeng/Parser,简单实用,亲测,轻松解决解析富文本存在的一些问题!!!
2020-12-18 - 简单实现签到日历效果
wxml: <view class="box"> <view class="section"> <picker mode="date" value="{{date}}" fields="month" start="2010-01-01" end="{{cy+'-'+cm}}" bindchange="bindDateChange"> <view class="picker">{{cur_year || "--"}} 年 {{cur_month || "--"}} 月</view> </picker> </view> <view> <!-- 显示星期 --> <view class="week color9b"> <view wx:for="{{weeks_ch}}" wx:key="unique">{{item}}</view> </view> <view class='days'> <!-- 行 --> <view class="rows" wx:for="{{days.length/7}}" wx:for-index="i" wx:key="unique"> <!-- 列 --> <view class="columns" wx:for="{{7}}" wx:for-index="k" wx:key="unique"> <!-- 每个月份的空的单元格 --> <view class='cell' wx:if="{{days[7*i+k].date == null}}"> <text decode="{{true}}"> </text> </view> <!-- 每个月份的有数字的单元格 --> <view class='cell' wx:else> <!-- 当前日期已签到 --> <view wx:if="{{days[7*i+k].isSign == true}}" class='qianbg'> <text class="colorff">{{days[7*i+k].date}}</text> <text class="sourse">+{{days[7*i+k].Score}}</text> </view> <!-- 当前日期未签到 --> <view wx:else> <text>{{days[7*i+k].date}}</text> </view> </view> </view> </view> </view> </view> </view> 简单提下思路,首先默认确定当前年月,cy cm, 初始化:获取days遍历日历的格子,通过获取当前月第一天是星期几来判断前面有几个空格,放入days,再当月天数放入days,然后进行渲染,再通接口去拿签到信息,签到成功的突出显示。这里签到初始化时我默认给了标识isSign,将已签到列表和当前年月日进行比较,符合条件则更新签到状态。切换选择日期,这里我用的是选择器,当然可以写成点击左侧按钮上一月,右侧按钮下一月那种,重新选择日期后,initdata(e) 传入年月,就是当前选择年月的数据。将星期日作为第一日的我也备注上去了。样式根据自己的喜好改就行了,最后看看我写的两个项目效果: [图片][图片] 写了个demo:https://developers.weixin.qq.com/s/SSlwjGmb7Wm9
08-14 - (4)获取用户信息
背景 我们发现大部分小程序都会使用 [代码]wx.getUserInfo[代码] 接口,来获取用户信息。原本设计这个接口时,我们希望开发者在真正需要用户信息的情况下才去调取这个接口,但很多开发者会直接调用这个接口,导致用户在使用小程序的时候产生困扰,归结起来有几点: 开发者在小程序首页直接调用 [代码]wx.getUserInfo[代码] 进行授权,弹框获取用户信息,会使得一部分用户点击“拒绝”按钮。 在开发者没有处理用户拒绝弹框的情况下,用户必须授权头像昵称等信息才能继续使用小程序,会导致某些用户放弃使用该小程序。 用户没有很好的方式重新授权,尽管我们增加了[代码]设置[代码]页面,可以让用户选择重新授权,但很多用户并不知道可以这么操作。 此外,我们发现开发者默认将 [代码]wx.login[代码] 和 [代码]wx.getUserInfo[代码] 绑定使用,这个是由于我们一开始的设计缺陷和实例代码导致的([代码]wx.getUserInfo[代码] 必须通过 [代码]wx.login[代码] 在后台生成 [代码]session_key[代码]后才能调用)。同时,我们收到开发者的反馈,希望用户进入小程序首页便能获取到用户的 [代码]unionId[代码],以便识别到用户是否以前关注了同主体公众号或使用过同主体的App 。 为了解决以上问题,针对获取用户信息我们更新了三个能力: 1.使用组件来获取用户信息 2.若用户满足一定条件,则可以用[代码]wx.login[代码] 获取到的[代码]code[代码]直接换到[代码]unionId[代码] 3.[代码]wx.getUserInfo[代码] 不需要依赖 [代码]wx.login[代码] 就能调用得到数据 获取用户信息组件介绍 [代码][代码] 组件变化: [代码]open-type [代码]属性增加 [代码]getUserInfo[代码] :用户点击时候会触发 [代码]bindgetuserinfo[代码] 事件。 新增事件 [代码]bindgetuserinfo[代码] :当 [代码]open-type[代码]为 [代码]getUserInfo[代码] 时,用户点击会触发。可以从事件返回参数的 [代码]detail[代码] 字段中获取到和 [代码]wx.getUserInfo[代码] 返回参数相同的数据。 示例: [代码]<button open-type="getUserInfo" bindgetuserinfo="userInfoHandler"> Click me button>[代码]和 [代码]wx.getUserInfo[代码] 不同之处在于: 1.API [代码]wx.getUserInfo[代码] 只会弹一次框,用户拒绝授权之后,再次调用将不会弹框; 2.组件 [代码][代码][代码][代码] 由于是用户主动触发,不受弹框次数限制,只要用户没有授权,都会再次弹框。 通过获取用户信息的组件,就可以解决用户再次授权的问题。 直接获取unionId开发者申请 [代码]userinfo[代码] 授权主要为了获取 [代码]unionid[代码],我们鼓励开发者在不骚扰用户的情况下合理获得[代码]unionid[代码],而仅在必要时才向用户弹窗申请使用昵称头像。为此,凡使用“获取用户信息组件”获取用户昵称头像的小程序,在满足以下全部条件时,将可以静默获得 [代码]unionid[代码]: 1.在微信开放平台下存在同主体的App、公众号、小程序。 2.用户关注了某个相同主体公众号,或曾经在某个相同主体App、公众号上进行过微信登录授权。 这样可让其他同主体的App、公众号、小程序的开发者快速获得已有用户的数据。 不依赖登录的用户信息获取某些工具类的轻量小程序不需要登录行为,但是也想获取用户信息,那么就可以在 [代码]wx.getUserInfo[代码] 的时候加一个参数 [代码]withCredentials: false[代码] 直接获取到用户信息,可以少一次网络请求。 这样可以在不给用户弹窗授权的情况下直接展示用户的信息。 最佳实践 1.调用 [代码]wx.login[代码] 获取 [代码]code[代码],然后从微信后端换取到 [代码]session_key[代码],用于解密 [代码]getUserInfo[代码]返回的敏感数据。 2.使用 [代码]wx.getSetting[代码] 获取用户的授权情况 1) 如果用户已经授权,直接调用 API [代码]wx.getUserInfo[代码] 获取用户最新的信息; 2) 用户未授权,在界面中显示一个按钮提示用户登入,当用户点击并授权后就获取到用户的最新信息。 3.获取到用户数据后可以进行展示或者发送给自己的后端。 One More Thing 除了获取用户方案介绍之外,再聊一聊很多初次接触微信小程序的开发者所不容易理解的一些概念: 1.关于OpenId和UnionId [代码]OpenId[代码] 是一个用户对于一个小程序/公众号的标识,开发者可以通过这个标识识别出用户。 [代码]UnionId[代码] 是一个用户对于同主体微信小程序/公众号/APP的标识,开发者需要在微信开放平台下绑定相同账号的主体。开发者可通过[代码]UnionId[代码],实现多个小程序、公众号、甚至APP 之间的数据互通了。 同一个用户的这两个 ID 对于同一个小程序来说是永久不变的,就算用户删了小程序,下次用户进入小程序,开发者依旧可以通过后台的记录标识出来。 2.关于 getUserInfo 和 login 很多开发者会把 [代码]login[代码] 和 [代码]getUserInfo[代码] 捆绑调用当成登录使用,其实 [代码]login[代码] 已经可以完成登录,[代码]getUserInfo[代码] 只是获取额外的用户信息。 在 [代码]login[代码] 获取到 [代码]code[代码] 后,会发送到开发者后端,开发者后端通过接口去微信后端换取到 [代码]openid[代码] 和[代码]sessionKey[代码](现在会将 [代码]unionid[代码] 也一并返回)后,把自定义登录态 [代码]3rd_session[代码]返回给前端,就已经完成登录行为了。而 [代码]login[代码] 行为是静默,不必授权的,用户不会察觉。 [代码]getUserInfo[代码] 只是为了提供更优质的服务而存在,比如展示头像昵称,判断性别,开发者可通过 [代码]unionId[代码] 和其他公众号上已有的用户画像结合来提供历史数据。因此开发者不必在用户刚刚进入小程序的时候就强制要求授权。 可以在官方的文档中看到 [代码]login[代码] 的最佳实践: [图片] Q & A Q1: 为什么 login 的时候不直接返回 openid,而是要用这么复杂的方式来经过后台好几层处理之后才能拿到? A: 为了防止坏人在网络链路上做手脚,所以小程序端请求开发者服务器的的请求都需要二次验证才是可信的。因为我们采取了小程序端只给 [代码]code[代码] ,由服务器端拿着 [代码]code[代码] 和 [代码]AppSecrect[代码] 去微信服务器请求的方式,才会给到开发者对应的[代码]openId[代码] 和用于加解密的 [代码]session_key。[代码] Q2: 既然用户的[代码]openId[代码] 是永远不变的,那么开发者可以使用[代码]openId[代码] 作为用户的登录态么? A: 不行,这是非常危险的行为。因为 [代码]openId[代码] 是不变的,如果有坏人拿着别人的 [代码]openId[代码] 来进行请求,那么就会出现冒充的情况。所以我们建议开发者可以自己在后台生成一个拥有有效期的 [代码]第三方session[代码] 来做登录态,用户每隔一段时间都需要进行更新以保障数据的安全性。 Q3: 是不是用户每次打开小程序都需要重新[代码]login[代码]? A: 不必,可以将登录态存入[代码]storage[代码]中,用户再次登录就可以拿[代码]storage[代码] 里的登录态做正常的业务请求,只有当登录态过期了之后才需要重新[代码]login[代码] 。这样子做一则可以减少用户等待时间,二则可以减少网络带宽。 目前微信的[代码]session_key[代码] 有效期是三天,所以建议开发者设置的登录态有效期要小于这个值。
2018-08-17 - 小程序应用如何实现扫码支付?
场景: 客人到店,门店工作人员在小程序帮客户下单,最后结款时调用 扫一扫 对准客户 付款码,扫码收款,完成订单。
2020-12-15 - 请问不同app_id的小程序下,open_id可能相同吗?
现在公司产品,可能会集团产生一个app,集团下单店产生一个,现在需求是希望通过open_id找用户时,如果单店找不到就去集团找,但这有个前提,不同app下的open_id是否有相同的可能,如果有那就不能这么做。请解答下
2020-10-23 - 域名已备案,微信打开网站还提示“非微信官方网页,请确认是否继续访问。”?
两个域名已备案;也提交申请恢复了;但是还是提示;域名是:dnsto.cc和bdlm.cc;请领导通过一下主域名及子域名;谢谢!
2020-10-12 - 微信登录,用来扫码授权的二维码有效期多久
https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html
2020-07-30 - 关于video如何禁止拖动进度条呢?
不能controls为false也不能使show progres 因为那样没有时间不知道播放到哪里了
2020-03-03 - (14)腾讯视频插件
想要在自己的电商小程序中增加商品介绍视频,但自己搭建视频服务开发成本太大? 想要在餐饮服务中添加菜品视频,但苦于带宽成本过高? 想要在门票预订服务中用视频打动用户,但视频资质申请流程太长? 腾讯视频插件来帮你~ 今天,我们跟大家分享腾讯视频插件的故事。 腾讯视频插件提供了完整视频播放能力,方便开发者可以给用户提供更好的视频体验。 插件基于腾讯视频的CDN节点和成熟视频方案,可以做到为不同地点的用户提供更流畅的播放服务,更清晰的视频,更稳定的播放质量。只需要视频的vid,开发者即可直接在小程序内播放腾讯视频上的内容! 腾讯视频插件使用场景 场景一:电商类小程序 除了对商品的语言描述,实惠的价格,精美的图片,也需要生动直观、360度动态介绍商品,比单一的图片更能引起消费者的好感。 现在,在商品介绍里直接链入相关商品视频。比如,买衣服的电商小程序,可以把电视或电影中明星穿过的同款视频链入,在满足用户感官享受的同时,提升转化率。 场景二:文娱推荐类小程序 不局限于苍白的文字描述,推荐类小程序也可在小程序中添加电影视频、预告片,为用户带来完美的购票、观影体验。开发者无需独立开发视频功能,直接使用“腾讯视频”插件,即可实现视频播放功能。 [图片] 场景三:资讯类小程序 “腾讯视频”插件还可以是内容创作者的一大利器,以游戏攻略类小程序为例。小程序就可以直接用视频的形式展现,一方面清晰明了地展示攻略流程,同时也增加了用户在小程序内的停留时长,进一步引导用户做更多动作。 或者生活居家小技巧类的小程序,比如想教大家一种打结的方式,纯文字的形式即很难说清楚,又浪费内容运营者的时间,这时候直接使用插件链入视频,就能很快地教会大家,给予用户更好的内容体验。 轻松接入腾讯视频插件 “腾讯视频”提供了这么多的功能,使用起来也同样很方便: 1 在“小程序管理后台→设置→第三方服务→插件管理”中查找插件名称“腾讯视频”,并申请使用。 [图片] 2 参考详情页中的 [开发文档],在小程序代码中使用插件。 了解完“腾讯视频”插件后,还想看看其他小程序是如何实际运用的?一起来体验一下 腾讯+ ! [图片] 页面视频服务是由腾讯视频插件提供
2018-08-17 - input键盘弹出时,滚动页面,输入框内容错位问题
在ios9.+的版本上,遇到了一个问题。在键盘弹出的时候,快速滚动页面,输入的内容或input提示语会错位。且有时无法恢复到原有位置。当然,前提是你这个页面是超过一屏需要滚动的时候 [图片] 解决办法: always-embed=true [图片]
2022-04-18 - 微信小程序增加了OCR功能审核能通过吗?
增加OCR功能后,第一次提交审核,经过四天半的审核,最后通知不通过,不通过原因是涉及收集用户敏感信息,查看代码,确实是我有信息上传按钮,将数据上传到云存储(这里确实有此需求的);第二次我将存储按钮去掉,其他代码不变,仅仅只有识别功能,结果还是审核不通过。想问一下各位大神,有没有使用OCR功能的,审核通过了吗?有什么需要注意的地方?
2019-12-31 - 小程序跳转页面加载优化
适应场景: 小程序页面跳转redirect/navigate/其它方式 分析: 从用户触发跳转行为到下一个页面onload生命周期函数内时间差会有500ms左右,如果在页面跳转之后进行onload函数内才开始去加载页面数据,那么这500ms左右的时间就浪费了。 改进: 在页面触发跳转行为的处理函数里结合promise预先加载下个页面的数据,并将promise对象缓存,此时页面跳转和加载数据同时进行,到了目标页面再取出缓存的promise对象进行判断和取数据操作。 效果: 跳转页面加载速度提高了600ms。 示例: 代码结构 [图片] pageManager.js [代码]// 写在utils里的公用方法 const pageList = {}; module.exports = { putData:function(pageName, data){ pageList[pageName] = data; }, getData:function(pageName){ return pageList[pageName]; } } [代码] util.js [代码]const myPromise = fn => obj => { return new Promise((resolve, reject) => { obj.complete = obj.success = (res) => { resolve(res); } obj.fail = (err) => { reject(err); } fn(obj); }) } module.exports = { myPromise : myPromise } [代码] index.js [代码]// 跳转页面 const {myPromise} = require('../../utils/util'); const pageManager = require('../../utils/pageManager'); page({ data: { }, onLoad:function(){ }, gotoPageA:function(){ const PromisePageA = myPromise(wx.request)({ url : '' }).then((res)=>{ return res.data; }) pageManager.putData('pageA',promisePageA); wx.navigateTo({ url: 'pages/pageA/pageA' }) } }) [代码] pageA.js [代码]// 被跳转页面 const util = require('../../utils/util.js'); const pageManager = require('../../utils/pageManager'); const {myPromise} = require('../../utils/util'); Page({ data:{ logs:[] }, onLoad: function(){ const promisePageA = pageManager.getData('pageA'); if(promisePageA){ const resData = promisePageA.then( function(data){ }, function(){ console.log("err"); } ) } } }) [代码]
2019-10-31 - 如何恢复"已超时"的小程序?
微信公众号及创建的小程序长时间不用都处在冻结或"已超时"状态,公众号通过邮箱验证已恢复,公众号上面创建的小程序的“已超时”状态怎么解除?
2020-06-09 - H5页面分享不显示自定义标题和图片?
原因是H5用旧的方式申请JSAPI分享权限,后台返回无权限,因此分享的时候不能自定义,建议开发者接入新的分享方式:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html ,使用新的wx.updateAppMessageShareData和wx.updateTimelineShareData接口来设置分享数据。
2020-04-23 - 有多少人象我这样开始霍霍胶囊菜单了?
就象这样: [图片] [图片] js里: data: { rect: wx.getMenuButtonBoundingClientRect() }, wxml里 <image src="../../image/timg.png" mode="widthFix" style="width:{{rect.width+80}}px;position:fixed;z-index:9;left:{{rect.left-28}}px;top:-12px"></image> <view class="card"> </view>
2020-01-13 - 如何使用scroll-view制作左右滚动导航条效果
最新:2020/06/13。修改为scroll-view与swiper联动效果,新增下拉刷新以及上拉加载效果。。具体效果查看代码片段,以下文章内容和就不改了 刚刚在社区里看到 有老哥在问如何做滚动的导航栏。这里简单给他写了个代码片段,需要的大哥拿去随便改改,先看效果图: [图片] 代码如下: wxml [代码]<scroll-view class="scroll-wrapper" scroll-x scroll-with-animation="true" scroll-into-view="item{{currentTab < 4 ? 0 : currentTab - 3}}" > <view class="navigate-item" id="item{{index}}" wx:for="{{taskList}}" wx:key="{{index}}" data-index="{{index}}" bindtap="handleClick"> <view class="names {{currentTab === index ? 'active' : ''}}">{{item.name}}</view> <view class="currtline {{currentTab === index ? 'active' : ''}}"></view> </view> </scroll-view> [代码] wxss [代码].scroll-wrapper { white-space: nowrap; -webkit-overflow-scrolling: touch; background: #FFF; height: 90rpx; padding: 0 32rpx; box-sizing: border-box; } ::-webkit-scrollbar { width: 0; height: 0; color: transparent; } .navigate-item { display: inline-block; text-align: center; height: 90rpx; line-height: 90rpx; margin: 0 16rpx; } .names { font-size: 28rpx; color: #3c3c3c; } .names.active { color: #00cc88; font-weight: bold; font-size: 34rpx; } .currtline { margin: -8rpx auto 0 auto; width: 100rpx; height: 8rpx; border-radius: 4rpx; } .currtline.active { background: #47CD88; transition: all .3s; } [代码] JS [代码]const app = getApp() Page({ data: { currentTab: 0, taskList: [{ name: '有趣好玩' }, { name: '有趣好玩' }, { name: '有趣好玩' }, { name: '有趣好玩' }, { name: '有趣好玩' }, { name: '有趣好玩' }, { name: '有趣好玩' }, { name: '有趣好玩' }, { name: '有趣好玩' }, { name: '有趣好玩' }, { name: '有趣好玩' }, { name: '有趣好玩' }, { name: '有趣好玩' }, { name: '有趣好玩' }, { name: '有趣好玩' }, { name: '有趣好玩' }, ] }, onLoad() { }, handleClick(e) { let currentTab = e.currentTarget.dataset.index this.setData({ currentTab }) }, }) [代码] 最后奉上代码片段: https://developers.weixin.qq.com/s/nkyp64mN7fim
2020-06-13 - 小程序取消橡皮筋回弹效果解决方案及坑总结
提到ios系统的橡皮筋效果,作为开发者是又爱又恨,有想要这个效果又有不想要的,无奈的是却没有一个简单的开关来设置这个效果是否开启。 最近在开发小程序时也遇到有关于ios橡皮筋回弹的问题,这里分两部分(取消橡皮筋回弹效果和因为这个效果遇到的坑)和大家分享一下。 取消IOS橡皮筋回弹效果的解决方案 1) 页面无滚动区域时,可通过页面json配置文件设置disableScroll:true禁止整个页面滚动,从而取消橡皮筋效果。 [代码]{ "disableScroll":true } [代码] 测试代码:https://github.com/YuniorZen/minicode-debug/tree/master/minicode01/pages/demo1 2) 页面有滚动区域,滚动区域通过view模拟实现,然后在页面json配置文件设置disableScroll:true禁止整个页面滚动,从而取消橡皮筋效果。 [代码]json文件配置 { "disableScroll":true } view元素模拟实现滚动样式 { height: calc(100vh - 120rpx); //高度必须是固定的值 overflow-y: auto; } [代码] 不足之处在于view元素模拟的滚动区域滚动时不够连贯,没有scroll-view那种原生丝滑般的感觉。 测试代码:https://github.com/YuniorZen/minicode-debug/tree/master/minicode01/pages/demo2 3) 页面有滚动区域,滚动区域使用scroll-view,这时通过disableScroll则无法实现,尝试设置一下scroll-view的scroll-y="{{false}}",上拉或下拉时居然不再触发橡皮筋的回弹啦,当然滚动区域也不能滚动。 小脑袋动一动,解决方法有啦! 通过设置一个变量scrollY动态控制滚动区域的滚动从而阻止回弹。 监听bindscrolltoupper\bindscrolltolower当scroll-view区域滚动到顶部或底部时候设置scrollY:false来关闭页面滚动,从而阻止回弹。 监听bindtouchstart\bindtouchmove 当用户反方向滑动的时候设置scrollY:true,再次开启页面滚动。 [代码]wxml滚动区域属性和事件处理,具体实现请点击测试代码链接 <scroll-view scroll-y="{{scrollY}}" class="list" upper-threshold="5" lower-threshold="5" bindscrolltoupper="bindscrolltoupper" bindscrolltolower="bindscrolltolower" bindtouchstart="touchstart" bindtouchmove="touchmove"> <view class="list-item" wx:for="{{list}}" wx:key="{{index}}">{{item}}</view> </scroll-view> [代码] 相对view模拟实现滚动区域,scroll-view滚动更丝滑,不过每次滚动到底部或顶部的时候,再反向滑动时由于再次开启scroll-view滚动会有操作卡顿的感觉,暂时没想到好的解决方法,有解决的大佬希望提供一下想法,一起学习下。 测试代码:https://github.com/YuniorZen/minicode-debug/tree/master/minicode01/pages/demo3 IOS橡皮筋效果遇到的坑 1) 操作左滑删除组件时上下移动,会触发橡皮筋效果导致页面抖动的问题 这个坑的严重程度看设计师的意愿了,反正我们团队目前是需要解决的,方案类似取消橡皮筋解决方案的第三种 在左滑的时候关闭scroll-view的滚动,取消时再次开启滚动 2) 如果页面顶部有置顶的横向滚动区域scroll-view,当页面滚动到底部时继续上拉会导致置顶头部消失,松开回弹后头部又会出现。 坑是社区里的朋友提出来的,我借了个iphone x 一预览,我嚓,还是真是个奇坑! 微信官方回复已复现正在解决中… 不想继续等下去的,暂时解决方法是 监听页面的滚动区域,当滚动到底部时设置顶部横向滚动scroll-view的scroll-x=false来解决。 写在最后 以上便是我在小程序开发中有关于ios橡皮筋回弹效果的分享,示例代码已上传github,可自行下载体验。 https://github.com/YuniorZen/minicode-debug/tree/master/minicode01 目前微信官方虽说已经着手解决(已两年)此类bug,但哪吒说 我命由我不由天,所以还是我们开发者多分享些解决方案自救来的快。 分享方案如有问题还望不吝指出,没有涉及到的坑也欢迎评论提出,一起学习和解决,后续也会基于此篇不断更新总结。
2021-01-14 - 怎么申请成为小程序服务商?
怎么申请成为小程序服务商?
2020-03-27 - 小程序页面吸顶效果、右下角悬浮按钮等隐藏显示切换时不卡顿的实现方法
使用的api及页面方法 api:wx.createSelectorQuery、wx.createIntersectionObserver 页面方法:onPageScroll 为什么使用以上方法? wx.createSelectorQuery:主要解决页面渲染后保证所涉及的元素能百分百渲染到屏幕上,这里打包一个异步方法。 [代码]getElement(elm, component) { const _this = this; return new Promise((resolve, reject) => { let ss = setInterval(function() { let Qy = component ? _this.createSelectorQuery() : wx.createSelectorQuery(); let a = Qy.select(elm).boundingClientRect(function(res) { if (res) { clearInterval(ss) resolve(res) } }).exec(); }, 50); }); } [代码] wx.createIntersectionObserver与onPageScroll的作用: 单纯使用onPageScroll切换隐藏显示状态必然会高频率使用setData导致页面卡顿。如果只是在wx.createIntersectionObserver与onPageScroll中隐藏或者显示,即确保每个方法中只setData一次,那么卡顿的现象就不会出现。 以下wx.createIntersectionObserver仅作显示元素 [代码]onCreateIntersectionObserver(component,elm) { const _this = this; this.getElement(elm||".tr-fixed", component).then(res => { _this.setData({ fixed_top: res.top //记录一直显示的元素的top值 }); _this.IntersectionObserver = component ? _this.createIntersectionObserver() : wx.createIntersectionObserver() _this.IntersectionObserver.relativeTo(".top-transparent", { bottom: 2 }).observe(elm||'.tr-fixed', (res) => { //显示吸顶 const { fixed_show } = _this.data; if (fixed_show === false) { _this.setData({ fixed_show: true }); } //显示吸顶 }) }); } [代码] 上面代码中: .top-transparent是自定义参照区域。 .tr-fixed或elm为切换隐藏与显示的元素(事先写好顶部浮动,隐藏起来,这里并没有css仅作为监听对象) wxml基本代码: [代码]<view class="top-transparent">页面顶部透明参照元素</view> <view class="tr-fixed">一直显示的部分(滚动的scrollTop小于此元素的top值则隐藏,如果监测到与透明的参照元素交叉则显示)</view> <view class="fixed-view" wx:if="{{fixed_show}}">隐藏的部分(与一直显示的部分一模一样)</view> [代码] [代码].top-transparent{ position: fixed; top: 0; left: 0; right: 0; height: 20px; background: transparent;//透明 pointer-events: none; //保证此元素所有点击事件无效,即点击事件都穿透到比它层级低的元素上 } [代码] 以下onPageScroll仅作隐藏元素 [代码]onPageScroll(e) { const { fixed_top, fixed_show } = this.data // 隐藏吸顶头部 if (fixed_top != undefined && fixed_show) { if (e.scrollTop <= fixed_top) { this.setData({ fixed_show: false }) } } // 隐藏吸顶头部 }, [代码] 代码片段: https://developers.weixin.qq.com/s/oUhsfCmP76au
2019-08-14 - 在scroll-view中使用sticky
.container{ width: 600rpx; height: 800rpx; } .a { position: sticky; position: -webkit-sticky; top: 0; width: 100%; height: 200rpx; background-color: black; } .b { width: 100%; height: 3000rpx; background-color: red; } <scroll-view class="container"> <view> <view class="a"></view> <view class="b"></view> </view> </scroll-view> sticky的元素在到达父元素的底部时会失效 scroll-view的高度为800rpx,但是scrollHeight为3200rpx,所以在scroll-view中嵌套一个view就能顺利定位
2019-12-18 - WXS 什么时候可以支持 boundingClientRect?
就是在 WXS 之中同步执行 https://developers.weixin.qq.com/miniprogram/dev/framework/view/selector.html 里面的 boundingClientRect() 方法。 为什么这非常有必要的原因在于,目前小程序端 FLIP 动画实现 https://aerotwist.com/blog/flip-your-animations/ 无法采用组件更新后立即获取 BCR 的方法,而是必须维持一个原始列表和一个新列表的渲染结果以供比较。这会造成很大的性能开销。
2020-03-20 - 中文小程序,文章中有外国文字,如:德文,法文Égérie,显示为乱码,需要怎么调整?请高手指教。
中文小程序,文章中有外国文字,如:德文,法文Égérie,显示为乱码,需要怎么调整?请高手指教。
2020-03-19 - 「激励式视频广告」向非游戏类小程序流量主开放
[图片] [图片] [图片] [图片] [图片] [图片] [图片] [图片] [图片] [图片] [图片] [图片] [图片] [图片] [图片] [图片] [图片]
2019-04-16 - emoji扩展组件报错呢?
[图片] emojiPicture: 'http://q1b7ehu5b.bkt.clouddn.com/emoji-sprite-2.png',这地址访问不了呢?
2020-03-19 - 使用web-view 外部连接下载安卓apk安装包可行吗?
<web-view src="https://www./************/*****.apk"></web-view> 这样小程序下载apk安装包时页面空白无反应,有没有类似下载并安装apk包的方法,请大神赐教 (该域名已经添加到开发者中心)
2019-12-03 - 请问小程序里面是否可以放APP的下载二维码?
无诱导、无奖励,仅放APP的二维码让用户保存后自愿扫码识别,是否可以?
2019-10-31 - 微信小程序有身份证护照拍照显示模具的是怎么弄的?
[图片]
2019-10-11 - 小程序迁移需要哪些材料?
1、满足小程序迁移条件的帐号:原小程序A必须是已成功注册的小程序帐号;目标主体不支持为个人类型。 2、原/目标主体证件:要求上传原件照片、扫描件,或加盖公章的复印件。 3、上传微信小程序迁移申请函:原件照片、扫描件;按照小程序提交迁移申请步骤,在第二步中下载申请函并填写完整准确信息。 4、目标主体新服务类目资质相关文件,具体参考非个人主体小程序开放的服务类目(请点击此处详细了解); 5、小游戏需提交相关资质进行审核(广电总局版号批文、文化部备案信息、游戏自审自查报告、计算机软件著作权登记证书等) 6、若授权验证选择公证书方式,申请公函需提前在公证机关进行公证并在授权验证步骤中上传公证书(详情请点击此处了解);或到律师事务所做律师见证,提供律师见证函; 7、因需支付300元审核费用,若需开具增值税发票,请提前和财务申请准备好税号、税务登记证/营业执照、开户许可证。
2020-03-18 - 如何隐藏右上角胶囊
抽奖助手,新增地址页面,右上角的胶囊不见了,怎么做到的?如图 查了console.log(wx),发现setNavigationBarRightButton,根据提示设置但是没效果 wx.setNavigationBarRightButton({ hide: true }); [图片]
2018-06-03 - 刚开发者工具提示 wx.chooseLocation 支持传入指定坐标了 文档上没有啊?
刚开发者工具提示 wx.chooseLocation 支持传入指定坐标了 文档上没有啊?
2019-09-27 - kbone,十分钟让 Vue 项目同时支持小程序
什么是kbone 微信小程序开发过程中,许多开发者会遇到 小程序 与 Web 端一起的需求,由于 小程序 与 Web 端的运行环境不同,开发者往往需要维护两套类似的代码,这对开发者来说比较耗费力气,并且会出现不同步的情况。 为了解决上述问题,微信小程序推出了同构解决方案 [代码]kbone[代码] 来解决此问题。 那么,[代码]kbone[代码] 要怎么使用呢?这里我们将通过一个 [代码]todo[代码] 的例子来跟大家讲解。 基本结构 首先,我们来看下一个基本的 kbone 项目的目录结构(这里的 [代码]todo[代码] 是基于 [代码]Vue[代码] 的示例,[代码]kbone[代码] 也有 [代码]React[代码],[代码]Preact[代码],[代码]Omi[代码] 等版本,详情可移步 kbone github)。 因为 kbone 是为了解决 小程序 与 Web 端的问题,所以每个目录下的配置都会有两份(小程序 与 Web 端各一份) [图片] 入口 不管是 小程序 端还是 Web 端,都需要入口文件。在 [代码]src/index[代码] 目录下,[代码]main.js[代码] 为 Web 端用主入口,[代码]main.mp.js[代码] 则为 小程序 端用主入口。 当然,Web 端会比 小程序 多一个入口页面,即 [代码]index.html[代码](位于根目录下)。 [图片] 下面两段代码分别是 小程序端 入口与 Web 端入口的代码,可以看到 小程序端的入口代码封装在 [代码]createApp[代码] 函数里面(这里固定即可),内部会比 Web 端多一个创建 [代码]app[代码] 节点的操作,其他的基本就是一致的。 [代码]// 小程序端入口 import Vue from 'vue' import todo from './todo.vue' export default function createApp() { // 创建app节点用于绑定 const container = document.createElement('div') container.id = 'app' document.body.appendChild(container) return new Vue({ el: '#app', render: h => h(todo) }) } [代码] [代码]// web端入口 import Vue from 'vue' import todo from './todo.vue' new Vue({ el: '#app', render: h => h(todo) }) [代码] todo.vue 在上面的入口图可以看到,源码目录中,除了入口文件分开之前,页面文件就是共用的了,这里直接使用 Vue 的写法即可,不用做特殊的适应。 配置 写完代码之后,我们要怎么跑项目呢?这时,配置就派上用场啦。 Web 端配置为正常的 Vue 配置,小程序端配置与 Web 端配置的唯一不同就是需要引入 [代码]mp-webpack-plugin[代码] 插件来将 Vue 组件转化为小程序代码。 [图片] 构建代码 接着,我们需要构建代码,让代码可以运行到各自的运行环境中去。构建完成后,生产代码会位于 dist 目录中。 [代码]// 构建 web 端代码 // 目标代码在 dist/web npm run build // 构建小程序端代码 // 目标代码在 dist/mp npm run mp [代码] 小程序端 的构建会比 Web 端的构建多一个步骤,就是 npm 构建。 进入 [代码]dist/mp[代码] 目录,执行 [代码]npm install[代码] 安装依赖,用开发者工具将 [代码]dist/mp[代码] 目录作为小程序项目导入之后,点击工具栏下的 [代码]构建 npm[代码],即可预览效果。 效果 最后,我们来看一下 todo 的效果。kbone 初体验,done~ todo 代码可到 kbone/demo13 自提。 [图片] 最后 如果你想了解更多 kbone 相关的使用及详情,可移步 kbone github。 如有疑问,可到 Kbone小主页 发帖沟通。
2020-04-22 - 微信小程序图表工具wx-charts
微信小程序图表工具,charts for WeChat small app,基于canvas绘制,体积小巧。
2017-12-13 - 如何实现一个6位数的密码输入框
背景: 因为公司业务调整需要做用户支付这一块 开发者需要在小程序上实现一个简单的6位数密码输入框 [图片] 首先想下如何实现该效果: 1.使用input覆盖在框上面,设置letter-spacing达到数字之间间距的效果,实现时发现在input组件上使用letter-spacing无效果 2.循环六个view模拟的框,光标使用动画模拟,一个隐藏的input,点击view框时触发input的Focus属性弹起键盘,同时模拟的光标展示出来,输入值后,input的value长度发生变化,设置光标位置以及模拟的密码小黑圆点 好了,废话不多数,咱们直接上手。 wxml [代码]<view class='container'> <!-- 模拟输入框 --> <view class='pay-box {{focusType ? "focus-border" : ""}}' bindtap="handleFocus" style='width: 604rpx;height: 98rpx'> <block wx:for="{{boxList}}" wx:key="{{index}}"> <view class='password-box {{index === 0 ? "b-l-n":""}}'> <view wx:if="{{(dataLength === item - 1)&& focusType}}" class="cursor"></view> <view wx:if="{{dataLength >= item}}" class="input-black-dot"></view> </view> </block> </view> <!-- 隐藏input框 --> <input value="{{input_value}}" focus="{{isFocus}}" maxlength="6" type="number" class='hidden-input' bindinput="handleSetData" bindfocus="handleUseFocus" bindblur="handleUseFocus" /> </view> [代码] wxss [代码]/* 第一个格子输入框 */ .container .b-l-n { border-left: none; } .pay-box { margin: 0 auto; display: flex; flex-direction: row; border-left: 1px solid #cfd4d3; } /* 支付密码框聚焦的时候 */ .focus-border { border-color: #0c8; } /* 单个格式样式(聚焦的时候) */ .password-box { flex: 1; border: 1px solid #0c8; margin-right: 10rpx; display: flex; align-items: center; justify-content: center; } /* 模拟光标 */ .cursor { width: 2rpx; height: 36rpx; background-color: #0c8; animation: focus 1.2s infinite; } /* 光标动画 */ @keyframes focus { from { opacity: 1; } to { opacity: 0; } } /* 模拟输入的password的黑点 */ .input-black-dot { width: 20rpx; height: 20rpx; background-color: #000; border-radius: 50%; } /* 输入框 */ .hidden-input { margin-top: 200rpx; position: relative; } [代码] JS [代码]Component({ data: { //输入框聚焦状态 isFocus: false, //输入框聚焦样式 是否自动获取焦点 focusType: true, valueData: '', //输入的值 dataLength: '', boxList: [1, 2, 3, 4, 5, 6] }, // 组件属性 properties: { }, // 组件方法 methods: { // 获得焦点时 handleUseFocus() { this.setData({ focusType: true }) }, // 失去焦点时 handleUseBlur() { this.setData({ focusType: false }) }, // 点击6个框聚焦 handleFocus() { this.setData({ isFocus: true }) }, // 获取输入框的值 handleSetData(e) { // 更新数据 this.setData({ dataLength: e.detail.value.length, valueData: e.detail.value }) // 当输入框的值等于6时(发起支付等...) if (e.detail.value.length === 6) { // 通知用户输入数字达到6位数可以发送接口校验密码是否正确 this.triggerEvent('initData', e.detail.value) } } } }) [代码] 实现方式很简单,有点小问题,还有一些后续准备做的优化点,等完善后上线后再来修改一波。 最后附上代码片段: https://developers.weixin.qq.com/s/8CtRqJmT7W8k
2020-07-06 - Page.onShow中如何区分从其他页面中进入还是从公众号消息卡片中进入?
从公众号消息卡片中进入携带参数拉取数据, 切换Tab,不携带参数刷新数据。 在代码逻辑中,如何区分这两种情况。
2019-11-21 - 小程序将小程序码与图片结合生成海报分享朋友圈
样例参考(瑞幸咖啡小程序) [图片][图片][图片] 需求分析 服务器端会返回不确认的图片资源到前端 前端将返回的每张图片都要贴上小程序码 将贴上小程序码的图片使用 swiper 组件轮播 用户点击保存时,将图片保存至相册。 至于点击保存如何保存至相册(wx.saveImageToPhotosAlbuml 了解一下,注意一下授权问题即可) 碰到的问题 canvas为原生组件, 而原生组件的层级是最高的,所以页面中的其他组件无论设置 z-index 为多少,都无法盖在原生组件上。 [代码]采用方法: 通过定位,将其移除到不在可视范围,如iphone6 .canvas { position: relative; left: -375px; } [代码] 绘制多张图片时, 一个canvas 标签只能对应画一张图片 (目前我测试的是这样,如有其它方法,欢迎评论交流) [代码]采用方法: 1. html端循环要生成的图片张数,对应循环出多个 canvas 组件,分别设置不同的 canvasId 区分 2. 封装一个绘制海报的函数,返回一个Promise对象,用于后面绘制完所有的图片,统一赋值渲染,避免多次触发数据更新 3. js端 循环执行一次 绘制海豹函数,存于一个数组列表 4. 使用 Promise.all 函数,统一绘制完毕将生产图片路径赋值 html: <canvas v-for="u in m.urlList" :key="u" :canvas-id="'poster'+index" class="canvas" style="width:100%; height:100%;"> </canvas> <swiper :indicator-dots="true" :circular="true" :autoplay="true" indicator-color="rgba(255,255,255,.2)" indicator-active-color="#fff" class="swiper"> <swiper-item v-for="f in m.filePaths" :key="index"> <image :src="f"> </swiper-item> </swiper> js: // 数据 (mpvue 开发) function data(){ return { m : { urlLIst: [ // 图片资源 '/static/poster0.jpg', '/static/poster1.jpg' ], filePaths: [], // 生成图片(贴上小程序码) } } } try { let res = wx.getSystemInfoSync(); // 同步获取系统信息 let w = res.windowWidth; // 手机可用区域宽度 let h = res.windowHeight; // 手机可用区域高度 let codeUrl = '/static/code.jpg'; // 小程序码 let drawList = []; // 用于保存绘制海报图Promise对象 m.urlList.forEach( (u, i)=> { // 传入canvas组件ID,图片路径(测试使用的是本地路径) drawList.push(drawPoster('poster'+i, u, codeUrl)); }) // 统一更新数据 Promise.all(drawList).then((valuse)=>{ m.filePaths = valuse; }); // 封装绘制图片函数 function drawPoster(canvasId, bgUrl, codeUrl){ return new Promise( (resolve, reject) => { // 创建画布实例 let ctx = wx.createCanvasContext(canvasId); // 绘制背景图: 图片路径,x坐标,y坐标,宽,高 ctx.drawImage(bgUrl, 0, 0, w, h); // 绘制小程序码 ctx.drawImage(codeUrl, w-120, h-120, 100, 100); // 绘制 ctx.draw(false, ()=>{ // 该通过函数将canvas绘制导出为图片 wx.canvasToTempFilePath({ x: 0, y: 0, width: w, height: h, canvasId: canvasId, success(res){ resolve(res.tempFilePath); } }); }); } }catch(e){ // 自己封装了一成 wx.$toast(e); } [代码] 最终demo效果图 [图片][图片] 在社区中暂未看到多张海报实现的方案,如果有更好的实现方案,欢迎交流
2019-07-30 - 如何实现快速生成朋友圈海报分享图
由于我们无法将小程序直接分享到朋友圈,但分享到朋友圈的需求又很多,业界目前的做法是利用小程序的 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 - 小程序海报生成工具,可视化编辑直接生成代码使用,你的海报你自己做主
开门见山 工具地址 点我直达>>painter-custom-poster 由于挂载在github page上,打开速度会慢一些,请耐心等待或自行解决git网速问题 背景 在做小程序时候,我们经常会有一个需求,需要将小程序分享到朋友圈,但是朋友圈是不允许直接分享小程序,那我们还有其他的办法解决吗?答案肯定是有的,即 canvas 生成个性化海报分享图片到朋友圈 分析 小程序中有大量的生成图片需求,但是使用过 canvas 的人,都会发现一些难以预料的问题>>有关小程序的坑 直接在 canvas 上绘制图形,对于普通开发者来说代码会特别凌乱并且难以维护,经常会花费很久的时间去优化代码 不同的环境渲染问题,例如在开发者工具看起来好好的,一到 Android 真机,就出现图片不显示,位置不对应等等问题 解决 那可不可以开发一款生成海报的插件库呢? 首先,只需要提供一份简单的参数配置文件即可 解决掉小程序Canvas遇到的一些大大小小的坑 有严苛的测试环节,解决各种环境和各种机型遇到的问题,并提供稳定的线上版本 长期维护,并有专人更新迭代更新颖的功能 以上的要求当然是可以的,曾经的我也想尝试开发一款出来,但是后来尝试了几款现成的工具之后就放弃了,毕竟轮子这个东西,是需要不断维护更新的,另外已经有这么多优秀现成的插件了,我为何还要费力去写呢,贡献代码岂不更美哉,以下是我收集的几款 小程序生成图片库,轻松通过 json 方式绘制一张可以发到朋友圈的图片>>Painter 小程序组件-小程序海报组件>>wxa-plugin-canvas 微信小程序:一个 json 帮你完成分享朋友圈图片>>mp_canvas_drawer 我想干什么 唠了这么多,好像提供给大家插件就没我什么事情了…想走是不可能的 为了能够制作出更酷炫的海报,我思考了许久 虽然有了插件后,只需要提供配置代码就能够制作出一款海报来,但是我发现还是有些许问题 制作海报效率还是不够高,微调一个元素的大小和位置,就需要不断的修改保存代码,等待片刻,查看效果,真的烦 一个小小的位置调整可能就需要来回调整无数次,这种最简单的机械化劳动,这辈子是不可能的 拿着完美的稿子,递给设计师看,这个位置不对,这个线太粗,这个颜色太重…你信不信我打死你 对于一些精美复杂的海报,实现起来真的不太现实 那我需要怎么做呢,请点击这个链接体验>>painter-custom-poster 点击左侧例子展示中的任意一个例子,然后导入代码就能看到效果图,这下你应该能猜到了我的想法了 如何实现 刚开始我想用简单的html和css加拖动功能实现,通过简单尝试之后就放弃了,因为这个功能真的太复杂了,简单的工具肯定是不行的 中间这个计划停滞了很长时间,一度已经放弃 直到发现了这个库fabric.js,真的太太优秀了,赞美之词无以言表,唯一的缺点就是中文教程太少,必须生啃英文加谷歌翻译 fabric介绍,你可以很容易地创建任何一个简单的形状,复杂的形状,图像;将它们添加到画布中,并以任何你想要的方式进行修改:位置、尺寸、角度、颜色、笔画、不透明度等 How To Use 目前工具一共分成4部分 例子展示 用来将一些用户设计的精美海报显示出来,通过点击对应的例子并将代码导入画布中 画布区 显示真实的海报效果,画布里添加的元素,都可以直接用鼠标进行拖动,旋转,缩放操作 操作区 第一排四个按钮 复制代码 将画布的展示效果转化成小程序海报插件库所需要的json配置代码,目前我使用的是Painter库,默认会转化成这个插件的配置代码,将代码直接复制到card.js即可 查看代码 这个功能用不用无所谓,可以直观的看到生成的代码 导出json 将画布转化成fabric所需要的json代码,方便将自己设计的海报代码保存下来 导入json 将第3步导出的json代码导入,会在画布上显示已设计的海报样式 第二排五个按钮 画布 画布的属性参数 详解见下方 文字 添加文字的属性参数 详解见下方 矩形 添加矩形的属性参数 详解见下方 图片 添加图片的属性参数 详解见下方 二维码 添加二维码的属性参数 详解见下方 第三排 各种元素的详细设置参数 激活区 激活对象是指鼠标点击画布上的元素,该对象会被蓝色的边框覆盖,此时该对象被激活,可以执行拖动 旋转 缩放等操作 激活区只有对象被激活才会出来,用来设置激活对象的各种配置参数,修改value值后,实时更新当前激活对象的对应状态,点击其他区域,此模块将隐藏 快捷键 ‘←’ 左移一像素 ‘→’ 右移一像素 ‘↑’ 上移一像素 ‘↓’ 下移一像素 ‘ctrl + z’ 撤销 ‘ctrl + y’ 恢复 ‘delete’ 删除 ‘[’ 提高元素的层级 ‘]’ 降低元素的层级 布局属性 通用布局属性 属性 说明 默认 rotate 旋转,按照顺时针旋转的度数 0 width、height view 的宽度和高度 top、left 如 css 中为 absolute 布局时的作用 0 background 背景颜色 rgba(0,0,0,0) borderRadius 边框圆角 0 borderWidth 边框宽 0 borderColor 边框颜色 #000000 shadow 阴影 ‘’ shadow 可以同时修饰 image、rect、text 等 。在修饰 text 时则相当于 text-shadow;修饰 image 和 rect 时相当于 box-shadow 使用方法: [代码]shadow: 'h-shadow v-shadow blur color'; h-shadow: 必需。水平阴影的位置。允许负值。 v-shadow: 必需。垂直阴影的位置。允许负值。 blur: 必需。模糊的距离。 color: 必需。阴影的颜色。 举例: shadow:10 10 5 #888888 [代码] 渐变色支持 你可以在画布的 background 属性中使用以下方式实现 css 3 的渐变色,其中 radial-gradient 渐变的圆心为 中点,半径为最长边,目前不支持自己设置。 [代码]linear-gradient(-135deg, blue 0%, rgba(18, 52, 86, 1) 20%, #987 80%) radial-gradient(rgba(0, 0, 0, 0) 5%, #0ff 15%, #f0f 60%) [代码] !!!注意:颜色后面的百分比一定得写。 画布属性 属性 说明 默认 times 控制生成插件代码的宽度大小,比如画布宽100,times为2,生成的值为200 1 文字属性 属性名称 说明 默认值 text 字体内容 别跟我谈感情,谈感情伤钱 maxLines 最大行数 不限,根据 width 来 lineHeight 行高(上下两行文字baseline的距离) 1.3 fontSize 字体大小 30 color 字体颜色 #000000 fontWeight 字体粗细。仅支持 normal, bold normal textDecoration 文本修饰,支持none underline、 overline、 linethrough none textStyle fill: 填充样式,stroke:镂空样式 fill fontFamily 字体 sans-serif textAlign 文字的对齐方式,分为 left, center, right left 备注: fontFamily,工具中的第一个例子支持文字字体,但是导入小程序为什么看不到呢,小程序官网加载网络字体方法>> 加载字体教程>> 文字高度 是maxLines lineHeight2个字段一起计算出来的 图片属性 属性 说明 默认 url 图片路径 mode 图片裁剪、缩放的模式 aspectFill mode参数详解 scaleToFill 缩放图片到固定的宽高 aspectFill 图片裁剪显示对应的宽高 auto 自动填充 宽度全显示 高度自适应居中显示 Tips(一定要看哦~) 本工具不考虑兼容性,如发现不兼容请使用google浏览器 painter现在只支持这几种图形,所以暂不支持圆,线等 如果编辑过程,一个元素被挡住了,无法操作,请选择对象并通过[ ]快捷键提高降低元素的层级 文字暂不支持直接缩放操作,因为文字大小和元素高度不容易计算,可以通过修改激活栏目maxLines lineHeight fontSize值来动态改变元素 如发现导出的代码一个元素被另一个元素挡住了,请手动调整元素的位置,json数组中元素越往后层级显示就越高,由于painter没有提供层级参数,所以目前只能这样做 本工具导出代码全是以px为单位,为什么不支持rpx, 因为painter在rpx单位下,阴影和边框宽会出现大小计算问题,由于原例子没有提供px生成图片方案,可以下载我这里修改过的demo>>Painter即可解决 文本宽度随着字数不同而动态变化,想在文本后面加个图标根据文本区域长度布局, 请参考Painter文档这块教程直接修改源码 由于本工具开发有些许难度,如出现bug,建议或者使用上的问题,请提issue,源码地址>>painter-custom-poster 海报贡献 如果你设计的海报很好看,并且愿意开源贡献,可以贡献你的海报代码和缩略图,例子代码文件在example中,按顺序排列,例如现在库里例子是example2.js,那你添加example3.js和example3.jpg图片,事例可以参考一下文件夹中源码,然后在index.js中导出一下 导出代码 代码不要格式化,会报错,请原模原样复制到json字段里 生成缩略图 刚开始我想在此工具中直接生成图片,但是由于浏览器图片跨域问题导致报错失败 所以请去小程序中生成保存图片,图片质量设置0.2,并去tinypng压缩一下图片 找到painter.js,替换下边这个方法,可以生成0.2质量的图片,代码如下 [代码] saveImgToLocal() { const that = this; setTimeout(() => { wx.canvasToTempFilePath( { canvasId: 'k-canvas', fileType: 'jpg', quality: 0.2, success: function(res) { that.getImageInfo(res.tempFilePath); }, fail: function(error) { console.error(`canvasToTempFilePath failed, ${JSON.stringify(error)}`); that.triggerEvent('imgErr', { error: error }); } }, this ); }, 300); } [代码] TODO 颜色值选择支持调色板工具 文字padding支持 缩放位置弹跳问题优化 假如需求大的话,支持其他几款插件库代码的生成 ~ 创作不易,如果对你有帮助,请给个星星 star✨✨ 谢谢 ~
2019-09-27 - App跳转小程序使用了Universal Links,调起微信后提示正在连接又返回App
这个不是bug,是符合预期的。当用户首次使用新版SDK时,会出现上述跳转流程完成安全验证。验证通过后,后续使用同一App将不会出现二次跳转。请开发者参考下常见问题解答:https://developers.weixin.qq.com/doc/oplatform/Mobile_App/FAQ/iOS.html[图片]
2019-10-17 - 请问,app如何跳转到小程序体验版?
请问下,app怎样才能跳转到小程序体验版进行调试啊?
2019-08-05