- 如何解决“Error: xxx.js 已被代码依赖分析忽略,无法被其他模块引用”报错?
错误原因: 微信开发者工具从 1.05.2201210 版本开始,对小程序项目新增了无依赖文件过滤能力。 如果某个 js 文件被静态分析显示是无依赖文件,在实际运行时又被其他 js 文件 require 引用了,则会在工具模拟器中报错这个错误。 此时,如果你继续预览或者上传代码,则在真机运行环境中会报 xxx.js is not defined 的错误。 解决方式: 修改依赖引用的代码:可根据控制台中的【代码依赖分析异常】提示进行修改。(推荐)关闭过滤无依赖文件:project.config.json 中 settings 选项添加 ignoreDevUnusedFiles: false , ignoreUploadUnusedFiles: false详细分析: 微信开发者工具的无依赖文件过滤能力,是基于代码静态依赖分析的数据来实现的。 也就是会分析小程序项目中的代码内容,如果发现某个 js / wxml / wxss / json 文件没有被使用到,则会将其列为无依赖文件。 无依赖文件在模拟器运行时会被忽略,在上传时也不会打入代码包中,因此可以有效减少代码包大小。 但由于 js 代码的灵活性,代码静态依赖分析功能在某些情况下,无法准确分析出依赖引用关系(控制台中会有对应的 warning 提示),此时部分 js 文件会被误判为无依赖文件,导致报错。开发者需配合提示信息修改代码,才能继续使用此功能。 导致依赖异常的常见情况: 动态引用的情况,如 var a = 'somefile.js'; require(a);将 require 函数赋值给其他变量的情况,如 var a = require; a('somefile.js');
2022-07-04 - onShareAppMessage 从分享朋友到分享朋友圈 onShareTimeline, 踩坑之旅
我们厂也是混微信生态的, 大厂有个风吹草动的, 我们就要立马操练起来! 前端时间分享朋友圈刚发了个beta版, 我们总部的产品大佬, 立马致电远在西部的开发部门, 干! 立马! 明天上线!!! (GNMA!G, 灵魂相同的开发们才能看懂) 还能说点啥呢? 以上是瞎扯淡, 以下面是干活: 为你提供方便: 接口文档: https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share-timeline.html 页面问答: https://developers.weixin.qq.com/miniprogram/dev/reference/api/Page.html#onShareTimeline 限制文档: https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share-timeline.html#%E5%8D%95%E9%A1%B5%E6%A8%A1%E5%BC%8F%E4%B8%8B%E7%9A%84%E9%99%90%E5%88%B6 文档一定要看, 一遍不行, 再来一遍! 第一步: 实现分享朋友圈 前置条件: [图片] 直接上代码: [图片] 找一步安卓手机, 扫码立显; 做为一个前端小菜, 我脚的走到这步, 应该木有一丁点儿问题! 如果你实现不出来, 那就回归到田野般的生活中找找赶脚 第二步: 踩坑 每次出来个新功能, 实现的道路上总是坑坑洼洼, 我就想问一问, 坐在腾讯大楼喝着菊花枸杞的小伙伴, 程序员何苦为难程序员? (文档写的好一点能si吗?) 大家一直关注的如何传参问题: 传参数方式是酱紫的: [图片] 代码是酱紫的: [图片] 接收参数: onLoad(option) , 直接就可以拿到参数对象, 点一点就就出来, 亲测可用. 第二步: 场景值 众所周知, 分享的页面, 在朋友圈打开是“单页面模式”, 那就收到以下限制: [图片] 需要开发且记且珍惜. 可以根据场景值来判断页面来源 [图片] 未完待续, 有任何问题都可以找留言(包括如何找对象)
2020-07-25 - open-type='share' onShareAppMessage不能触发
- 当前 Bug 的表现(可附上截图) [图片] [图片] 为什么不触发onShareAppMessage??? 我新建个项目去测试这个,发现神奇的可以了。但是同样的代码放到我的项目里就是不行,why?? 心态爆炸 - 预期表现 [图片] - 复现路径 - 提供一个最简复现 Demo
2018-11-18 - 小程序用户头像昵称获取规则调整公告
更新时间:2022年11月9日由于 PC/macOS 平台「头像昵称填写能力」存在兼容性问题,对于来自低于2.27.1版本的访问,小程序通过 wx.getUserProfile 接口将正常返回用户头像昵称,插件通过 wx.getUserInfo 接口将正常返回用户头像昵称。 更新时间:2022年9月28日考虑到近期开发者对小程序用户头像昵称获取规则调整的相关反馈,平台将接口回收的截止时间由2022年10月25日延期至2022年11月8日24时。 调整背景在小程序内,开发者可以通过 wx.login 接口直接获取用户的 openId 与 unionId 信息,实现微信身份登录,支持开发者在多个小程序或其它应用间匿名关联同一用户。 同时,为了满足部分小程序业务中需要创建用户的昵称与头像的诉求,平台提供了 wx.getUserProfile 接口,支持在用户授权的前提下,快速使用自己的微信昵称头像。 但实践中发现有部分小程序,在用户刚打开小程序时就要求收集用户的微信昵称头像,或者在支付前等不合理路径上要求授权。如果用户拒绝授权,则无法使用小程序或相关功能。在已经获取用户的 openId 与 unionId 信息情况下,用户的微信昵称与头像并不是用户使用小程序的必要条件。为减少此类不合理的强迫授权情况,作出如下调整。 调整说明自 2022 年 10 月 25 日 24 时后(以下统称 “生效期” ),用户头像昵称获取规则将进行如下调整: 自生效期起,小程序 wx.getUserProfile 接口将被收回:生效期后发布的小程序新版本,通过 wx.getUserProfile 接口获取用户头像将统一返回默认灰色头像,昵称将统一返回 “微信用户”。生效期前发布的小程序版本不受影响,但如果要进行版本更新则需要进行适配。自生效期起,插件通过 wx.getUserInfo 接口获取用户昵称头像将被收回:生效期后发布的插件新版本,通过 wx.getUserInfo 接口获取用户头像将统一返回默认灰色头像,昵称将统一返回 “微信用户”。生效期前发布的插件版本不受影响,但如果要进行版本更新则需要进行适配。通过 wx.login 与 wx.getUserInfo 接口获取 openId、unionId 能力不受影响。「头像昵称填写能力」支持获取用户头像昵称:如业务需获取用户头像昵称,可以使用「头像昵称填写能力」(基础库 2.21.2 版本开始支持,覆盖iOS与安卓微信 8.0.16 以上版本),具体实践可见下方《最佳实践》。小程序 wx.getUserProfile 与插件 wx.getUserInfo 接口兼容基础库 2.27.1 以下版本的头像昵称获取需求:对于来自低版本的基础库与微信客户端的访问,小程序通过 wx.getUserProfile 接口将正常返回用户头像昵称,插件通过 wx.getUserInfo 接口将正常返回用户头像昵称,开发者可继续使用以上能力做向下兼容。对于上述 3,wx.getUserProfile 接口、wx.getUserInfo 接口、头像昵称填写能力的基础库版本支持能力详细对比见下表: [图片] *针对低版本基础库,兼容处理可参考 兼容文档 请已使用 wx.getUserProfile 接口的小程序开发者和已使用 wx.getUserInfo 接口的插件开发者尽快适配。小游戏不受本次调整影响。 最佳实践小程序可在个人中心或设置等页面使用头像昵称填写能力让用户完善个人资料: [图片] 微信团队 2022年5月9日
2023-09-26 - 部分手机input的type=number时,键盘无法弹出
- 当前 Bug 的表现(可附上截图) [图片] [图片] [图片] - 预期表现 应该进去默认弹出键盘,或者点击之后弹出 - 复现路径 - 提供一个最简复现 Demo <view class="password-box"> <view class='password-wrapper'> <!-- 伪装的input --> <block wx:for="{{inputLength}}" wx:key="item"> <!-- 宽高可以由外部指定 --> <view class="password-item {{currentValue.length === index ? 'password-active' : ''}}" style="width: {{inputWidth}}; height: {{inputHeight}}" catchtap='_focusInput'> <!-- 隐藏密码时显示的小圆点【自定义】 --> <view wx:if="{{!showValue && currentValue.length>=index+1}}" class="hidden"></view> <!-- 显示密码时显示对应的值 --> <view wx:if="{{showValue}}" class="show"> {{currentValue.length>=index+1?currentValue[index]:''}} </view> </view> </block> </view> <!-- 隐藏的输入框 --> <input type="number" password="{{true}}" value="{{currentValue}}" class='hidden-input' maxlength="{{inputLength}}" focus="{{inputFocus}}" bindinput="_setCurrentValue"></input> </view> _focusInput() { this.setData({ inputFocus: true }); },
2019-03-20 - 如何实现一个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 - 高适应性的自定义导航栏开发思路
[图片] 非自定义导航栏高度怎么计算? 自定义导航栏高度由谁决定? 小程序自定义导航栏开发注意点与参考文档 一、默认导航栏高度怎么计算?(非custom情况下获取) wx.getSystemInfo 和 wx.getSystemInfoSync 获取机器信息 screenHeight - windowHeight 计算标题栏高度 [代码]{[代码][代码] [代码][代码]'iPhone'[代码][代码]: 64,[代码][代码] [代码][代码]'iPhone X'[代码][代码]: 88,[代码][代码] [代码][代码]'android'[代码][代码]: 68[代码][代码] [代码][代码]}[代码]不完全统计(ip6 , ip5 , ip6p , ipx , 小米mix2 , 小米5等综合了开发工具提供的数据和真机数据)所得 二、自定义导航栏高度由谁决定?(自定义情况下,屏幕高度和窗口高度没有差别,所以要通过步骤1先获取数据,预定义到代码中) 开发时发现,自定义导航栏的实现需要 包含状态栏+胶囊 :没有自定义导航栏的时候页面是全屏幕滚动会出现在状态栏的下一层 根据上一标题中步骤1的函数,可以获得状态栏高度 statusBarHeight demo,点击打开小程序开发工具 三、小程序自定义导航栏开发注意点与参考文档 微信官方设计指导中关于胶囊按钮的描述 由此得知胶囊宽度87pt=116px,设置之后,的确能产生较好的兼容性效果 社区Q&A:自定义标题栏高度计算、在 navigationStyle: 'custom',苹果X和8兼容问题 注意某些方法、参数的兼容性,时刻关注官方更新信息 开一个项目采集设备的screenHeight,windowHeight,pixelRatio等信息到一个数据库中,或者微信可以提供这样一个数据库便于计算,亦或者微信优化自定义标题栏(譬如通知栏可以改变颜色但不要算在自定义范围内,给出胶囊宽高到通知栏距离到右侧屏幕边框距离等相关参数)
2018-07-31 - 如何实现从微信小程序跳转到别的微信小程序页面
例如上面所示 仔细研究过微信小程序开发文档的小伙伴应该知道,微信小程序跳转到微信小程序采用的是wx.navigateToMiniProgram接口。 最简示例: wx.navigateToMiniProgram({ appId: appId, path: mpPath }) 从上面的代码可以看出,要想实现小程序跳转,需要知道要跳转的微信小程序的appid,这个一般通过查看微信小程序的更多资料可以查到,而path如果不熟悉是不容易知道的,有的说可以通过生成小程序码查到已经可以显示页面的路径信息,但是有可能是个加密的变值(如京东商品的路径),对于定值是可以的。 此外还有一个地方需要加,就是在app.json的配置里面 "navigateToMiniProgramAppIdList": [ "wx467145181671b58c" ] 新版本已经不需要在app.json里面加这个配置了。 是以数组的形式填写的appid,也就是说要跳转的小程序的appid都要在这里配置一下,这个地方最多可以填10个,也就是允许向10个微信小程序跳转。 特别说明: 个人类型的微信小程序已经不允许商业服务推广,本来我做小程序是想推广京东的商品,但因为是个人类型账号,发布后审核没能通过,而企业类型小程序是可以正常发布的。 [图片]
2020-12-22 - 小程序性能优化指南
开发者可通过开发者工具中的性能扫描工具提前发现代码中的可优化项: 1. 代码包不包含插件大小超过 1.5 M 【建议】小程序代码包单个包大小限制为2M。因此我们建议开发者在开发时,如果遇到单包体积大于1.5M的情况,可以采取分包的方式,把部分代码拆分到分包去,降低单个包的体积,提升小程序的加载速度。具体可以查看文档《使用分包》。 2. 引用插件大小超过 200 K 【知会】小程序插件的大小是会算进小程序代码包2M体积限制中的。因此当我们发现开发者引用的插件体积大于200K时,会对开发者予以提示,避免出现上传阶段提示代码包体积超限,但是不知道为何超限的问题。 3. 图片和音频资源大小超过 200 K 【建议】小程序代码包里可以存放一些必要的静态资源(如tabbar的icon等);但其他非必要的静态资源体积过大会影响小程序代码包加载速度。因此我们建议图片、音频等静态资源体积大小超过200K时,将它们上传到CDN,用URL引入会是个更好的选择。 4. 主包存在仅被其他分包依赖的JS 【建议】当主包里存在一些JS文件只会被分包使用(而主包自己不使用)时,我们建议把这些JS文件从主包中拆分出去,放到对应的分包里,从而优化主包的加载速度。 5. 主包存在仅被其他分包依赖的组件 【建议】当主包里存在一些组件只会被分包使用(而主包自己不使用)时,我们建议把这些组件从主包拆分出去,并且可以使用 分包异步化 这个特性加载这些组件,从而优化主包的加载速度。 6. 存在无使用的插件 【必须】如果有无使用的插件,请将其从 app.json 中去除。不然它会占用代码包体积,也会延迟代码包加载的时间。 7. 存在无使用的组件 【必须】如果在对应页面JSON的 `usingComponents` 里声明的组件但是没有使用,请将其从 `usingComponents` 里去除。 8. 未开启JS压缩 【必须】在工具「详情」-「本地设置」中开启「上传代码时自动压缩脚本文件」的设置 [图片] 9. 未开启WXML压缩 【必须】在工具「详情」-「本地设置」中开启「上传代码时自动压缩wxml文件」的设置 [图片] 10. 未开启WXSS压缩 【必须】在工具「详情」-「本地设置」中开启「上传代码时自动压缩样式文件」的设置 [图片] 11. 存在无依赖文件 【必须】在「代码质量」面板,点击「建议去除」后,可以打开代码依赖分析面板的「无依赖文件」页面,这里可以看到代码包里没有被用到的文件。请在代码包中去除这部分文件,减小体积并优化加载速度。 在本地开发的过程中,会自动过滤无依赖的文件,如果出现误过滤的情况,可以在 project.config.json 的 setting 字段中添加 ignoreDevUnusedFiles 为 false,也可以在 packOptions 的 include 字段中手动将被忽略的文件引入,同时欢迎发帖反馈误报的情况提交代码片段帮助我们完善此功能 注意:页面若为配置在 app.json 中,将被识别为无依赖文件 [图片] 12. 未开启组件懒注入(按需注入) 【必须】在 app.json 中加入 `"lazyCodeLoading": "requiredComponents"` 可以开启小程序组件按需注入特性。 其他优化内容,请点击学习《小程序性能优化实践》课程 [图片]
2023-02-17 - 如何制作自己的小程序? 从零开始制作一个微信小程序!
关于“小程序怎么开发自己的小程序”这个不少人关注的问题,小编针对性的给出详细教程,一共22个步骤。 1、进入公众平台,点击右上角“注册”蓝色文字。 [图片] 2、选择“小程序”注册板块。 [图片] 3、按照要求填写小程序账号信息,填写完成后,点击绿色“注册”按钮。 [图片] 4、提交注册信息后,页面会跳转到“邮箱激活”,登录自己的邮箱去激活。 [图片] 5、登录邮箱后,打开邮件点击激活链接,它会跳转进入小程序账号“信息登记”页面。 [图片] [图片] 6、举例:以下操作以“个人”主体类型为例:选择“个人”填写主体信息登记,按照上页面提示如实填写,必须实名填写。 [图片] 7、填写信息后点击“继续”,会出现下面的提示。 [图片] 8、点击确定后,它会提示提交成功,进入小程序。 [图片] 9、至此说明小程序已注册成功,页面会跳转到小程序账号的页面。 [图片] 10、点击“填写”补充小程序的基本信息,基本信息填写完整才能进入设置去获取APPID、APPSECRET。 [图片] 11、点击“添加开发者”增加小程序的项目成员,配置成员的权限,由成员管理小程序,但是管理员人只有一人。 12、设置-开发者设置,保存APPID、APPSECRET。 [图片] 13、通过mcppgl.com.cn页面,点击大图“立即创建”按钮,进入系统注册账号。 [图片] 14、进入功能分区导航页面,选择小程序,点击继续按钮进入模板库。 [图片] 15、挑选小程序成品模板类型,可通过功能分类、行业分类和颜色色系进行筛选查找,通过预览查看展示,确定后即可选用。 [图片] 16、进入编辑设计界面,可通过左右侧的功能模块进行设计、替换和添加内容,如图所示。 [图片] 17、打包前,应到小程序公众平台配置服务器域名,然后返回小程序模板界面,点击发布按钮,填写AppID、密钥,一键打包并下载到桌面。(体验版本需升级到付费版才能打包下载) [图片] [图片] 18、下载微信开发者工具并登录,开发者工具上输入APPID(即微信小程序ID)、项目名称(填写字母) 、项目目录(选择代码包解压后的首目录)。 [图片] [图片] 19、点击添加项目,项目添加成功后点击返回。 [图片] 20、点击刚刚上传的项目,进入调试界面,确认体验是否正常。 [图片] 21、确认无误,填写版本号及项目备注,点击上传。 [图片] 22、最后返回腾讯小程序后台,点击“提交审核”,等审核通过以后,即可发布上线。
2021-08-11 - WxParse解析富文本
WxParse是专门解析后台返给我们的HTML数据的,也叫做小程序的HTML解析器 这种方式可以解析 html/markdown 两种脚本,功能很强大 缺点:在解析富文本过程中,多次调用小程序的setData()方法,对性能有一定影响。 GitHub地址:https://github.com/icindy/wxParse 解压出来后,直接复制到小程序项目的根级目录 WXML: //引入 <import src="/wxParse/wxParse.wxml"/> //article为JS里WxParsewxParse第一个参数 <template is="wxParse" data="{{wxParseData:article.nodes}}"/> JS: //引入 const WxParse = require('../../wxParse/wxParse.js'); onLoad: function (options) { //第一个参数将成为WXML展示的数据名称 //第三个参数是要展示的数据 WxParsewxParse('article', 'html', this.data.articleHtml, this, 5); }, WXSS: //引入 @import "/wxParse/wxParse.wxss"; 另一种解析富文本的方法,rich-text为小程序自带富文本组件,直接使用即可 rich-text富文本组件是小程序1.4.0版本后推出来的,可以通过js脚本把html解析成一定格式的nodes,然后在 rich-text 中显示。 缺点:只能解析html内容,需要做兼容处理 WXML: //articleHtml是JS数据 <rich-text nodes="{{articleHtml}}"></rich-text>
2022-03-11 - 微信小程序设置滚动条
转载一篇文章,原文戳这里 原因 原来在app.wxss中定义了如下的内容【不知道是不是新建项目自动生成的,这里也就提供了隐藏滚动条的思路啦】 [代码]::-webkit-scrollbar { width: 0px; height: 0px; color:#transparent; } [代码] what, 宽高为0,而且还是透明的,难怪,好吧,修改宽高4px,color设置为green,以为可以了,呵呵,太年轻。 scroll-viwe依然没有滚动条,以为是布局原因,导致滚动条消失在界面外,我将宽高设为20px,想想也是搞笑,设这么宽,但是,正是这种傻劲,再运行,发现右边宽出了好多,然而还是没有滚动条,懂了,肯定还有其他设置,果不其然…… 解决 一通捣腾,原来,除了设置::-webkit-scrollbar,还需要设置::-webkit-scrollbar-track,这是设置滚动的轨道,::-webkit-scrollbar-thumb,这是设置滚动条的。 所以完整的设置如下(在app.wxss中,这样所有的scroll-view都有了,如果需要单独设置样式,可在单独page的wxss中设置) [代码]::-webkit-scrollbar { width: 4px; height: 4px; color:#ffffff; } /*定义滚动条轨道 内阴影+圆角*/ ::-webkit-scrollbar-track { -webkit-box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.3); box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1); border-radius: 10px; background-color:#FFFFFF; } /*定义滑块 内阴影+圆角*/ ::-webkit-scrollbar-thumb { border-radius: 10px; -webkit-box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.3); box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1); background-color:#39b54a; } [代码] [图片]
2020-07-16 - 微信小程序swiper的自适应高度
小程序组件swiper需要指定固定高度,但在某些场景中我们需要动态设置swiper的高度以完整展示swiper中的内容,比如高度不同的图片,笔者最近项目中的日历组件(31号有时会多出一行)等等,如何使swiper组件自适应高度呢? 翻阅了一些网上的例子,一般的解决方法是通过设置style.height来解决 [代码]<swiper style="{{style}}" > <swiper-item></swiper-item> </swiper> [代码] [代码] Page({ data: { style: '' }, onReady(){ this.setData({style: 'height: 100px'}) } }) [代码] 问题:状态丢失 直接设置样式可以动态设置高度,但这样做的不好之处在于会重新渲染结构,导致之前设置的状态丢失,比如我们在日历中选中的日期 我们的需求是,1. 动态设置swiper高度,2. 不丢失之前的状态 一番折腾过后,发现这条路是个死胡同,不能解决问题。 解决: CSS变量 后来发现使用css变量也能够动态改变样式,抱着试一试的想法 模板 [代码]<view class="box" style="{{boxStyle}}"> <swiper class="container"> <swiper-item></swiper-item> </swiper> </view> [代码] 样式 [代码].box{ --box-height: 400px; --append-height: 0; width: 100vw; height: calc(var(--box-height) + var(--append-height)) } .container{ height: 100%; width: 100%; } [代码] js [代码]Page({ data: { boxStyle: '' }, onReady(){ if (...) { this.setData({boxStyle: '--append-height: 50px'}) } else { this.setData({boxStyle: '--append-height: 0'}) } } }) [代码] 上述设置,居然能够完美的实现项目需求,现在项目正在上线中,等待测试出bug,哈哈 欢迎关注github项目 关注下面的小程序查看最新的DEMO示例 [图片]
2020-06-24 - 如何覆盖swiper-item的样式?
如何覆盖swiper-item的样式?
2021-01-19 - bind:change=和bindtap=有什么不同呢?
一直都是用bindtap="onChange" 这样的形式传递参数,但是今天用别人的ui 才发现 人家是这样写的 <wux-input-number longpress value="{{ value }}" min="{{ 1 }}" max="{{ 1000 }}" bind:change="onChange" slot="footer" /> 注意到没 bind:change="onChange" 是这样写的, 用我原来的方法一直获取不到input里的value值,而用他的方法就可以获取到 value值 我就是想问下 bindtap="onChange" 和 bind:change="onChange" 他们有什么不同,什么情况下应该用=号 什么情况下应该用:号?? 要是有知道的大神麻烦告诉我下,实在是困惑了 不知道其中的原因
2018-09-10 - table表格组件,分享给各位
前言 移动端的页面本应该很少有table表格这样的展示、操作,但总归有这样的需求,然而平时用的vant和iview的小程序组件库都没有table组件,这里将自己编写的table组件展示一下供大家查看。 小程序实现table的问题在于,自定义td的实现,而小程序没办法像react一样使用[代码]jsx[代码],也没办法像vue一样用[代码]作用域插槽[代码]传row行的信息给slot,但是小程序还是留有一样东西可以完成自定义td的功能。 抽象节点 这个特性自小程序基础库版本 1.9.6 开始支持。 有时,自定义组件模板中的一些节点,其对应的自定义组件不是由自定义组件本身确定的,而是自定义组件的调用者确定的。这时可以把这个节点声明为“抽象节点”。 微信官方api地址 通过抽象节点我们可以做到使用自定义组件通过key值分发组件内容到不同的td里。 具体的源码地址可点击下方查看,如果对你有帮助请点个star~~ 源码地址 具体的实现效果可以扫描下方小程序码。 [图片] API prop 参数 说明 类型 默认值 是否必填 columns 表格的配置 Columns[] [] true dataList 数据 any[] [] true getListLoading 请求列表的loading boolean false true showTipImage 无数据时的提示文本图片 boolean false true rowKey 用于指明行的唯一标识符,在勾选中有使用 string id false scrollViewHeight 控制可滚动区域高度。 string 600rpx false tipTitle 无数据时的提示文本主标题 string 提示 false tipSubtitle 无数据时的提示文本副标题 string 暂无数据 false scrollX 是否需要X轴滚动。 boolean false false select 控制是否出现勾选。 boolean false false selectKeys 勾选的初始值 any[] [] false generic:action-td 当列表项内具有操作列,需要在[代码]columns[代码]内添加[代码]type:action[代码]的一项,操作列的内容往往需要自定义,小程序不提供react,vue的[代码]rander函数[代码],所以使用到了抽象节点,该属性指明抽象节点的组件。操作列位置可以不固定,点击事件由[代码]bindclickaction[代码]触发 component undefined false isExpand 控制是否点击展开。 boolean false false expandValueKey 展开信息的key值 string false initExpandValue 当展开信息为空时的默认提示语 string ‘暂无信息’ false expandStyle 展开信息的最外层的样式 string ‘’ false generic:expand-component 如果展开区域的内容需要自定义,[代码]expandValueKey[代码]设置为空字符串,则切换到组件模式,传一个组件进来,展开区域的点击事件由[代码]bindclickexpand[代码]触发 component undefined false dynamicValue 给自定义内容的动态值,用于改变状态 ,建议{value:放的数据} object {} false Events 事件 解释 类型 bindclicklistitem 点击列表行事件 Function(e); e.detail.value = {index:number(当前行序号),item: any(当前行的内容)} bindclickexpand 点击展开内容事件 Function(e); e.detail.value = {type:(这个按钮的含义字段,如‘close’),index:(当前的行),item:(当前行的数据)};(这是我这里定义的结构,具体可以自己定义在expand-component里)} bindclickaction 点击抽象节点事件 Function(e); e.detail.value = {type:(这个按钮的含义字段,如‘close’),index:(当前的行),item:(当前行的数据)};(这是我这里定义的结构,具体可以自己定义在action-td里)} bindcheckkey 勾选事件 返回被勾选项的rowKey数组 Function(e); e.detail.value = any[]//(数组内每一项是rowKey字段定义的数据的toString()结果) bindscrolltolower 滚动触底 Function() bindscrolltoupper 滚动触顶 Function() column 列描述数据对象,是 columns 中的一项,Column 使用相同的 API。 事件 解释 类型 必填 title 字段名中文含义 string true key 字段名 string true width 单元格宽度 string false type 判断字段是否是自定义组件 ‘action’/undefined false render td内内容由函数返回 (value: any, item: any, index: number, data?: 当前页面的this.data) => any,// 设置内容 function false
2022-11-24 - 实战丨如何制作一个完整的外卖小程序(已开源)
最近微信小店开放了,赶着微信全面开放之前,把自己的小程序开源出来给大家使用~ 小程序效果 [图片] [图片] [图片] 开发心得 如何在项目中集成云开发 一开始项目并非基于云开发而开发的,目前考虑用云开发,因此,需要在项目中开启云开发的相关选项。 首先,在小程序文件夹中建立 [代码]cloud[代码] 文件夹,并在package文件中配置,建立用户登录的云函数并上传到微信小程序云中。相关的操作可以参考官方文档。 我在项目目录中添加了 [代码]cloud[代码] 和 [代码]miniprogram[代码] 两个目录,并在 [代码]project.config.json[代码] 文件夹进行配置 [代码]{ "miniprogramRoot": "./miniprogram" "cloudfunctionRoot": "./cloud/" } [代码] 开通云开发 配置完成后,可以点击控制台中的「云开发」来开通云开发。 [图片] 在云开发的界面中配置,并开通云开发。 [图片] 开通数据库集合 云开发不会自动创建数据库集合,因此,你需要手动创建集合。分别创建 店铺表Seller、分类表Category、商品表Food、订单表Order、地址表Address、用户表*_User*。 [图片] 数据操作 有了数据库的表后,就可以在代码中对数据进行操作了。 下方是我进行目录操作的代码。 [代码]const db = wx.cloud.database() const { showModal } = require('../../utils/utils') Page({ onLoad: function(options) { // 管理员认证 getApp().auth() if (options.objectId) { // 缓存数据 this.setData({ isEdit: true, objectId: options.objectId }) // 请求待编辑的分类对象 db.collection('Category') .doc(options.objectId) .get() .then(res => { // 获取分类信息 this.setData({ category: res.data }) }) } }, add: function(e) { var form = e.detail.value if (form.title == '') { wx.showModal({ title: '请填写分类名称', showCancel: false }) return } form.priority = Number.parseInt(form.priority) // 添加或者修改分类 // 修改模式 if (this.data.isEdit) { const category = this.data.category db.collection('Category') .doc(category._id) .update({ data: form }) .then(res => { console.log(res) showModal() }) } else { db.collection('Category') .add({ data: form }) .then(res => { console.log(res) showModal() }) } }, showModal() { // 操作成功提示并返回上一页 wx.showModal({ title: this.data.isEdit ? '修改成功' : '添加成功', showCancel: false, success: () => { wx.navigateBack() } }) }, delete: function() { // 确认删除对话框 wx.showModal({ title: '确认删除', success: res => { if (res.confirm) { const category = this.data.category db.collection('Category') .doc(category._id) .remove() .then(res => { console.log(res) wx.showToast({ title: '删除成功' }) wx.navigateBack() }) } } }) } }) [代码] 联表查询 在使用数据库时,难免要进行联表查询,云开发支持在云函数侧进行联表查询,你可以参考我的代码,来实现联表查询的功能。 [代码]const cloud = require('wx-server-sdk') cloud.init() const db = cloud.database() // 云函数入口函数 exports.main = async (event, context) => { const result = await db.collection('Food') .aggregate() .lookup({ from: 'Category', localField: 'category', foreignField: '_id', as: 'categories' }) .end() // .orderBy('priority', 'asc') // .get() console.log(result) return result.list } [代码] 文件上传 在小程序的操作中,难免会遇到需要进行图片上传的场景。在进行图片上传时,云开发提供了方便的云存储供我们查询数据。 在获取到文件的本地路径后,调用 [代码]wx.cloud.uploadFile[代码] 即可上传文件。 [代码]chooseImage() { wx.chooseImage({ count: 1, // 默认9 sizeType: ['compressed'], // 可以指定是原图还是压缩图,默认二者都有 sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有 success: res => { const tempFilePaths = res.tempFilePaths const file = tempFilePaths[0] const name = utils.random_filename(file) //上传的图片的别名,建议可以用日期命名 console.log(name) wx.cloud.uploadFile({ cloudPath: name, filePath: file, // 文件路径 }).then(res => { console.log(res) const fileId = res.fileID // 将文件id保存到数据库表中 db.collection('Seller').doc(this.data.seller._id) .update({ data: { logo_url: fileId } }).then(() => { wx.showToast({ title: '上传成功' }) // 渲染本地头像 this.setData({ new_logo: fileId }) }, err => { console.log(err) wx.showToast({ title: '上传失败' }) }) }) } }) } [代码] 微信支付逻辑的实现 作为一个商城,难免会有微信支付相关逻辑的实现。在这种情况下,可以借助云开发提供的微信支付云调用功能实现快速的 API 调用和接口的实现。 绑定商户 在使用云开发提供的微信支付时,需要先执行微信支付的绑定,在云开发控制台添加相应的商户号 [图片] 添加后微信会发来通知 [图片] 根据提示,开通账号即可。 [图片] 如果不绑定,将报“受理关系不存在”的错误 [图片] 函数代码调用 配置完成后,只需要在云函数中调用微信支付的接口,就可以实现相关调用的能力 [代码]const cloud = require('wx-server-sdk') cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) // 云函数入口函数 exports.main = async (event, context) => { console.log('请求中') console.log(cloud.getWXContext().ENV) let { orderId, amount, body } = event const wxContext = cloud.getWXContext() const res = await cloud.cloudPay.unifiedOrder({ body: body, outTradeNo: orderId, spbillCreateIp: '127.0.0.1', subMchId: '1447716902', totalFee: amount, envId: 'dinner-cloud', functionName: 'pay_cb' }) return res.payment } [代码] 这里 [代码]functionName: 'pay_cb'[代码]指的就是支付成功后,微信支付那侧给我的回调信息,后面我们就用它来更新我们的订单状态 小程序端代码调用 调用云函数后,会获得微信支付所需要的各种参数, [图片] 这个时候,就可以在小程序端调用微信支付接口,进行支付,相关代码可以参考 [代码]const { result: payData } = res wx.requestPayment({ timeStamp: payData.timeStamp, nonceStr: payData.nonceStr, package: payData.package, signType: 'MD5', paySign: payData.paySign, success: res => { console.log('支付成功', res) wx.showModal({ title: '支付成功', showCancel: false, success: () => { // 跳转订单详情页 wx.navigateTo({ url: '/order/detail/detail?objectId=' + order._id }) } }) }, ... [代码] 微信支付回调处理 微信统一下单里一个pay_cb回调函数,它是一个云函数,后续微信支付的支付信息将会发送在这个函数中,相应的,我们需要编写处理的方法 [代码]// 云函数入口文件 const cloud = require('wx-server-sdk') cloud.init({ // API 调用都保持和云函数当前所在环境一致 env: cloud.DYNAMIC_CURRENT_ENV }) const db = cloud.database() // 云函数入口函数 exports.main = async (event, context) => { console.log('支付回调') console.log(event) console.log(cloud.getWXContext().ENV) const orderId = event.outTradeNo const resultCode = event.resultCode if (resultCode === 'SUCCESS') { const res = await db .collection('Order') .doc(orderId) .update({ data: { status: 1 } }) console.log(res) return { errcode: 0 } } } [代码] 总结 云开发体验下来,优点自不必多说,微信登录与支付原生支持,调用与调试都很方便,特别是不用启本地服务开发,真的好用; 这个小程序的源码我已经开源了,你可以访问社区官网 获取源码,自行使用~ 作者:黄秀杰,16年开始从事小程序开发与技术布道,同名个人公众号「黄秀杰」。 云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为开发者提供高可用、自动弹性扩缩的后端云服务,包含计算、存储、托管等serverless化能力,可用于云端一体化开发多种端应用(小程序,公众号,Web 应用,Flutter 客户端等),帮助开发者统一构建和管理后端服务和云资源,避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。 产品文档:https://cloud.tencent.com/product/tcb 技术文档:https://cloudbase.net 技术交流加Q群:601134960 最新资讯关注微信公众号【腾讯云云开发】
2020-07-29 - 页面局部滑动的方法推荐 详解【scroll-view】【swiper】【overflow:scroll属性】区别
前言: 初期开发小程序的时候 我们可能遇到一个问题 一个scroll-view组件内的滑动与页面的滑动冲突 造成 scroll-view动画到边界后 页面才跟着滑动另外 有时可能遇到这样的需求 一个页面中有多处局部滑动 且 他们之间不能互相干扰 互相影响 而且大多数情况下 页面整体不能滑动 这时候我们通过文档 获取到的第一印象是使用scroll-view组件 或 使用swiper组件满足需求 而在实际的工程搭建上又会因为经验不足遇到许多坑 下面我们使用不同方法分别创建一个竖向的局部滑动区域 横向的参考竖向即可 多个滑动区域的使用三种方法创建对应组件 三种方法区别较大 需要根据实际场景选择 第一种方式 使用scroll-view方式创建一个滑动区域 我们创建一个长度为10的数组 在scroll-view内部 wxml: [图片] wxss: [图片] js: [图片] 注意 1.Page元素是该页面整体 类似于H5中的body 给其设置height:100%;变相屏蔽了页面的滑动事件 2.这里scroll-view组件除了设置scroll-y属性外 需要给list一个固定高度 才能生效 第二种方式 使用css属性 overflow-y:scroll 这里wxml和wxss稍作修改 其他的和上面相同 [图片] [图片] 其实使用css属性只是模拟了scroll-view组件的效果 但毕竟scroll-view组件提供了许多其他的属性和方法可供开发者操作 例如监控组件的滑动等 如果使用css的话 只有局部区域的滑动效果而已 第三种方式 使用swiper组件实现竖向滑动 wxml [图片] js [图片] wxss: [图片] 这里还是比较复杂的,其中swiper组件需要设置vertical属性为true 另外margin-next指 swiper-item与后面子元素的距离 介于我们要设置swiper内尽可能显示全部的子元素 margin-next应设置为swiper高度 减 swiper-item的高度 计算方法如下 使用 wx.createSelectorQuery() 方法获取swiper和swiper-item元素的属性 [图片] 预览图: [图片] 注意: 1.swiper的margin-next属性不支持 calc()动态计算高 因此只能使用在页面渲染完成后 获取滑动区域总体的高 - 元素内容的高 setdata 来渲染 2.swiper无论如何滑动 都会最终停在某个元素的顶端/左端 而上面两种方式可以scrollTop值可以停留在任何地方 3.swiper滑动到最后几个元素的时候 下方/右方还会留下空白位置 而上面两种方式scrollTop滑动到最后几个元素 滑动条不再滑动 下面/右方没有空白位置 4.swiper组件有 bindanimationfinish 这个方法监控 滑动动画的结束事件 而scroll-view只能通过 bindtouchend 拿到滑动手势的结束事件 swiper的这种特性可以满足特殊场景下的需求 比如无论如何滑动区域后 自动对焦 5.经过测试 swiper组件 在渲染子元素变多的情况下 性能会远小于 scroll-view 以5000个子元素为例 swiper 在安卓/IOS手机上的渲染速度已经严重影响用户体验 而scroll-view组件渲染可以在2秒内完成 并且实现滑动 因此在渲染数量在极限状态下 推荐使用scroll-view 6.如果想使用 scroll-view 模拟swiper的效果 可以使用 遮罩浮层盖住scroll-view主体 + 监听scroll-into-view事件 的方法达到效果 不过如果快速滑动 会造成高频使用 setdata 触发 scroll-into-view 事件造成页面撕裂 不同高度设备的适配: 但进一步想 现在设备五花八门 不同设备的宽高是不一样的 比如新出的安卓手机和iphone x/10/12屏幕都比较长,需要我们对滑动区域父元素进行高的计算 需要 height:calc()/width:calc() 和 createSelectorQuery 动态计算,一个页面顶部有一处固定广告 下面的区域是滑动区域 那么滑动区域的高为 height:calc(100% - 300rpx) 相关代码如下 另附一个可以多处区域滑动的页面 https://developers.weixin.qq.com/s/jgK6DNmR77hJ 作者:陶路 其他相关阅读: 1.swiper组件 https://developers.weixin.qq.com/miniprogram/dev/component/swiper.html 2..scroll-view组件 https://developers.weixin.qq.com/miniprogram/dev/component/scroll-view.html 3.动态获取页面元素方法 wx.createSelectorQuery https://developers.weixin.qq.com/miniprogram/dev/api/wxml/wx.createSelectorQuery.html
2020-06-02 - 微信小程序用户授权弹窗,获取用户信息。用户拒绝授权时,引导用户去重新授权
我们在开发小程序时,如果想获取用户信息,就需要获取用的授权,如果用户误点了拒绝授权,我们怎么样去正确的引导用户重新授权呢。今天就来给大家讲讲如果正确的引导用户授权。 老规矩,先看效果图 [图片] 从上图可以看出,我们在用户点击拒绝授权时,我们会弹出一个提示框,提示用户去设置页重新授权,当用户去授权页重新授权以后,我们再回到首页,点击获取用户信息时,就可以成功的获取到用户信息了。 如下图蓝色框里,就是我们成功的获取的用户信息。 [图片] 一,我们获取用户信息的时候需要用户授权 我们点击获取用户信息时,通常会弹出如下提示框,如果用户点击了取消,就再也没有办法通过点击授权按钮获取用户信息了。 [图片] 所以接下来我们要做的就是在用户拒绝了授权时,引导用户去设置页重新授权。 把获取用户授权的代码先贴给大家 [代码]<button open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 授权获取头像昵称 </button> [代码] 二,检测用户是否授权 我们在用户点击了上面定义的button按钮后,做权限检测。代码如下。 [代码] getUserInfo: function(e) { let that = this; // console.log(e) // 获取用户信息 wx.getSetting({ success(res) { // console.log("res", res) if (res.authSetting['scope.userInfo']) { console.log("已授权=====") // 已经授权,可以直接调用 getUserInfo 获取头像昵称 wx.getUserInfo({ success(res) { console.log("获取用户信息成功", res) that.setData({ name: res.userInfo.nickName }) }, fail(res) { console.log("获取用户信息失败", res) } }) } else { console.log("未授权=====") that.showSettingToast("请授权") } } }) }, [代码] 给大家简单解析下。 wx.getSetting :用来获取用户授权列表 if (res.authSetting[‘scope.userInfo’]) 代码用户授权成功,如果用户没有授权,就代表授权失败。 在授权失败时,我们调用that.showSettingToast()方法 三,showSettingToast方法如下 [代码] // 打开权限设置页提示框 showSettingToast: function(e) { wx.showModal({ title: '提示!', confirmText: '去设置', showCancel: false, content: e, success: function(res) { if (res.confirm) { wx.navigateTo({ url: '../setting/setting', }) } } }) } [代码] 这方法做的就是引导用户去设置页。 四,我们的设置页 [图片] 我们的设置页其实很简单,只有上图这么一段代码。 [图片] 五,去系统设置页。 我们上面第四步的button按钮,点击以后,就会去系统设置页。 [图片] 可以看到系统设置页,有一个开关,当用户点击开关时,就可以重新授权啦。 [图片] 重新授权成功以后,我们回到首页,就可以成功的获取到用户信息了。 [图片] 到这里我们就成功的实现了引导用户授权的功能了。 把index.wxml和index.js代码贴出来给大家 index.wxml [代码]<!--index.wxml--> <button open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 授权获取头像昵称 </button> <text>{{name}}</text> [代码] index.js [代码]//index.js Page({ getUserInfo: function(e) { let that = this; // console.log(e) // 获取用户信息 wx.getSetting({ success(res) { // console.log("res", res) if (res.authSetting['scope.userInfo']) { console.log("已授权=====") // 已经授权,可以直接调用 getUserInfo 获取头像昵称 wx.getUserInfo({ success(res) { console.log("获取用户信息成功", res) that.setData({ name: res.userInfo.nickName }) }, fail(res) { console.log("获取用户信息失败", res) } }) } else { console.log("未授权=====") that.showSettingToast("请授权") } } }) }, // 打开权限设置页提示框 showSettingToast: function(e) { wx.showModal({ title: '提示!', confirmText: '去设置', showCancel: false, content: e, success: function(res) { if (res.confirm) { wx.navigateTo({ url: '../setting/setting', }) } } }) }, }) [代码] 有任何关于编程的问题都可以留言或者私信我,我看到后会及时解答 编程小石头,码农一枚,非著名全栈开发人员。分享自己的一些经验,学习心得,希望后来人少走弯路,少填坑。 有任何关于小程序的问题可以加我微信:2501902696(备注小程序) 视频讲解: https://edu.csdn.net/course/detail/9531
2019-07-26 - 开发工具调试器区域显示语言能不能改成中文?
微信开发者大多数是国内用户,不是每一个人都是英语专家,特别是有些小白还半路出家成程序员的,大多数人都是只使用控制台和网络这两个部分,对其他部分的东西看不懂也没兴趣去想那英文是什么意思,除了资深程序员之外,开发人员对调试器工具利用率太低了,总体开发效率也比较低。建议调试区域的语言也和其他地方一样能够切换中文版,国内的软件,对自己人友好点。
2021-03-17 - radio组件实例代码有bug
https://developers.weixin.qq.com/miniprogram/dev/component/radio.html <radio value="{{item.value}}" checked="true"/> 这段代码导致radio组件每次都是循环的最后一个item默认选中, 应该为 <radio value="{{item.value}}" checked="{{item.checked}}"/>
2021-12-19 - 地理位置接口新增与相关流程调整
一、地理位置接口新增说明 由于精确地理位置接口只允许部分类目的小程序申请使用,为了满足开发者在更多场景使用地理位置接口,自 2022 年 7 月 14 日起,新增获取模糊地理位置接口(wx.getFuzzyLocation)。同时为保障用户合法权益,该接口调用前需进行准入开通申请,该接口准入规则与 wx.chooseLocation 一致。 wx.getFuzzyLocation 接口说明: 1、该接口返回的是经过模糊处理的经纬度坐标; 2、该接口支持返回 wgs84 或 gcj02 两种类型的坐标; 3、该接口需要用户授权 scope.userFuzzyLocation。 二、app.json 的配置指引 为了开发者能够正常使用获取模糊地理位置等接口,以及后续对于代码提审环节的优化(见「三、地理位置接口使用流程」),自 2022 年 7 月 14 日起,开发者在使用地理位置相关接口时(共计 8 个,见表1),需要提前在 app.json 中进行配置。 1、需配置的接口列表 [图片] 表1 2、配置规则 1)在代码中使用的地理位置相关接口(共计 8 个,见表1),开发者均需要在 app.json 中 requiredPrivateInfos 配置项中声明,代码格式如下: [图片] 2)表1中模糊位置信息(序号1)和精确位置信息(序号2-5)是互斥的,即声明了模糊位置信息就无法声明精确位置信息。若同时声明模糊位置信息和精确位置信息,则在编译代码时出现错误; 3)注意:自 2022 年 7 月 14 日后发布的小程序,如果未在 app.json 中声明表1中的相关接口,则小程序调用这些接口(表1)时会出现错误,在 2022 年 7 月 14 日之前发布的小程序不受影响; 4)对于第三方开发者,需要在上传代码时通过参数在 ext.json 中声明其需调用的地理位置相关接口,配置规则和普通小程序的配置规则相同。 三、地理位置接口使用流程 自 2022 年 7 月 14 日起,开发者如需在最新版本发布后使用地理位置相关接口,除需完成接口权限开通外,还需在 app.json(或ext.json)配置环节,具体如下: 1、接口权限开通 以下 8 个接口需完成准入开通流程:wx.getFuzzylocation、wx.getLocation、wx.onLocationChange、wx.chooseAddress、wx.choosePoi、wx.chooseLocation、wx.startLocationUpdate、wx.startLocationUpdateBackground 1)普通开发者:需要在 “小程序管理后台 -「开发」-「开发管理」-「接口设置」” 中完成权限申请; 2)第三方开发者:可通过 apply_privacy_interface 接口完成权限申请。 2、app.json(或 ext.json)配置 1)普通开发者:需在 app.json 中声明其需调用的地理位置相关接口,具体配置流程见「二、app.json 的配置指引」; 2)第三方开发者:需要在上传代码时通过参数在 ext.json 中声明其需调用的地理位置相关接口(配置方式:可通过 commit 接口配置)。 同时,为了提升开发者体验,平台在代码提审环节会协助开发者对地理位置接口进行检测,如检测出代码中包含未完成准入开通的地理位置接口,平台将再次提醒开发者确认是否需使用相关接口。 1)普通开发者:若无需使用,开发者可在提审时确认不使用该接口,即可正常进行代码提审。小程序审核通过且新版本发布完成后,平台将对小程序确认不使用的接口关闭使用权限; 2)第三方开发者:若无需使用,可在提审时通过参数声明不使用该接口(声明方式:可通过 submit_audit 接口配置),即可正常进行代码提审,审核通过后发布上线,将对其声明不使用的接口关闭使用权限。 以上调整将仅对所有小程序生效。 微信团队 2022年6月1日
2023-09-26 - 小程序 左上角返回按钮 可以自定义设置吗?
[图片]就是类似于这种的~~~点击可以跳转到自定义的页面~~~
2018-12-07 - 微信小程序动态绑定style样式
第一种,根据data的值判断显示什么颜色 // js文件 data:{ selected:true } // wxml <view class="tab-header"> <view style="background:{{selected ? 'red' : 'blue'}}" >红色</view> <view style="background:{{selected ? 'blue' : 'red'}}" >蓝色</view> </view> 第二种:绑定data的值,当需要修改颜色的时候直接在js文件里面setData({})改变color的值即可 // js文件 data:{ color:"red", color1:"blue" } // wxml <view class="tab-header"> <view style="background:{{color}}" >红色</view> <view style="background:{{color1}}" >蓝色</view> </view>
2021-07-16 - wx.createSelectorQuery()怎么获取当前页面组件中的元素?【解决】
首先, wx.createSelectorQuery()这个方法,在当前页面中获取元素,没有问题。在我自定义的组件中获取,也可以。 但现在碰到一个问题,我需要获取一个第三方组件的高度。那么就需要获取该组件内的一个元素的高度。 现在经过各种尝试都无法获取到。 后来发现wx.createSelectorQuery().in(组件),这个方法,可以放个组件进去。但是虽然没有报错,却也没有任何执行结果。 代码类似如下: wx.createSelectorQuery().in('组件名').select('.组件内元素的class').boundingClientRect(function (res1) { console.log("res1", res1); }).exec(); 请问大家都是用什么办法在组件外,获取指定组件部分元素的高度的呢? ==================================================== 解决办法: wx.createSelectorQuery().in(this.selectComponent('#navTabs')).select('.van-ellipsis').boundingClientRect(res1 => { console.log("res1", res1); }).exec(); 给van-tabs加了一个id="navTabs",然后从源码中找到需要获取的class值,然后就获取到了。
2019-11-25 - 自定义导航栏高度精确适配方案
之前自己做小程序,凡是自定义导航栏的地方,我都是 状态栏高度用 getSystemInfo 中的 statusBarHeight导航栏高度固定 44 px 不过最近发现在几款安卓较新的机型上,状态栏高度都OK,但导航栏的高度要么大了要么小了。于是我又重新研究了一下,尝试归纳目前(截至发文 2021-06-08)小程序的导航栏高度的规律,总结如下。 小程序自定义导航栏高度精确适配方案 iOS 端 状态栏高度用 getSystemInfo 中的 statusBarHeight导航栏高度固定 44 px导航栏高度 44 px 的表现效果,与默认导航栏("navigationStyle": "default")一致,但这种情况下胶囊不是上下居中的,各位需根据具体场景来自行选择方案。如果想要胶囊精确地上下居中,可使用下方 Android 端的方案Android 端 状态栏高度用 getSystemInfo 中的 statusBarHeight导航栏高度根据胶囊位置与高度计算,计算方式如下let sysInfo = wx.getSystemInfoSync(); let menuInfo = wx.getMenuButtonBoundingClientRect(); let navigationBarHeight = (menuInfo.top - sysInfo.statusBarHeight) * 2 + menuInfo.height; 按照胶囊位置计算出的导航栏高度,与默认导航栏("navigationStyle": "default")一致,且这种情况下胶囊是上下居中的 以上的方案经过多款 iOS 设备与 Android 设备的测试验证,但我们能用于测试的设备有限,得出的结论并不 100% 适用于所有设备。若有补充欢迎在评论区发言。
2021-06-08 - 微信小程序swiper高度动态适配(子元素高度不固定)
示例代码地址 https://github.com/s568774056/swipe.git 对于整页都是swiper的情况下。例如下面这张图: [图片] 则可以使用如下css [代码] [代码] [代码]swiper,swiper-item{[代码] [代码] [代码][代码]height[代码][代码]: [代码][代码]100[代码][代码]vh [代码][代码]!important[代码][代码];[代码][代码]}[代码] [代码] [代码] [代码]或者 [代码] [代码] [代码] [代码][代码] [代码][代码] swiper,swiper-item{ height: calc(100vh - 75rpx) !important; } [代码][代码] [代码] [代码] 对于swiper占据部分高度的情况下。 [图片] 使用如下代码 原理为在[代码]swiper-item[代码][代码][代码]的最上面和最下面插入空view,并利用wx api获取两个之间的高度差,然后设置给[代码]swiper[代码]。 细节方面需要自己调整下。为什么小程序不把这个组件做好呢?还得自己计算- -! <swiper class='hide' bindanimationfinish="swiperChange" style="height:{{swiper_height}};" current="{{isIndex}}"> <swiper-item wx:for="{{roomList}}" wx:for-item='room' wx:for-index="index"> <view id="start{{index}}" class='start-view'></view> <block wx:for="{{imgUrls}}" wx:for-item='path' wx:for-index="img-index"> <image mode="aspectFill" src="{{path}}" /> </block> <view id="end{{index}}" class='start-view'></view> </swiper-item> </swiper> [代码][代码][代码][代码] swiper { margin-top: 45rpx; } Page({ data: { roomList: ['Room1', 'Room2', 'Room3'], imgUrls: [ 'https://images.unsplash.com/photo-1551334787-21e6bd3ab135?w=640', 'https://images.unsplash.com/photo-1551214012-84f95e060dee?w=640', 'https://images.unsplash.com/photo-1551446591-142875a901a1?w=640' ], swiper_height: 0, isIndex:0 }, onLoad: function () { this.autoHeight(); }, changeNavBar: function (e) { this.setData({ isIndex: e.detail }); }, swiperChange: function (e) { this.setData({ isIndex: e.detail.current }); this.autoHeight(); }, autoHeight() { let { isIndex } = this.data; wx.createSelectorQuery() .select('#end' + isIndex).boundingClientRect() .select('#start' + isIndex).boundingClientRect().exec(rect => { let _space = rect[0].top - rect[1].top; _space = _space + 'px'; this.setData({ swiper_height: _space }); }) } }) 参考文章https://developers.weixin.qq.com/community/develop/doc/00008aaf4a473056d1c69a8b253c04
2019-09-04 - 动态设置自定义组件内元素的高度
动态设置的行内高度样式跟实际显示的样式不一样,在微信开发者工具上面切换了好几个机型都这样,真机上也是这样的 [图片]
2019-08-06 - 请问如何动态获取某个元素的高度?
[图片] [图片] 我要做展开收起的效果,需要根据高度去判断是否显示展开按钮, 先谢谢大家了
2019-12-09 - 小程序动态获取的元素高度后赋值失败?
[图片] [图片]
2020-02-22 - 小程序如何获取手机屏幕宽度和高度以及如何获取手指按下的XY坐标?
请问 小程序如何获取手机屏幕宽度和高度以及如何获取手指按下的XY坐标?
2021-01-27 - JavaScript函数与拓展
JavaScript进阶内容学习:函数与小程序特有的JS。 课程最终代码,点此领取:https://share.weiyun.com/5Kb7U6O [视频]
2021-11-26 - 小程序开发起步
学习 5 节课程,从 0 至 1 做第一个属于你的小程序,深入浅出了解小程序开发。本系列视频,由腾讯课堂 NEXT 学院、微信学堂联合出品。
2022-03-24 - 做一个名片小程序
本节课程,以制作一个名片小程序为案例,快速学习了解小程序前端开发。 iframe class="embed-responsive-item vqq-player" type="text/html" width="640" height="390" src="https://v.qq.com/txp/iframe/player.html?vid=w3552hggw3g&disableplugin=IframeBottomOpenClientBar&&auto=0" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen>
2024-06-12 - 小程序之Hello World
本节课程主要围绕第一个 Hello world 小程序的开发,带你了解小程序开发者工具及基本框架。 iframe class="embed-responsive-item vqq-player" type="text/html" width="640" height="390" src="https://v.qq.com/txp/iframe/player.html?vid=p0872j7l9xw&disableplugin=IframeBottomOpenClientBar&&auto=0" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen>
2022-10-08 - 小程序与h5页面之间跳转?
需求是 小程序A页 -> 内嵌H5 ,进入h5页面后,如果用户点击左上角的返回按钮,或者手势返回,要返回到另一个h5页面,有什么解决办法么??
2021-03-26 - H5和小程序间的通信
1.h5向小程序发送消息,根据官方文档,网页向小程序 postMessage 时,会在特定时机(小程序后退、组件销毁、分享)触发并收到消息。小程序页面通过 bindmessage 绑定的函数读取 post 信息。 2.微信小程序怎么向H5发送消息呢? 目前常用的方法是通过设置webview指向网页的链接(url)拼接参数,然后H5页面截取url中的参数的方式来通信。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 基于以上两种相互间的通信和传参,现在要解决H5页面A,跳转到H5页面B,在页面B中做了一些操作(这些操作会改变了页面A中的一些数据),然后返回到页面A,希望将这些改变反馈到页面A。 如果页面A跳转到页面B是使用的location.href,操作完成后完返回上一页(页面A)用的是window.history.go(-1)。这时是不会触发visibilitychange事件,可以使用pageshow事件window.addEventListener('pageshow', (event) => { if (event.persisted) { // 是否从缓存读取 } }) 2.第二种方式是使用hashchange来处理的,具体操作如下: 页面B中发送postMessage,增加标识符test,值为test_时间戳,用来告知webview,返回上一页面的时在页面A的url后拼接#test_。(建议使用时间戳,如果是固定值,hashchange之后执行一次) webview中接收页面B发送的消息postMessage,判断是否存在test,如果有则将test的值存入全局变量。在webview的onShow中判断全局变量中是否有test,如果有,修改webview的src,增加hash参数#test_,如果没有则不增加。清除全局变量test。由于只修改了hash部分,页面不会重新刷新。 页面A中绑定hashchange事件,hashchange事件执行自定义逻辑方法,读取hash参数,调用window.history.go(-1),恢复history。
2021-08-03 - 微信小程序页面间图片传递?
第一页中从本地传入了多张照片,点击按钮跳转到第二页,希望实现第二页读取第一页传入的照片怎样实现。 page1: chooseImage: function () { var _this = this, pics = this.data.pics; wx.chooseImage({ count: 9 - pics.length, sizeType: ['original', 'compressed'], sourceType: ['album', 'camera'], success: function (res) { var imgSrc = res.tempFilePaths; pics = pics.concat(imgSrc); if (pics.length >= 6) { _this.setData({ isShow : (!_this.data.isShow) }) }else { _this.setData({ isShow: (_this.data.isShow) }) } _this.setData({ pics: pics }) }, fail: function () { // fail }, complete: function () { // complete } }) }, previewImage: function (e) { var current = e.target.dataset.src wx.previewImage({ current: current, urls: this.data.pics }) } pages2: var sides = ['1.jpg', '2.jpg','3.jpg', '4.jpg','5.jpg', '6.jpg'] 请问如何把sides改为读取第一页从本地上传的图片
2021-11-10 - 小程序图片上传,存储,获取,显示
我们在做小程序开发时,难免会遇到图片上传的功能,我们如果自己搭建图片服务器的话,成功太大了,并且还要写后台程序来接收上传的图片,还要有存储服务器。好在小程序云开发为我们提供了云存储的功能,这样我们就可以轻松的实现小程序图片的上传和存储。 老规矩,先看效果图 [图片] 本节知识点 1,小程序图片的选取 2,小程序图片的上传 3,小程序图片的存储 4,获取云端图片并显示 下面就来具体讲解下具体实现步骤 图片的选择和上传 index.wxml文件如下 [代码] <view class='item_root' bindtap='chuantupian'> <text>{{zhaopian}}</text> <view class='right_arrow' /> </view> [代码] index.js文件如下 [代码] //上传图片 chuantupian() { let that = this; let timestamp = (new Date()).valueOf(); wx.chooseImage({ success: chooseResult => { wx.showLoading({ title: '上传中。。。', }) // 将图片上传至云存储空间 wx.cloud.uploadFile({ // 指定上传到的云路径 cloudPath: timestamp + '.png', // 指定要上传的文件的小程序临时文件路径 filePath: chooseResult.tempFilePaths[0], // 成功回调 success: res => { console.log('上传成功', res) wx.hideLoading() wx.showToast({ title: '上传图片成功', }) if (res.fileID) { that.setData({ zhaopian: '图片如下', imgUrl: res.fileID }) } }, }) }, }) }, [代码] 到这里其实我们就可以实现图片的选取和上传功能了。 下面讲讲具体是如何实现的 首先我们通过wx.chooseImage来获取相册里的图片 再获取照片成功后,我们用当前时间戳命名图片,然后使用 wx.cloud.uploadFile方法来实现图片的上传 在上传成功后,会有如下回调。下图中的filenId就是我们在云存储中的路径,可以直接用这个路径来获取图片并显示的。 [图片] 到这里我们就轻松的实现了小程序图片上传的功能,是不是很简单。 有任何关于编程的问题都可以加我微信2501902696(备注编程开发) 编程小石头,码农一枚,非著名全栈开发人员。分享自己的一些经验,学习心得,希望后来人少走弯路,少填坑。 视频讲解地址:https://edu.csdn.net/course/play/9604/281187 [图片]
2019-06-11 - 小程序怎么从文件里面选而不是会话中选择文件上传?
小程序怎么上传其他类型文件,从文件里面选而不是会话中选择文件?
2021-03-16 - 小程序扩展file-uploader真机测试服务器不能接收数据,怎么回事?
电脑测试正常,手机真机测试出现这个问题 [图片][图片]
2021-07-27 - 小程序扩展组件file-uploader怎么引入,或有例子中吗?
[图片]
2021-07-27 - 小程序可以调取手机文件夹选择文件上传吗?
小程序可以调取手机文件夹选择文件上传吗?
2020-07-22 - 小程序端如何读取手机存储里的文件?
类似下面小程序,本地文件的效果(我目前小程序只发现可以读取小程序自己存下来的文件) [图片]
2020-11-27 - 微信开发者工具占用CPU和内存很高,怎么解决?
[图片] 打开模拟器就飙升,这让开发者怎么开发?
2020-12-10 - 小程序开发者工具为什么狂吃cpu内存? 动不动就崩溃了。
[图片]
2019-11-19 - 为啥小程序的开发工具占内存和CPU这么高~~~~~~~~~?
[图片]
2020-07-31 - 为什么我没有在使用微信开发者工具时,微信开发者工具要吃这么多CPU呢?
Mac 系统:10.13.6 微信开发者工具:Stable 1.05.2105170 场景:我把微信开发者工具开着,之前在写小程序代码,后来在用Intellij IDEA写代码加接口,已经至少2个小时没有用微信开发者工具了,突然我的电脑风扇声音很大,一会又会安静下来,过一会风扇又会声音很大,打开活动监视器,都是微信开发者工具在吃CPU,我想问下,这个情况是不是工具BUG [图片] [图片]
2021-05-28 - 为什么小程序能占用这么多内存和cpu
详细情况如图 [图片]
2018-05-22 - 最新版本开发者工具 吃CPU耗内存严重
吃内存严重,每天都要重启N次 尤其是如果晚上没关闭 第二天来了 内存直接吃满 狂跑CPU 使用一会儿 退出工具 99%卡死 必须强制结束 [图片] [图片] 系统: mac 10.12.6 开发工具版本: 已经更新为官方最新 1.01.170907 版本
2017-09-13 - 微信开发工具为什么这么吃CPU
[图片] 编译的时候经常会出现cpu占用率满格
2019-08-12 - 【笔记】小程序中的水平与垂直居中
在复习水平居中与垂直居中时发现居然有点忘了 因此写个笔记下来记录一下 只要涉及到CSS就绕不开定位问题,尤其是盒子居中。居中又分为水平居中和垂直居中,有多种实现方式,下面我便一一列出来。 水平居中 inline元素:text-align: center block元素:margin: 0 auto absolute元素:left: 50% + margin-left负值(值为该元素宽度的一半) absolute元素:left: 50% + transform: translateX(-50%) 垂直居中 inline元素:line-height的值等于height值 absolute元素:top:50%+margin-top负值(值为该元素高度的一半) absolute元素:top:50%+transform: translateY(-50%) absolute元素:有固定宽高度+top,left,bottom,right=0 + margin:auto 水平垂直居中 就是上述的水平居中+垂直居中合起来 这里我举几个常用的例子: 1. 放在定位是relative盒子内的absolute盒子: top: 50%;left: 50%;transform: translate(-50%,-50%); [图片] [图片] 2. 知道盒子的宽度和高度 top: 50%;left: 50%; 加上 margin-left负值(值为该元素宽度的一半);margin-top负值(值为该元素高度的一半) [图片] [图片] 3. 放在定位是relative盒子内的absolute盒子且该盒子有固定宽高: top,left,bottom,right=0 + margin:auto [图片] [图片] 4. CSS3弹性布局(flex) 如果使用CSS3的弹性布局(flex)的话,问题就会变得容易多了。使用CSS3的弹性布局很简单,只要设置父元素设置成 display:flex // flex布局 align-items:center;// 元素水平居中 justify-content:center;// 元素垂直居中 [图片] [图片] 欢迎大家在评论区提出问题 觉得文章对你有帮助的不妨点个赞~
2021-11-13 - 微信小程序云开发教程-墨刀原型工具入门
本小节,我们将学习墨刀原型工具的基本使用。 [图片] 墨刀主要有3大功能,1是用来做产品原型设计,2是可以非常方便地进行功能和效果演示,3是为前端工程师提供了样式的开发标注。 [图片] 原型的开发,我们可以分为5步,第一步,建立页面,第二步,使用组件进行布局(页面结构),第三步,为组件设置样式(变得更好看些),第四步,给各个按钮之间添加跳转链接,第五步,将做好的原型进行预览和发布。 下面我们具体一步步来看。 1. 进入墨刀官网:https://modao.cc/,注册墨刀账号; 2. 点击“进入工作台”; [图片] 3. 点击“新建”->“项目”; [图片] 4. 点击新建页面; [图片] 5. 使用组件布局; [图片] 6. 设置组件样式; [图片] 7.设置按钮的跳转链接; [图片] 8. 运行预览原型的效果; [图片] 下面,请根据教学视频进行学习和操作。
2020-09-06 - 扫描普通链接二维码跳转小程序,可以传递动态生成的参数吗
各位大神,请教一下,例如: https://www.xxx.com/miniprogram?id=123 这个id=123的参数,是只能在微信小程序后台配置的时候写死吗?如果我想传递动态的参数,那要怎么做呢?并且看操作步骤里,需要下载验证文件放到服务器指定目录下,前端代码是托管在微信服务器的,又如何把这个验证文件放到指定目录下呢?如果是这个文件是放到开发者自己服务器指定目录的,是要在开发者自己的服务端重定向到小程序界面
2018-03-27 - 生成带参数二维码如何带多个参数?
请教一个,getwxacodeunlimit生成带参数小程序二维码,为什么只有一个参数的时候可以生成成功,但是如果用&或者其他字符拼接多个参数,生成不成。有经验的请指导一下 [图片]
2019-08-06 - 扫普通链接二维码打开小程序如何传递动态参数?
后台配置好的地址,如 https://baidu.com/mc?code=1 通过这个生成的二维码是可以打开,那么如果 code=2就打不开了。如何传递动态参数
2019-09-25 - 如何生成带参数的小程序码?
首先要看什么需求带的这个问题? 今天在实现一个需求:分享小程序码到朋友圈,然后有人扫码完成助力,也就是相当于拉新 具体交互截图如下所示 [图片] [图片] 这里就要涉及到,该小程序码是谁生成的,小程序码要带生成者的openid信息,涉及到生成带参数的小程序码的api https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/qr-code/wxacode.getUnlimited.html 获取小程序码,适用于需要的码数量极多的业务场景。通过该接口生成的小程序码,永久有效,数量暂无限制。 更多用法详见 获取二维码。 调用方式: HTTPS 调用云调用 由于本次在云开发中使用,本文章代码用云调用方式实现, 创建一个云函数qrcode const cloud = require('wx-server-sdk') cloud.init() exports.main = async (event, context) => { try { const result = await cloud.openapi.wxacode.getUnlimited({ scene: event.userInfo.openId }) console.log(result) return await cloud.uploadFile({ cloudPath: 'qrcode/' + event.userInfo.openId +'.png', fileContent: result.buffer, //二进制数据 success: res => { // 返回文件 ID console.log(res.fileID) }, fail: console.error }) } catch (err) { console.log(err) return err } } 占位 onGetQrcode: function() { let that = this; // 调用云函数 wx.cloud.callFunction({ name: 'qrcode', data: {}, success: res => { console.log('[云函数] [qrcode]: ', res) }, fail: err => { console.error('[云函数] [qrcode] 调用失败', err) wx.navigateTo({ url: '../deployFunctions/deployFunctions', }) } }) } 占位 [图片][图片][图片] 占位 生成带参数的二维码之后,便可以在业务代码完成具体的逻辑。本文不往下阐述
2020-02-18 - 新能力解读:小程序后台持续定位功能
在 2019 年 7 月 30 日发布的小程序基础库 v2.8.0 版本中,新增了小程序后台持续定位功能,在这篇文章中,将为你介绍这个能力的用途和用法。 新增的后台持续定位能力能干嘛? 在基础库版本 v2.8.0 版本以前,小程序提供的 API 仅有 [代码]wx.openLocation[代码]、[代码]wx.getLocation[代码] 和 [代码]wx.chooseLocation[代码],这些 API 都仅能用于某一时刻用户位置的获取和选择,这导致在进行产品设计上,是无法完成对于一些具有实时性要求的需求。所有的用户位置状态都是一个特定的时刻。 新增的后台持续定位能力可以让你在你的地图应用中实现实时的定位。在没有该能力之前,如果你需要实现类似的功能,需要每隔一秒获取一次地址,以获取当前用户的位置,并进行比较,但晒在新的后台持续定位能力中,你可以直接在 [代码]wx.onLocationChange[代码] 方法中获取到变动后的位置,相比于之前的轮询的方式,新的方式会更加的省电。 新增的后台持续定位能力应当如何使用? 在使用新的后台持续定位能力时,你需要根据实际的情况,选择使用 [代码]wx.startLocationUpdate[代码] 或 [代码]wx.startLocationUpdateBackground[代码] 从而开启自动获取数据。 随后,使用 [代码]wx.onLocationChange[代码] 来获取变动后的位置,从而对该位置进化后续的业务逻辑的判断。 当你使用完成后,需要使用 [代码]wx.stopLocationUpdate[代码] 来禁用后台持续定位能力,节省设备电量。 后台持续定位能力使用注意事项? 在使用后台持续定位能力时需要注意两点: 调用前需要 用户授权 scope.userLocationBackground 该功能从基础库 2.8.0 开始支持,低版本需做兼容处理。
2019-08-04 - wx.getLocation 返回定位精度不准问题
- 需求的场景描述(希望解决的问题) wx.getLocation 获取定位的时候,用的gcj02,altitude传入true,返回的是小数点后6位的经纬度。发现手机真机定位的时候返回定位精度不准,有时候位置还可以,有时候偏了几百米。当应用需要精准定位,偏了几百米,这误差有点不能接受,用户完全找不到地方啊。 - 希望提供的能力 像百度地图Android定位SDK提供GPS、基站、WI-FI、地磁、蓝牙、传感器等多种定位方式,适用于室内、室外多种定位场景。但百度地图微信小程序API不提供定位功能,定位用的也是小程序的wx.getLocation。目前也没有发现微信小程序自身提供高精度定位,希望微信小程序能提供高精度定位或 有其他方法解决定位精度不足的问题。
2018-09-07 - 微信小程序现在是否支持录屏功能?
微信小程序现在是否支持录屏功能?如果不支持,自己实现的话,能有什么思路?
2019-11-22 - 小白入门必看 ‘’微信小程序地图定位开发教程‘’
前言 目前腾讯位置服务提供路线规划、地图选点、地铁图、城市选择器插件四款插件产品,本篇博客主要针对地图选点功能进行实现。 开通腾讯位置服务 1、进入微信公众平台 2、登录进入小程序后台,选择 “开发 - 开发工具 - 腾讯位置服务” [图片] 3、点击 “开通”,进入授权扫码界面 [图片] 4、使用微信扫码进行授权 [图片] 5、绑定开发者账号 [图片] 接入插件 1、在小程序后台,选择 “设置 - 第三方设置 - 插件管理”,点击 “添加插件” [图片] 2、搜索 “腾讯位置服务地图选点” 进行添加 [图片] 开发者密钥配置 1、申请开发者密钥 2、设置KEY的 “启用产品” a、勾选微信小程序,设置授权 APP ID [图片] 授权 APP ID 可以通过 “设置 - 基本设置” 的账号信息进行查看 [图片] b、勾选 “WebService API” [图片] 小程序插件需要使用WebService API的部分服务,所以需要给使用该功能的KEY配置相应权限。 如果填写了域名白名单,需要把[代码]servicewechat.com[代码]域名添加进域名白名单中,否则小程序下将无法正常使用WebServiceAPI服务。 插件的使用 1、引入插件 地图选点appId: wx76a9a06e5b4e693e [代码]// app.json { "plugins": { "chooseLocation": { "version": "1.0.5", "provider": "wx76a9a06e5b4e693e" } } } [代码] 2、设置定位授权 地图选点插件需要小程序提供定位授权才能够正常使用定位功能 [代码]// app.json { "permission": { "scope.userLocation": { "desc": "你的位置信息将用于小程序定位" } } } [代码] 3、代码实现 a、js代码 [代码]"use strict"; const chooseLocation = requirePlugin('chooseLocation'); Page({ data: { address: "", locationName: "" }, onShow: function () { // 从地图选点插件返回后,在页面的onShow生命周期函数中能够调用插件接口,取得选点结果对象 // 如果点击确认选点按钮,则返回选点结果对象,否则返回null const location = chooseLocation.getLocation(); if(location){ this.setData({ address: location.address?location.address : "", locationName: location.name?location.name : "" }); } }, //显示地图 showMap() { //使用在腾讯位置服务申请的key(必填) const key = ""; //调用插件的app的名称(必填) const referer = ""; wx.navigateTo({ url: 'plugin://chooseLocation/index?key=' + key + '&referer=' + referer }); } }); [代码] [代码]plugin://chooseLocation/index[代码] 接口参数说明: [图片] b、wxml代码 [代码]<!--index.wxml--> <view class="container"> <button bindtap="showMap">选择位置</button> <view style="margin-top:10px">地址:{{address?address:"暂无"}}</view> <view style="margin-top:10px">名称:{{locationName?locationName:"暂无"}}</view> </view> [代码] 4、效果实现 [图片] 作者:盛夏温暖流年 链接:https://blog.csdn.net/j1231230/article/details/112352787 来源:CSDN 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
2021-04-30 - 微信小程序生成二维码
最近比较忙,好久没有写文章了,今天抽时间来给大家讲讲如何使用小程序生成二维码。 老规矩,先看效果图 [图片] 通过上图可以看出,我们是先输入一个网站,或者自己想输入的任何信息。然后点击生成二维码,就可以生成我们想要的二维码了。拿出微信来扫描下,可以识别出我们输入的内容。 扫描后的结果如下 [图片] 这样我们就可以实现生成一个网址二维码,然后用户扫描这个二维码,就可以进入我们指定的网址的功能了。 使用场景 1,生成网址二维码 2,生成桌号二维码,识别点餐 3,生成订单二维码,扫码验证 4,自己做付款二维码 。。。。。 一,创建小程序 这个我讲过很多遍了,还不知道如何创建小程序的同学去翻看下我之前的文章。 二,创建qrcode.wxml [图片] 三,简单的用了点样式 qrcode.wxss [图片] 四,导入qrcode.js到utils目录下。 [图片] 这个qrcode.js是我们生成二维码的核心工具类。我会把这个工具类放到网盘里,需要的同学加我v信获取:2501902696(备注小程序,否则不通过奥) 五,编写我们生成二维码的逻辑。 [图片] 其实到这里就可以完整的实现小程序生成二维码的功能了。 [图片] 工具类和源码已经放到网盘,需要的同学留言或者私信我。
2019-10-22 - 微信小程序能提供防截屏录屏的功能么?
目前有开发一个类似于视频会议的小程序,主要目的是提供商家对普通用户进行远程视频方案讲解的功能,考虑到一个方案的保密性与安全性,小程序这边能否开放防截屏录屏的功能(原生App是有这样的能力的)。
2020-03-09 - 针对微信小程序被反编译问题,如何保护最大程度原创小程序的权益
许多原创的微信小程序,被技术人员通过反编译技术或者工具,将小程序前端代码完整的反编译down下来。 针对这种情况怎么最大程度上保护,开发者的权益? 1.除了人工发现,原创代码在未进行传播的情况下,被其他小程序账号上架,进行举报投诉下架(这种非常损耗人力,效率低下)。 2.代码层面保护:在上传部署过程中进行代码混淆加密? 3.微信本身是否考虑:运行小程序后下载本地的运行文件进行加密处理?
2020-11-13 - 关于小程序文件下载并保存到本地的功能?
目前小程序要做保存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 - 微信小程序开放「分享到朋友圈」功能
2020年7月7日(据说是6日深夜),一个很特别的日子,微信低调地放开了一个功能:微信小程序“分享到到朋友圈”,这个看似微小的变化,对微信小程序来说意义重大。 用fenng大的话说就是: [图片] 目前此功能没有完全放开,需微信安卓7.0.16版本才支持,灰度测试 ,iOS版本暂不支持。 想让小程序提供“分享到朋友圈”的功能,小程序端需要通过调用wx.showShareMenu 这个api,支持此功能,具体的操作步骤如下: 1.设置“调试基础库”的版本wx.showShareMenu api支持分享朋友圈的功能参数“[代码]menus[代码]”需要基础库2.11版本以上,因此首先在微信小程序开发工具里设置基础库为2.11版本以上 [图片] 设置完成后,在点击小程序右上角的三个点,会出现“分享到朋友圈”的按钮,不过是灰色的,无法触发。 [图片] 2.调用wx.showShareMenu api在需要转发的页面的onLoad(onShow也可以)事件里加入如下代码: [代码]wx.showShareMenu({[代码] [代码]withShareTicket:true,[代码] [代码]menus:['shareAppMessage','shareTimeline'][代码] }) 加入后,点击小程序右上角的三个点“分享到朋友圈”按钮就可以使用了 [图片] 在开发工具里可以预览分享的效果 [图片] 小程序提交审核发布后,在朋友圈里的分享效果如下 [图片] 分享后的封面图是默认小程序的logo,标题是默认当前分享的小程序的页面导航标题。 点击打开小程序后,跳转到分享的小程序页面,点击不能直接使用小程序的跳转,需要点击下方的“前往小程序”才是真正进入小程序。 [图片] 这个功能目前还有完善,在开发工具里里查看小程序的分享页,如果小程序里有“updateManager.onUpdateReady”方法来更新小程序,会提示报错: [代码]Cannot read property 'onUpdateReady' of undefined[代码] 目前小程序分享到到朋友圈的方式是:小程序单页模式,并不会直接打开小程序,无法交互。“单页模式”下,页面顶部固定有导航栏,标题显示为分享时的标题,非常适合阅读类、内容类、资讯类小程序;顶部导航栏与底部操作栏均不支持自定义样式。以后开发需要考虑单页模式的布局,同时也要考虑专门为转发朋友圈来设计页面导航标题。 有关单页面模式的适配和限制详见微信官方文档: https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share-timeline.html 以上这些功能设计,就是微信防止此功能的滥用。 3.自定义分享的封面、标题和页面参数可以使用页面的分享朋友圈事件处理函数:onShareTimeline(), 编写方法参考微信开发文档:https://developers.weixin.qq.com/miniprogram/dev/reference/api/Page.html#onShareTimeline [图片] 微信小程序都推出3年了,但转发一直不能转发到朋友圈,总算开了这个口子,这对小程序来说是巨大的利好,相信后续会不断完善,既增加小程序的曝光率,也防止滥用,这点我对微信的产品设计有信心,此前一直都非常克制。 微慕小程序所有版本已经支持转发的到朋友圈,详情见:https://www.minapper.com/
2020-07-13 - 请问,小程序能否读取或打开PDF文档
请问,小程序能否读取或打开PDF文档
2017-01-14 - 小程序分享功能问题
想咨询一下,小程序想要增加分享解锁功能。 举例:A用户发布了信息,有联系方式。但是平台给隐藏了,B用户想要获取联系方式需要分享微信群或用户才能显示。 但是有个bug,B用户每次分享的时候,都是分享给同一个人或微信群。那分享裂变就没什么意义了。 有没有办法可以限定用户每次分享不同的人或微信群才可以解锁联系方式。 更有效的分享裂变? 希望有人可以解答,谢谢
2019-07-25 - 微信小程序之分享功能
今天分享一下在小程序开发中,关于分享功能的常见的3种实现方式: 1)入口 a.小程序右上角自带的分享功能: 如果在当前页面调用wx.hideShareMenu()方法,那么右上角的分享功能将被隐藏 调用wx.showShareMenu()方法,可以显示该功能。 下面是开发文档中的注意事项和示例代码: 注意事项: "shareAppMessage"表示“发送给朋友”按钮,"shareTimeline"表示“分享到朋友圈”按钮显示“分享到朋友圈”按钮时必须同时显示“发送给朋友”按钮,显示“发送给朋友”按钮时则允许不显示“分享到朋友圈”按钮示例代码: wx.showShareMenu({ withShareTicket: true, menus: ['shareAppMessage', 'shareTimeline'] }) b.自定义分享按钮,页面内发起转发: 通过给 button 组件设置属性 open-type="share",可以在用户点击按钮后触发 Page.onShareAppMessage 事件分享 c.生成带小程序码的海报 通过官方提供的接口可生成带参数的小程序码 https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=ACCESS_TOKEN 请求参数[图片] 以上3种方式均可实现分享功能 2)自定义转发分享内容: a. 转发给好友/群 通过onShareAppMessage方法设置官方文档对该方法的介绍: [图片] 示例代码: Page({ onShareAppMessage: function (res) { if (res.from === 'button') { // 来自页面内转发按钮 console.log(res.target) } return { title: '自定义转发标题', path: '/page/user?id=123' } } }) 如果开发人员在onShareAppMessage(options)不进行任何处理,那么微信将 会有一个默认的数据转发出去,title为当前小程序名称,path为当前页面的路径, imageUrl为当前页面的截图。 b. 转发到朋友圈 通过onShareTimeline()方法设置官方介绍文档: [图片] 对于分享到朋友圈,有些要注意的地方,比如现在只支持安卓系统 且分享到朋友圈的是单页模式,有以下限制: 页面无登录态,与登录相关的接口,如 [代码]wx.login[代码] 均不可用;云开发资源需开启未登录访问方可在单页模式下使用,详见未登录模式。不允许跳转到其它页面,包括任何跳小程序页面、跳其它小程序、跳微信原生页面不允许横屏使用若页面包含 tabBar,tabBar 不会渲染,包括自定义 tabBar本地存储与小程序普通模式不共用详情见官方参考文档 有更多关于实现微信小程序分享的骚操作欢迎留言分享交流
2020-12-17 - 关于小程序打开PDF?
请问微信小程序怎么将PDF内容渲染到小程序的页面上?
2020-11-06 - 微信公众平台用户信息相关接口调整公告
微信公众平台为开发者提供了用户授权登录功能及相关接口,以便开发者为用户提供便捷的使用体验。 根据相关法律法规,为进一步规范开发者调用用户信息相关接口或功能,保障用户合法权益,平台将对用户信息相关功能及接口进行调整,具体如下: 一、相关接口调整: 1、小程序与小游戏获取用户信息相关接口:不再返回用户性别及地区信息; 能力参考:小程序用户信息 、小游戏用户信息; 2、 公众号用户信息获取接口:不再返回用户性别及地区信息; 能力参考:公众号用户信息; 3、 Open平台授权接口:包括App授权登录、公众号H5授权登录、网站扫码授权登录,不再返回用户性别及地区信息; 能力参考:移动应用、网站应用、第三方平台; 本次改造调整生效后,所述涉及字段返回值将按如下规则生效: [图片] *注:字段名均保持不变,小程序与小游戏获取用户信息接口“用户性别”字段名为gender;Open 平台授权接口“用户性别”字段名为 sex 二、相关功能调整: 1、 公众号个性化菜单功能:不再提供基于性别/地区设置个性化菜单的能力; 能力参考:个性化菜单接口; 2、公众号后台粉丝列表:粉丝列表等不再展示用户的性别信息; 涉及功能页面:公众平台帐号管理后台-用户管理/留言管理/赞赏/视频弹幕/消息; 3、服务号粉丝列表筛选:不再提供基于地区筛选粉丝的能力; 涉及功能页面:公众平台帐号管理后台-对话能力-客户管理。 平台预计10月20日完成调整,请开发者及时进行调整适配,避免影响相关服务及用户体验。 微信团队 2021年09月26日
2023-09-26 - 微信小程序某个页面想实现禁止用户进行截屏操作,是否有办法?求解!!!
小程序中想实现某个页面禁止用户截屏(不是api中的监听截屏事件,是禁止截屏),请问一下有没有办法可以实现。谢谢
2018-05-08 - 小程序能防止手机截屏吗?
为了在一定程度上确保信息安全不被泄露,甚至我听说别人开发的APP还是什么,可以防止另外一个手机去拍照。
2019-08-28 - 小程序实现文件上传功能,怎么上传excel,word,ppt?
小程序实现文件上传功能,怎么上传excel,word,ppt
2019-09-17 - 小程序里如何手动文字换行(换行符是什么) (未解决)
2 比如活动介绍,是一段文字。第二段需要另起一行,但是\n无效, 也无效,难道要用块级标签来实现吗
2017-09-29 - 云函数获取openid
代码如下: app.js: //如果担心openid的安全,就用这个函数 getCloudOpenid: async function () { return this.openid = this.openid || (await wx.cloud.callFunction({name: 'login'})).result.OPENID }, //最佳方案。 getOpenid: async function () { (this.openid = this.openid || wx.getStorageSync('openid')) || wx.setStorageSync('openid', await this.getCloudOpenid()) return this.openid }, 任何page: onLoad: async function () { console.log(this.openid = await getApp().getOpenid()) }, //在本page的其他函数里获得openid。 yourFunc: function(){ console.log(this.openid) } 云函数login: const cloud = require('wx-server-sdk') cloud.init() exports.main=async()=>{return cloud.getWXContext()}
2020-10-18 - 002微信小程序示例源码学习之app
0 前言 这是我学习微信官方小程序源码的第一篇文章,看了下源码目录,必须要写app啊。 这里做个定义,我说的学习app指的是分别学习app.js、app.json、app.wxss文件,学习其他组件时,还会有.wxml文件。在文章的开始时,我会写学习本节过程中的一些通用知识,最后会写学习过程中的疑问,希望路过大神答疑解惑。 点开app.js一看,吓到了,好复杂啊!!!那也的啃…… [图片] 1 通识 关于.js文件中单引号和双引号问题:使用时单引号和双引号都不会报错,但在源码中.js文件中字符串都是用的单引号,决定保持一致。 在.json文件中,属性名用双引号,字符串值也用双引号。 console.log(参数1, 参数2),参数1是一个字符串,对参数2的一个说明。参数2是在console调试面板上的显示值。 let与const的区别:let声明的变量可以改变,值和类型都可以改变,没有限制。const声明的变量不得改变值,一旦声明变量,就必须立即初始化,不能留到以后赋值。 2 app.js [代码]const config = require('./config') //引入配置文件[代码],配置文件中包含云端服务器的一些配置参数。 暂时不知道[代码]global.isDemo = true[代码]是什么用途,估计其他页面使用。 [代码]wx.cloud.init({[代码] 小程序端,调用云开发API前的初始化,env为云开发环境ID,traceUser是否在将用户访问记录到用户管理中,在控制台中可见 [代码]const self = this[代码],this的问题比较复杂,对于我这初学难度比较大,理解着困难,上网查说this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象。在这个文件里,this就是指App()。 [代码]globalData: {[代码]中定义了是否登录的状态变量、及openid的值。 3 app.json 用来对微信小程序进行全局配置,决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等。 文件中各参数的设置在开发文档中有详细的说明 很多参数的值是颜色,需要填写十六进制颜色值,可以参考官方设计规范中给出的几个视觉规范,或者W3school查找需求。 [代码]"workers": "workers",[代码]使用 Worker 处理多线程任务 [代码]"style": "v2",[代码]v2表示新版的组件样式。 4 app.wxss app.wxss中的样式在具体使用页面详细研究。 5 sitemap.json 这是一个与app同级别的配置文件,配置小程序页面是否允许微信索引。如果没有 sitemap.json ,则默认为所有页面都允许被索引。目前,还不了解这一功能的作用,希望随着学习的深入能知道其作用。 6 疑惑 第1行require(’./config’)中,我知道…/是上一层,为什么用./congfig,./是什么意思,明明app.js与config.js在同一层? [代码]if (!wx.cloud)[代码],判断基础库是否有云函数功能,我在开发工具中把调试基础库改为2.2.3以下,并没有执行[代码]console.error('请使用 2.2.3 或以上的基础库以使用云能力')[代码]。但报了个错误:[代码]VM1513:1 page/weui/example/button/button has not been declared in app.json.[代码]算是个疑问。 [代码]getUserOpenId(callback) {和getUserOpenIdViaCloud() {[代码]暂未发现哪个页面调用这两个函数,此处暂时不分析。 写的第一个学习笔记文章,难度有点大,感觉学习的也不是很透彻,思考了很久如何能达到更好的效果,暂定这种模式吧。明天从基础view开始。 三万!胡了。
2019-12-17 - 小程序选择本地文件上传
小程序选择本地文件上传,如何选择相应的文件进行上传?????不是图片!!!
2018-08-20 - 微信小程序怎么获取一个上传文件的具体格式是doc还是PPT等
- 当前 Bug 的表现(可附上截图) 微信小程序怎么获取一个上传文件的具体格式是doc还是PPT
2019-04-18 - 小程序支持屏幕录制么? 不是录像是录屏
小程序支持屏幕录制么? 不是录像是录屏
2020-07-21 - 【征文大学篇】Attack!足球!
大家好,我们是来自华中赛区的 “NCHU_文体两开花”团队,意在文娱与体育,两面皆开花。 当2019年5月31日晚,距离微信小程序大赛作品提交截止时间仅剩最后10分钟时,我们几乎颤抖着手将最后一项更新的文件上传到微信小程序比赛入口,看到网页上提示“提交成功!”的字样,所有人心中的一块大石头终于都落了地。 “辛苦了,辛苦了!” “我要先睡个三天三夜!终于能先睡个好觉了。”前端小哥哥如是说。 然而这只是参加微信小程序大赛的第一阶段,未来我们还有很长的路要走。从确认选题到提交作品,这不长不短的两个月以来,我们一起拼搏,一起在实验室里不断完善作品。个中辛苦,有目共睹。 关于我们的作品“Attack足球”,就要追溯到选题时期了。 一、选题idea 我们团队大部分的成员都身在软件学院足球队,秉持着一颗热爱足球的心,积极参与日常训练和比赛,然而每当比赛前后,不只是我们学院的球队,纵观全校,都会经常出现一个问题:在教练使用战术板讲解战术时,我们一些站得远的队友经常听不清、看不着、不理解,尤其是每次教练指导完战术之后,便很难再复盘了。 为了今后战术指导更加顺利地进行,我们要改变这种现状!我们不仅是足球队的一员,还是软件学院的一名学生,具有得天独厚的优势。如果将足球战术板与软件结合到一起,会碰撞出怎样奇妙的火花呢? 我们想要将战术记录下来,在日后能够随时随地翻看已保存的战术指导,而微信小程序能够给一些优质服务提供平台,其即用即走的特性也是我们选择将战术板与微信小程序结合的重要原因之一,这便是我们开发Attack足球微信小程序的初衷。 为什么我们要叫“Attack足球”呢? 其实在这之前,我们有想过最普通直白的名字——“足球战术板”、“战术足球”等,也想过稍加修饰后的“战术风云”,但总感觉缺了些韵味,在一番思考后,我们定下了“Attack足球”这么一个中西结合的名字。 在足球赛场上,要想成功夺冠,离不开正确的战术,成功组织战术、巧妙运用战术是克敌制胜的关键。 “进攻是最好的防御,防御是为了更好的进攻”。 Attack取其“进击”之意,希望能借助这个名字,鼓励人们无论是在球场上还是生活中,都应该拼搏向前,锐意进取。 二、我们是如何做的? 需求分析对于一个项目来说是一个不容怠慢的关键点,一个好的需求分析代表着整个项目已经成功了一半。确认好Attack足球的基础功能后,如下图,便到了需要仔细考虑整个项目的功能需求的时候了。 [图片] 我们团队早期的会议并非是在讨论整个项目如何具体实施,而是提出自己对项目中还不理解的地方。例如: “在我们的Attack足球的球队管理功能中,被队长指派的教练可以像微信群一样把人踢出球队吗?” 有人提出疑问,就要进行解答。经过探讨,我们的答案是否定的,教练没有必要拥有对球队成员进行管理的权限,只有创建球队的队长才可以对成员进行管理工作。 由于要将整个项目细究,不放过任何一个点,因此需求分析确实花费了我们很多时间,但是这项工作绝不是在浪费时间。通过需求分析,我们所有人都对Attack足球有了十分具象的认识,团队中人人心中都有数,会让项目进展得更加顺利。 认真确定好需求,技术方案跟着便确定下来了: [图片] 我作为团队中的UI设计师,在刚开发Attack足球时,灵感乍现设计了一套方案,但是应用起来,如下图左图,效果并没有想象中好…… [图片] 没有得到预期的效果,对于UI设计师来说是一件很沮丧的事情。好在其余的团队成员帮助我及时调整心态,加上通过这些日子我对Attack足球有了更多了解,方案二也在我心中成型了。在与团队商量后,我们果断推翻方案一,及时止损,正式启用方案二,如上图右图。方案二与方案一比起来,不仅视觉效果好很多,考虑到的用户接口也会更加细致、更加贴近用户需求。 确定好界面风格,我需要将设计稿的各部分信息,例如间距、颜色等整理出来,接下来就由我们团队的前端小哥哥将设计稿付诸实践了。不过单独只有界面没有实际的功能可不行。要让Attack足球真正运作起来,前端小哥哥和后台小哥哥的配合必不可少。 在开发阶段,并非我就闲下来了,我还需要不断跟进项目,改进交互体验。我在尝试使用我们的作品Attack足球时,会将自己的身份定位为用户而不是开发者,这时又会发现很多用户体验不好的情况,例如:提示信息不够明确(此时用户的心理状态就是:嗯?我是谁?我接下来要做什么?)、界面观感太多繁杂(颜色爆炸!)等。我在设计球队管理功能界面时,就出现了这一类型的状况: [图片] 上图是我的球队管理界面设计稿,如左图,所有的教练、球员列表后都有按钮,红叉代表将成员踢出球队,黄色带有上下箭头的标志分别代表将教练降为球员和将球员设为教练。在没有教练、球员列表旁的提示信息时,仅看带有箭头的黄色标志不足以让用户明白这个按钮代表的是什么含义;而加上提示信息,整个界面颜色又过于杂乱、显得拥挤。 经过团队探讨后,我们确定了方案二,如右图:将队长对成员的操作按钮隐藏起来,当用户对球员信息从右向左滑时,显示按钮,才可以对其进行操作。 相比之下,方案二中左滑滚出选项的交互方式无弹窗、无等待,操作简便,也避免了整个画面过于杂乱而导致的糟糕的用户体验,这也证明了交互设计应该切实用用户之所用,想用户之所想,这样才能留住我们的用户大大! 在开发录制战术模块时,我们会毫不留情地对前端小哥哥吐槽:这些工具真的太难用了!中号铅笔太粗、橡皮擦不干净、删除界面中的球员的方式极其不友好等等,同时在我们强烈建(yao)议(qiu)下,他花了一下午的时间研究怎么将代表球员前进路径的铅笔笔划加上箭头标志,最终,他确实做到了!最终的效果如下图,完美完成我们的预期: [图片] 接下来的日子,我们一步一步将功能添加:录制战术、球队管理、战术文件管理、实时演练等。在最后的冲刺阶段,小程序的鲁棒性与用户体验是我们的重中之重,团队全员皆测试工程师,一边绞尽脑汁找BUG,一边废寝忘食改BUG,尽力将每一步都做好,每天我们的开发小哥哥们都要面临我们团队集体的灵魂拷问: “我的长昵称显示到第二行啦!怎么还没有改过来?” “有人加入了我的球队,我这边怎么还没有消息提示呢?” “这里……改改改!” 开发小哥哥们也都是先仰天长叹,不过紧接着就燃起熊熊斗志,埋头修改,最终完成的成品就是我们已上线的“Attack足球”。 不知不觉,开发Attack足球的这两个月就过去了,我也见证了在整个团队的共同努力下,Attack足球从无到有的整个过程。这过程中我们有笑有疲惫,但还好,我们相互扶持、相互鼓励,没有什么问题是齐心协力不能解决的。 虽然作品已经提交,但是我们了解Attack足球仍旧存在一些不足的地方,我们依然还在不断思考如何拓展更多功能、怎样提供更佳的用户体验。 提升专业性:添加更多与足球专业相关的词汇,使其更具专业性; 重视小细节:增加引导页,让用户第一次进入不迷茫; 完善不停歇:在Attack足球今后的版本中,可能还会出现其他不足之处,我们会不断对此进行相应的修改,Attack足球走在前进的道路上永不停歇。 三、感悟 足球作为一项体育活动,能给人带来快乐的同时,其团队协作、努力拼搏的足球精神也深深影响着每一个热爱足球人士的心。对于一个开发团队而言,不仅需要有优秀的成员冲锋陷阵,也需要卓越的领导运筹帷幄。我们的PM小哥哥带领着我们团队一步一步从设计到实践,在整个项目开发,他贯穿始终,是我们前进的导向标,是我们强而有力的领导者。 经过此次微信小程序大赛的洗礼,我们团队中的所有人不仅是编程技术上有了突破,更在心灵上经历了一次历练,这次为了同一个目标奋斗的过程也在我们的人生经历中添上了浓墨重彩的一笔。 在此,我总结了一些经验,希望可以帮到有需要的人: 对于UI设计师来说,灵感是一项很重要的东西,当灵感出现时,要及时记录,同时在实现灵感的过程中,并不需要面面俱到,因为在此期间,还可能会产生新的灵感,将灵感整理成点子,再将点子完善成作品,这个过程十分重要。 用户体验成为软件成败的关键点之一,需要在满足需求的同时不做太多繁琐的操作,化繁为简,切实照顾到用户的主观意向,用户才不易流失。 团队协作对于一个项目的开发而言尤为重要,团队的每一个人都是不可或缺的。在小团队中,每个人都清楚了解其他成员的工作任务,团队所有成员的步调一致会让项目开发更加高效。 作品是不断完善的,要想做到无论多么简单的需求,执行出来的产品都或多或少会有些缺陷。我们要做的,就是尽可能弥补这些缺陷。在实践过程中,不断积累经验,可以在今后编程时规避同种类型的缺陷。 四、愿景 在从开始到完成Attack足球的这两个月内,我们执行了完成一个项目的所有流程。微信小程序大赛是一个正式的比赛,是一个开放的平台,我们真诚地希望通过这次比赛,能让更多人了解Attack足球,同时也希望能在微信小程序大赛上我们“NCHU_文体两开花”团队能够取得一个满意的成绩。 足球所代表的是一种团队精神,而开发一个项目也需要团队成员组成的凝聚力,需要成员为团队的共同目标而齐心努力奋斗。虽然如今的Attack足球还是一款主要面向校园足球队的战术板工具,但在今后,Attack足球面向的可能不仅是校园足球队,还有可能走出校园,步入专业足球队,我们也会带着足球教会我们的团队与拼搏精神,为了这一天努力奋斗。
2019-06-25 - 小程序如何实现录屏功能?
开发小程序的过程中,由于业务需要,需要对用户屏幕进行录制,但是发现小程序好像并不支持屏幕录制功能,请问有什么解决方案么??
2021-04-15 - 小程序录屏?
小程序有api可以调用 用户进行录屏吗
2020-10-29 - 小程序可以禁止截屏录屏么?
小程序可以禁止截屏录屏么?
2021-07-26 - 防录屏
微信小程序怎么防止录屏?
2021-08-27 - 小程序如何限制用户录屏操作?
目前已完成的小程序对接腾讯云的实时音视频,因使用群体特殊,需要对视频过程限制用户录屏操作。请问如果进行控制,或者有没有替代方案来解决防止录屏操作?
2021-01-18 - 小程序如何防止用户录屏?
有关版权问题 如何防止用户手机的录屏事件
2021-01-13 - 小程序订阅消息,现在点击总是授权之后,还能再次唤起订阅的弹窗吗?
wx.requestSubscribeMessage 在弹起授权弹窗之后,用户点击了总是选择该选项,不再询问后。 之后不再会唤起授权弹窗,能否设置重新唤起授权弹窗呢?
2019-10-17 - 微信小程序wx.showModal如何修改样式?
[图片]
2020-04-07 - wx.navigateBack(Object object)返回上一页 ,怎么会一直跳到首页?
wx.navigateTo(Object object) 保留当前页面,跳转到应用内的某个页面。再返回,不知道什么原因一直都跳到首页。 [图片] [图片]
2021-08-24 - 联通4G下请求网络接口速度超慢(15秒-30秒)
1,WIFI条件下,请求接口数据很快,4G条件下,请求接口数据很慢(15-30秒),可以排除4G网络慢的原因 2,4G条件下,请求同样的接口数据——访问APP端的时候,请求数据很快,访问小程序端的接口,请求数据很慢 请问这是什么原因?
2018-10-17 - wx.request 接口调用很慢,是什么问题?
您好,请问一下,最近用户用4G等网络调用接口时一直很卡顿,我们这边用安卓试了一下,也发现了同样的问题,我们写了日志,看反馈卡顿的用户的日志,请求发出到进入success回调用的时间如下图所示,我不知这是什么原因导致的,是偶发性的,玩了一下拼多多的小程序,也同样偶尔有这个问题存在,我们也检查了服务器,我们nginx日志没有相关超时日志,还有我们服务端超过10s就会返回超时500的。麻烦相关人员查看一下wx.request接口是不是有问题。 [图片] [图片]
2019-10-24 - 小程序上请求接口特别慢,网页上请求是毫秒级的?
为何在小程序上请求接口是秒级的?而在网页上请求是毫秒级的 [图片]
2020-08-07 - 为什么小程序调用接口很慢??
request接口调用接口和前几次非常慢,有时候甚至能达到七八秒! 但是我直接用浏览器访问基本上算秒开。 请求这是什么意思??
2018-09-10 - 小程序接口响应慢,问题排查
- 需求的场景描述(希望解决的问题) 现在遇到一个问题,微信小程序请求延迟7s返回:拿到微信客户端的日志,前端在0s的时候发出,后端在7s的时候拿到并在7s的时候返回,现在已经排除我们的小程序业务逻辑问题和服务端处理响应问题;业务方如何更细化分析7s的耗时在哪里?(偶现的问题) - 希望提供的能力 wx.request 的请求api是否可以提供dns解析时间、tcp握手耗时、ssl解析时间、从请求发起到服务端响应总耗时。
2019-06-10 - 小程序弹窗如何让它每日只弹一次
现在的弹窗是每次打开都弹窗 如何设计成每天弹出一次 类似弹窗签到那种
2019-01-16 - 微信小程序支持双向绑定
贴个官方大大的链接 https://developers.weixin.qq.com/miniprogram/dev/framework/view/two-way-bindings.html 刚试了一下 真舒爽 基本库版本需要2.9.3以上 [图片]
2020-11-10 - 小程序新 Canvas 接口公测
各位开发者: 为了提高 Canvas 组件的性能,我们计划在小程序基础库 v2.9.0 正式开放一套全新的 Canvas 接口。该接口符合 HTML Canvas 2D 的标准,实现上采用 GPU 硬件加速,渲染性能相比于现有的 Canvas 接口有一倍左右的提升。现邀请广大开发者参与 Canvas 接口的公测。 公测需使用 iOS v7.0.5 版本,接口用法可参考该代码片段。 欢迎广大开发者参与公测,如有问题,请在本帖下方评论反馈。 微信团队 2019.08.29
2019-08-29 - 微信小程序canvas 波浪背景组件 wave-bg-weapp
微信小程序canvas 波浪背景组件 wave-bg-weapp 前言 最近的项目中坑爹的设计师设计了一个波浪的背景效果, 本着高度还原设计稿的原则打算用canvas实现一下, 一番百度之后并没有找到满意的效果, 所以自己撸了一个感觉还不错共享给大家. 效果 [图片] 演示片段 https://developers.weixin.qq.com/s/g9tWlAmG7st8 依赖 组件依赖simplex-noise Simplex噪声算法 npm 安装 安装之后开发者工具点击npm构建 [代码]npm i wave-bg-weapp --production [代码] 引入 在app.json或index.json中引入组件 [代码]"usingComponents": { "bg": "/miniprogram_npm/wave-bg-weapp/bg/index" } [代码] 页面结构 [代码]<bg class="bg" color="#d13435" percent="90" position="top" amp="20"></bg> [代码] 参数 参数 说明 类型 默认值 版本 color 波浪填充颜色 String [代码]#d13435[代码] 1.0.2 percent 高度百分比 如:90(即波浪高度为canvas高度的90%) Number 50 1.0.2 position 波浪填充位置 可设置 [代码]top[代码]: 在上部填充颜色, [代码]bottom[代码]: 在下部填充颜色 String top 1.0.2 amp 波浪振幅 Number 20 2.0.2 插槽 不知道为何canvas写完之后发现层级很高,但是看官方文档支持同层渲染阿 没研究明白,弄了个插槽可以将一些元素覆盖上去,本质上是写了cover-view,所以插槽里只能用cover-view下支持的组件,而且开发者工具看不到覆盖的东西,真机测试有效果 [代码]<bg class="bg" style="height: 50vh;" color="#d13435" percent="90" position="top" amp="20"> <cover-view>插槽内容</cover-view> </bg> [代码] 仓库 https://github.com/wzs28150/wave-bg-weapp
2021-09-25 - 如何实现快速生成朋友圈海报分享图
由于我们无法将小程序直接分享到朋友圈,但分享到朋友圈的需求又很多,业界目前的做法是利用小程序的 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 - 小程序绘制canvas可以像html2canvas一样截取整块区域的图?
小程序绘制canvas可以像html2canvas一样截取整块区域的图了吗?以前是不可以的,需要手动画图。调位置。html2canvas可以直接截取整块区域的图或者文案直接放置到canvas里。 现在支持吗??????
2018-06-13 - 微信小程序开发之富文本编辑器
微信小程序开发之富文本编辑器 一年多去了,还有这么多人关注这个编辑器,那就索性把这个组件放上去,各位直接引用吧!如果您感觉很好用,很实用,也请大家给点一个赞!前言:富文本在Web开发上的地位大家可想而知,很多地方都需要用到富文本编辑器,比如开发类似新闻管理小程序、商品简介等。微信小程序在基础库2.7.0之后上线了一个editor富文本编辑器组件,这个组件是本次要讲的内容。组件相关的内容大家可以去看官方文档的内容,这里我们就不进行讲解。而我们要做的就是将官方的富文本组件进行二次开发达到一个好用而又实用的地步:https://developers.weixin.qq.com/miniprogram/dev/component/editor.html 先看效果图(以下只是一个基础的实用): [图片] 代码方案: 1.引入组件(组件的下载地址链接:https://pan.baidu.com/s/15D3ejvs30BZPwn94RgyNmw 提取码:hg66) 2、在你需要的使用的页面的JSON文件中引入该组件,引入方法如下: "usingComponents": { "hg-editor":"../../../components/hg-editor/hg-editor(根据自己的放置位置修改,其中/hg-editor/hg-editor是固定的)" } 3、在wxml文件中使用,使用案例如下,可选参数有四个 参数详解: [图片] showTabBar :是否显示工具栏(默认为true,显示,如果改为false则为不显示)placeholder:文本框提示文字,默认为“请输入相关内容”name:是编辑器的name属性,默认为空uploadImageURL:图片的上传地址,默认为空使用属性案例测试: bind:input可以获得用户输入的内容: onInputtingDesc: function (e) { let html = e.detail.html; //相关的html代码 let originText = e.detail.text; //text,不含有任何的html标签 this.setData({ ['topic.text']: html, ['topic.originText']: originText }); } 使用案例: [图片][图片][图片] 您的想法有多大,组件拓展的无限可能就有多大,欢迎各位留言,欢迎各位使用! 好用,就来收藏一下,更新不易,点个赞!
2022-04-22 - 自定义tabbar 【恋爱小清单开发总结】
看官方demo的小伙伴知道,自定义tabbar需要在小程序根目录底下建一个名叫custom-tab-bar的组件(我有试过,如果放在components目录里面小程序会识别不了),目前我自己实现的效果是:通过在配置可以切换tab,也可以点击tab后重定向到新页面,支持隐藏tabbar,同时也可以显示右上角文本和小红点。 官方demo里面用的是cover-view,我改成view,因为如果页面有弹窗的话我希望可以盖住tabbar 总结一下有以下注意点: 1、tabbar组件的目录命名需要是custom-tab-bar 2、app.json增加自定义tabbar配置 3、wx.navigateTo不允许跳转到tabb页面 4、进入tab页面时,需要调用tabbar.js手动切换tab 效果图: [图片] 可以扫码体验 [图片] 代码目录如下: [图片] 代码如下: app.json增加自定义tabbar配置 "tabBar": { "custom": true, "color": "#7A7E83", "selectedColor": "#3cc51f", "borderStyle": "black", "backgroundColor": "#ffffff", "list": [ { "pagePath": "pages/love/love", "text": "首页" }, { "pagePath": "pages/tabbar/empty", "text": "礼物说" }, { "pagePath": "pages/tabbar/empty", "text": "恋人圈" }, { "pagePath": "pages/me/me", "text": "我" } ] }, 自定义tabbar组件代码如下 index.js //api.js是我自己对微信接口的一些封装 const api = require('../utils/api.js'); //获取应用实例 const app = getApp(); Component({ data: { isPhoneX: false, selected: 0, hide: false, list: [{ showRedDot: false, showBadge: false, badgeText: "", pagePath: "/pages/love/love", iconPath: "/images/tabbar/home.png", selectedIconPath: "/images/tabbar/home-select.png", text: "首页" }, { showRedDot: false, showBadge: false, badgeText: "", pagePath: "/pages/tabbar/empty", navigatePath: "/pages/gifts/giftList", iconPath: "/images/tabbar/gift.png", selectedIconPath: "/images/tabbar/gift-select.png", text: "礼物说", hideTabBar: true }, { showRedDot: false, showBadge: false, badgeText: "", pagePath: "/pages/tabbar/empty", navigatePath: "/pages/moments/moments", iconPath: "/images/tabbar/lover-circle.png", selectedIconPath: "/images/tabbar/lover-circle-select.png", text: "恋人圈", hideTabBar: true }, { showRedDot: false, showBadge: false, badgeText: "", pagePath: "/pages/me/me", iconPath: "/images/tabbar/me.png", selectedIconPath: "/images/tabbar/me-select.png", text: "我" }] }, ready() { // console.error("custom-tab-bar ready"); this.setData({ isPhoneX: app.globalData.device.isPhoneX }) }, methods: { switchTab(e) { const data = e.currentTarget.dataset; console.log("tabBar参数:", data); api.vibrateShort(); if (data.hideTabBar) { api.navigateTo(data.navigatePath); } else { /*this.setData({ selected: data.index }, function () { wx.switchTab({url: data.path}); });*/ /** * 改为直接跳转页面, * 因为发现如果先设置selected的话, * 对应tab图标会先选中,然后页面再跳转, * 会出现图标变成未选中然后马上选中的过程 */ wx.switchTab({url: data.path}); } }, /** * 显示tabbar * @param e */ showTab(e){ this.setData({ hide: false }, function () { console.log("showTab执行完毕"); }); }, /** * 隐藏tabbar * @param e */ hideTab(e){ this.setData({ hide: true }, function () { console.log("hideTab执行完毕"); }); }, /** * 显示小红点 * @param index */ showRedDot(index, success, fail) { try { const list = this.data.list; list[index].showRedDot = true; this.setData({ list }, function () { typeof success == 'function' && success(); }) } catch (e) { typeof fail == 'function' && fail(); } }, /** * 隐藏小红点 * @param index */ hideRedDot(index, success, fail) { try { const list = this.data.list; list[index].showRedDot = false; this.setData({ list }, function () { typeof success == 'function' && success(); }) } catch (e) { typeof fail == 'function' && fail(); } }, /** * 显示tab右上角文本 * @param index * @param text */ showBadge(index, text, success, fail) { try { const list = this.data.list; Object.assign(list[index], {showBadge: true, badgeText: text}); this.setData({ list }, function () { typeof success == 'function' && success(); }) } catch (e) { typeof fail == 'function' && fail(); } }, /** * 隐藏tab右上角文本 * @param index */ hideBadge(index, success, fail) { try { const list = this.data.list; Object.assign(list[index], {showBadge: false, badgeText: ""}); this.setData({ list }, function () { typeof success == 'function' && success(); }) } catch (e) { typeof fail == 'function' && fail(); } } } }); index.html <view class="footer-tool-bar flex-center {{isPhoneX? 'phx_68':''}}" hidden="{{hide}}"> <view class="tab flex-full {{selected === index ? 'focus':''}}" wx:for="{{list}}" wx:key="index" data-path="{{item.pagePath}}" data-index="{{index}}" data-navigate-path="{{item.navigatePath}}" data-hide-tab-bar="{{item.hideTabBar}}" data-open-ext-mini-program="{{item.openExtMiniProgram}}" data-ext-mini-program-app-id="{{item.extMiniProgramAppId}}" bindtap="switchTab"> <view class="text"> <view class="dot" wx:if="{{item.showRedDot}}"></view> <view class="badge" wx:if="{{item.showBadge}}">{{item.badgeText}}</view> <image class="icon" src="{{item.selectedIconPath}}" hidden="{{selected !== index}}"></image> <image class="icon" src="{{item.iconPath}}" hidden="{{selected === index}}"></image> </view> </view> </view> index.json { "component": true, "usingComponents": {} } index.wxss @import "/app.wxss"; .footer-tool-bar{ background-color: #fff; height: 100rpx; width: 100%; position: fixed; bottom: 0; z-index: 100; text-align: center; font-size: 24rpx; transition: transform .3s; border-radius: 30rpx 30rpx 0 0; /*padding-bottom: env(safe-area-inset-bottom);*/ box-shadow:0rpx 0rpx 18rpx 8rpx rgba(212, 210, 211, 0.35); } .footer-tool-bar .tab{ color: #242424; height: 100%; line-height: 100rpx; } .footer-tool-bar .focus{ color: #f96e49; font-weight: 500; } .footer-tool-bar .icon{ width: 44rpx; height: 44rpx; margin: 18rpx auto; } .footer-tool-bar .text{ line-height: 80rpx; height: 80rpx; position: relative; display: inline-block; padding: 0rpx 40rpx; box-sizing: border-box; margin: 10rpx auto; } .footer-tool-bar .dot{ position: absolute; top: 16rpx; right: 16rpx; height: 16rpx; width: 16rpx; border-radius: 50%; background-color: #f45551; } .footer-tool-bar .badge{ position: absolute; top: 8rpx; right: 8rpx; height: 30rpx; width: 30rpx; line-height: 30rpx; border-radius: 50%; background-color: #f45551; color: #fff; text-align: center; font-size: 20rpx; font-weight: 450; } .hide{ transform: translateY(100%); } app.wxss(这里的样式文件是我用来存放一些公共样式) /**app.wxss**/ page { background-color: #f5f5f5; height: 100%; -webkit-overflow-scrolling: touch; } .container { height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: space-between; box-sizing: border-box; } .blur { filter: blur(80rpx); opacity: 0.65; } .flex-center { display: flex; align-items: center; justify-content: center; } .flex-column { display: flex; /*垂直居中*/ align-items: center; /*水平居中*/ justify-content: center; flex-direction: column; } .flex-start-horizontal{ display: flex; justify-content: flex-start; } .flex-end-horizontal{ display: flex; justify-content: flex-end; } .flex-start-vertical{ display: flex; align-items: flex-start; } .flex-end-vertical{ display: flex; align-items: flex-end; } .flex-wrap { display: flex; flex-wrap: wrap; } .flex-full { flex: 1; } .reset-btn:after { border: none; } .reset-btn { background-color: #ffffff; border-radius: 0; margin: 0; padding: 0; overflow: auto; } .loading{ opacity: 0; transition: opacity 1s; } .load-over{ opacity: 1; } .phx_68{ padding-bottom: 68rpx; } .phx_34{ padding-bottom: 34rpx; } 另外我还对tabbar的操作做了简单的封装: tabbar.js const api = require('/api.js'); /** * 切换tab * @param me * @param index */ const switchTab = function (me, index) { if (typeof me.getTabBar === 'function' && me.getTabBar()) { console.log("切换tab:", index); me.getTabBar().setData({ selected: index }) } }; /** * 显示 tabBar 某一项的右上角的红点 * @param me * @param index */ const showRedDot = function (me, index, success, fail) { if (typeof me.getTabBar === 'function' && me.getTabBar()) { me.getTabBar().showRedDot(index, success, fail); } }; /** * 隐藏 tabBar 某一项的右上角的红点 * @param me * @param index */ const hideRedDot = function (me, index, success, fail) { if (typeof me.getTabBar === 'function' && me.getTabBar()) { me.getTabBar().hideRedDot(index, success, fail); } }; /** * 显示tab右上角文本 * @param me * @param index * @param text */ const showBadge = function (me, index, text, success, fail) { if (typeof me.getTabBar === 'function' && me.getTabBar()) { me.getTabBar().showBadge(index, text, success, fail); } }; /** * 隐藏tab右上角文本 * @param me * @param index */ const hideBadge = function (me, index, success, fail) { if (typeof me.getTabBar === 'function' && me.getTabBar()) { me.getTabBar().hideBadge(index, success, fail); } }; /** * 显示tabbar * @param me * @param success */ const showTab = function(me, success){ if (typeof me.getTabBar === 'function' && me.getTabBar()) { me.getTabBar().showTab(success); } }; /** * 隐藏tabbar * @param me * @param success */ const hideTab = function(me, success){ if (typeof me.getTabBar === 'function' && me.getTabBar()) { me.getTabBar().hideTab(success); } }; module.exports = { switchTab, showRedDot, hideRedDot, showBadge, hideBadge, showTab, hideTab }; 最后,进入到tab对应页面的时候要手动调用一下swichTab接口,然tabbar聚焦到当前tab /** * 生命周期函数--监听页面显示 */ onShow: function () { tabbar.switchTab(this, this.data.tabIndex);//tabIndex是当前tab的索引 }
2021-11-09 - 微信小程序拨号功能,调起手机拨号!
微信官方文档·:https://developers.weixin.qq.com/miniprogram/dev/api/device/phone/wx.makePhoneCall.html 方法也很简单,直接调用wx.makePhoneCall({}),如下图,phoneNumber就是电话号码,触发call方法后,会直接跳转到拨号页面,如下图: call() { // 打电话 let phone = "13123123123" // 仅为示例,并非真实的电话号码 wx.makePhoneCall({ phoneNumber: phone }) } [图片]
2021-06-29 - 小程序拿到用户上传的图片后怎么传到后台服务器?
拿到用户上传图片的路径,怎么将图片作为文件发送到后端服务器
2019-09-19 - 5行代码实现微信小程序模版消息推送 (含推送后台和小程序源码)
由于小程序2020年1月10日以后改模板消息为订阅消息,所以我写了一篇新的文章来更新这个知识点 《小程序订阅消息推送(含源码)java实现小程序推送,springboot实现微信消息推送》 我们在做小程序开发时,消息推送是不可避免的。今天就来教大家如何实现小程序消息推送的后台和前台开发。源码会在文章末尾贴出来。 其实我之前有写过一篇:《springboot实现微信消息推送,java实现小程序推送,含小程序端实现代码》 但是有同学反应这篇文章里的代码太繁琐,接入也比较麻烦。今天就来给大家写个精简版的,基本上只需要几行代码,就能实现小程序模版消息推送功能。 老规矩先看效果图 [图片] 这是我们最终推送给用户的模版消息。这是用户手机微信上显示的推送消息截图。 本节知识点 1,java开发推送后台 2,springboot实现推送功能 3,小程序获取用户openid 4,小程序获取fromid用来推送 先来看后台推送功能的实现 只有下面一个简单的PushController类,就可以实现小程序消息的推送 [图片] 再来看下PushController类,你没看错,实现小程序消息推送,就需要下面这几行代码就可以实现了。 [图片] 由于本推送代码是用springboot来实现的,下面就来简单的讲下。我我们需要注意的几点内容。 1,需要在pom.xml引入一个三方类库(推送的三方类库) [图片] pom.xml的完整代码如下 [代码]<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.qcl</groupId> <artifactId>wxapppush</artifactId> <version>0.0.1-SNAPSHOT</version> <name>wxapppush</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--微信小程序模版推送--> <dependency> <groupId>com.github.binarywang</groupId> <artifactId>weixin-java-miniapp</artifactId> <version>3.4.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> [代码] 其实到这里我们java后台的推送功能,就已经实现了。我们只需要运行springboot项目,就可以实现推送了。 下面贴出完整的PushController.java类。里面注释很详细了。 [代码]package com.qcl.wxapppush; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; import java.util.List; import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; import cn.binarywang.wx.miniapp.bean.WxMaTemplateData; import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; import cn.binarywang.wx.miniapp.config.WxMaInMemoryConfig; import me.chanjar.weixin.common.error.WxErrorException; /** * Created by qcl on 2019-05-20 * 微信:2501902696 * desc: 微信小程序模版推送实现 */ @RestController public class PushController { @GetMapping("/push") public String push(@RequestParam String openid, @RequestParam String formid) { //1,配置小程序信息 WxMaInMemoryConfig wxConfig = new WxMaInMemoryConfig(); wxConfig.setAppid("XXX");//小程序appid wxConfig.setSecret("xxx");//小程序AppSecret WxMaService wxMaService = new WxMaServiceImpl(); wxMaService.setWxMaConfig(wxConfig); //2,设置模版信息(keyword1:类型,keyword2:内容) List<WxMaTemplateData> templateDataList = new ArrayList<>(2); WxMaTemplateData data1 = new WxMaTemplateData("keyword1", "获取老师微信"); WxMaTemplateData data2 = new WxMaTemplateData("keyword2", "2501902696"); templateDataList.add(data1); templateDataList.add(data2); //3,设置推送消息 WxMaTemplateMessage templateMessage = WxMaTemplateMessage.builder() .toUser(openid)//要推送的用户openid .formId(formid)//收集到的formid .templateId("eDZCu__qIz64Xx19dAoKg0Taf5AAoDmhUHprF6CAd4A")//推送的模版id(在小程序后台设置) .data(templateDataList)//模版信息 .page("pages/index/index")//要跳转到小程序那个页面 .build(); //4,发起推送 try { wxMaService.getMsgService().sendTemplateMsg(templateMessage); } catch (WxErrorException e) { System.out.println("推送失败:" + e.getMessage()); return e.getMessage(); } return "推送成功"; } } [代码] 看代码我们可以知道,我们需要做一些配置,需要下面信息 1,小程序appid 2,小程序AppSecret(密匙) 3,小程序推送模版id 4,用户的openid 5,用户的formid(一个formid只能用一次) 下面就是小程序部分,来教大家如何获取上面所需的5个信息。 1,appid和AppSecret的获取(登录小程序管理后台) [图片] 2,推送模版id [图片] 3,用户openid的获取,可以看下面的这篇文章,也可以看源码,这里不做具体讲解 小程序开发如何获取用户openid 4,获取formid [图片] 看官方文档,可以知道我们的formid有效期是7天,并且一个form_id只能使用一次,所以我们小程序端所需要做的就是尽可能的多拿些formid,然后传个后台,让后台存到数据库中,这样7天有效期内,想怎么用就怎么用了。 所以接下来要讲的就是小程序开发怎么尽可能多的拿到formid了 [图片] 看下官方提供的,只有在表单提交时把report-submit设为true时才能拿到formid,比如这样 [代码] <form report-submit='true' > <button form-type='submit'>获取formid</button> </form> [代码] 所以我们就要在这里下功夫了,既然只能在form组件获取,我们能不能把我们小程序里用到最多的地方用form来伪装呢。 下面简单写个获取formid和openid的完整示例,方便大家学习 效果图 [图片] 我们要做的就是点击获取formid按钮,可以获取到用户的formid和openid,正常我们开发时,是需要把openid和formid传给后台的,这里简单起见,我们直接用获取到的formid和openid实现推送功能 下面来看小程序端的实现代码 1,index.wxml [图片] 2,index.js [图片] 到这里我们小程序端的代码也实现了,接下来测试下推送。 [代码]formid: 6ee9ce80c1ed4a2f887fccddf87686eb openid o3DoL0Uusu1URBJK0NJ4jD1LrRe0 [代码] [图片] 可以看到我们用了上面获取到的openid和formid做了一次推送,显示推送成功 [图片] [图片] 到这里我们小程序消息推送的后台和小程序端都讲完了。 这里有两点需要大家注意 1,推送的openid和formid必须对应。 2,一个formid只能用一次,多次使用会报一下错误。 [代码]{"errcode":41029,"errmsg":"form id used count reach limit hint: [ssun8a09984113]"} [代码] 编程小石头,码农一枚,非著名全栈开发人员。分享自己的一些经验,学习心得,希望后来人少走弯路,少填坑。 这里就不单独贴出源码下载链接了,大家感兴趣的话,可以私信我,或者在底部留言,我会把源码下载链接贴在留言区。 单独找我要源码也行(微信2501902696) 视频讲解:https://edu.csdn.net/course/detail/23750 源码链接:https://github.com/qiushi123/wxapppush
2020-01-08 - 小程序之主动推送消息(订阅消息)
微信的东西,第一次玩,记录下全过程,略过申请小程序步骤 1:配置类目,建议在申请小程序的时候多选几个类目,类目越多,可选的消息模版越多,修改地址(传送门 路径: 设置-基本设置-服务类目) 2:设置推送消息模版 地址:传送门 选择公共模版,这一步与上一步选择的类目相关。 3:配置服务器域名+消息推送 地址:传送门 1):服务器域名配置: 路径:开发-开发设置-服务器域名,前四个都填写(注意需要80或443端口),如下图 [图片] 2):代码编写:此步骤是为了给微信服务器提供验证用,就是说我们要写一个接口(GET方式),给微信调用,具体参数如下 文档地址:传送门 参数 描述 signature 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。 timestamp 时间戳 nonce 随机数 echostr 随机字符串 以下是我的code,可以直接使用(netcore版本) /// <summary> /// 接口认证 /// </summary> /// <param name="echostr"></param> /// <param name="signature"></param> /// <param name="timestamp"></param> /// <param name="nonce"></param> /// <returns></returns> [HttpGet] [Route("GetWechatSubscription")] [SkipResponseDataFilter] public string WechatSubscription(string echostr, string signature, string timestamp, string nonce) { string token = "jdcommonpushmessage123";//此处token需要保存下,第三步会用到 if (!CheckSignature(token, signature, timestamp, nonce)) { //echostr = "验证不正确"; throw new UserFriendlyException("token验证不正确"); } return echostr; } /// <summary> /// 验证微信签名 /// </summary> private bool CheckSignature(string token, string signature, string timestamp, string nonce) { string[] ArrTmp = { token, timestamp, nonce }; Array.Sort(ArrTmp); string tmpStr = string.Join("", ArrTmp); var data = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(tmpStr)); var sb = new StringBuilder(); foreach (var t in data) { sb.Append(t.ToString("X2")); } tmpStr = sb.ToString(); tmpStr = tmpStr.ToLower(); if (tmpStr == signature) { return true; } else { return false; } } 接口写好了,那怎么调用呢?请看第三条 3)我们在第一步的时候填写了服务器域名,那么 (1)把第二步的接口发布到上述的服务器 (2)回到配置服务器域名的页面(点击此处进入传送门),往下拉找到 消息推送 进入页面,如下图 [图片] 参数说明:url--就是第二步发布的接口地址 token--随便输入一个32位的字符串(注意,第二步代码中有 string token = "jdcommonpushmessage123";,这个jd....需要和这个token保持一致) EncodingAESKey:直接点击右侧随机生成即可,编写代码的时候没用到。 信息加密方式:选择安全模式。 数据格式:json。 然后点击提交,注意:如果能够提交成功,说明第二步写的接口没问题,失败则是接口有问题,可以查看下参数名称、大小写、返回的参数大小写、格式是否与微信要求的一致。 以上便是服务端相关接口,当然只是做了这些是不可能调起下图内容的 [图片] 还需要前端调微信下发权限接口,点击进入(传送门) 以上便是小程序信息推送,供大家一起交流。
2020-03-14 - 小程序登录、用户信息相关接口调整说明
公告更新时间:2021年04月15日考虑到近期开发者对小程序登录、用户信息相关接口调整的相关反馈,为优化开发者调整接口的体验,回收wx.getUserInfo接口可获取用户授权的个人信息能力的截止时间由2021年4月13日调整至2021年4月28日24时。为优化用户的使用体验,平台将进行以下调整: 2021年2月23日起,若小程序已在微信开放平台进行绑定,则通过wx.login接口获取的登录凭证可直接换取unionID2021年4月28日24时后发布的小程序新版本,无法通过wx.getUserInfo与<button open-type="getUserInfo"/>获取用户个人信息(头像、昵称、性别与地区),将直接获取匿名数据(包括userInfo与encryptedData中的用户个人信息),获取加密后的openID与unionID数据的能力不做调整。此前发布的小程序版本不受影响,但如果要进行版本更新则需要进行适配。新增getUserProfile接口(基础库2.10.4版本开始支持),可获取用户头像、昵称、性别及地区信息,开发者每次通过该接口获取用户个人信息均需用户确认。具体接口文档:《getUserProfile接口文档》由于getUserProfile接口从2.10.4版本基础库开始支持(覆盖微信7.0.9以上版本),考虑到开发者在低版本中有获取用户头像昵称的诉求,对于未支持getUserProfile的情况下,开发者可继续使用getUserInfo能力。开发者可参考getUserProfile接口文档中的示例代码进行适配。请使用了wx.getUserInfo接口或<button open-type="getUserInfo"/>的开发者尽快适配。开发者工具1.05.2103022版本开始支持getUserProfile接口调试,开发者可下载该版本进行改造。 小游戏不受本次调整影响。 一、调整背景很多开发者在打开小程序时就通过组件方式唤起getUserInfo弹窗,如果用户点击拒绝,无法使用小程序,这种做法打断了用户正常使用小程序的流程,同时也不利于小程序获取新用户。 二、调整说明通过wx.login接口获取的登录凭证可直接换取unionID 若小程序已在微信开放平台进行绑定,原wx.login接口获取的登录凭证若需换取unionID需满足以下条件: 如果开发者帐号下存在同主体的公众号,并且该用户已经关注了该公众号如果开发者帐号下存在同主体的公众号或移动应用,并且该用户已经授权登录过该公众号或移动应用2月23日后,开发者调用wx.login获取的登录凭证可以直接换取unionID,无需满足以上条件。 回收wx.getUserInfo接口可获取用户个人信息能力 4月28日24时后发布的新版本小程序,开发者调用wx.getUserInfo或<button open-type="getUserInfo"/>将不再弹出弹窗,直接返回匿名的用户个人信息,获取加密后的openID、unionID数据的能力不做调整。 具体变化如下表: [图片] 即wx.getUserInfo接口的返回参数不变,但开发者获取的userInfo为匿名信息。 [图片] 此外,针对scope.userInfo将做如下调整: 若开发者调用wx.authorize接口请求scope.userInfo授权,用户侧不会触发授权弹框,直接返回授权成功若开发者调用wx.getSetting接口请求用户的授权状态,会直接读取到scope.userInfo为true新增getUserProfile接口 若开发者需要获取用户的个人信息(头像、昵称、性别与地区),可以通过wx.getUserProfile接口进行获取,该接口从基础库2.10.4版本开始支持,该接口只返回用户个人信息,不包含用户身份标识符。该接口中desc属性(声明获取用户个人信息后的用途)后续会展示在弹窗中,请开发者谨慎填写。开发者每次通过该接口获取用户个人信息均需用户确认,请开发者妥善保管用户快速填写的头像昵称,避免重复弹窗。 插件用户信息功能页 插件申请获取用户头像昵称与用户身份标识符仍保留功能页的形式,不作调整。用户在用户信息功能页中授权之后,插件就可以直接调用 wx.login 和 wx.getUserInfo 。 三、最佳实践调整后,开发者如需获取用户身份标识符只需要调用wx.login接口即可。 开发者若需要在界面中展示用户的头像昵称信息,可以通过<open-data>组件进行渲染,该组件无需用户确认,可以在界面中直接展示。 在部分场景(如社交类小程序)中,开发者需要在获取用户的头像昵称信息,可调用wx.getUserProfile接口,开发者每次通过该接口均需用户确认,请开发者妥善处理调用接口的时机,避免过度弹出弹窗骚扰用户。 微信团队 2021年4月15日
2021-04-15 - 借助云开发实现小程序的登陆注册功能
我们在开发小程序时,难免会用到登陆注册功能。通常小程序有为我们提供用户授权登陆的功能,但是这个只能获取用户的头像和昵称,我们该怎么样来实现小程序账号密码的注册和登陆呢,今天就来手把手的带大家学习小程序登陆注册功能的开发。 老规矩,先看效果图 [图片] 通过上图可以看到我们主要实现了以下功能 1,账号密码登陆 2,账号密码注册 3,退出登陆 下面我们就来看下具体实现 一,原理讲解 因为我们账号密码的注册,就是把用户设置的账号密码存到数据库里,登陆也是从数据库里取账号和密码来校验。所以我们必须要有数据库。如果用传统的数据库来做,比较麻烦,所以我们今天就借助小程序云开发数据库来做。 二,编写一个云开发的小程序 云开发的知识我讲过很多遍了,还不知道云开发是啥的同学可以翻看下我历史文章,或者看下我录制的云开发基础入门视频:《5小时零基础入门小程序云开发》 编写云开发的时候有几点注意的事项给大家说下 1,要先注册小程序获取appid,因为只有appid你才可以使用云开发 2,记得在app.js里初始化云开发环境id,如下图 [图片] 三,设置用户存储用户的数据库(集合) 在云开发管理后台,点击数据库,然后点击 + 号,添加user集合(数据表),如下图 [图片] 四,编写注册代码 代码其实很简单,我这里把对应的代码给大家贴出来。 1,注册页面的wxml文件 [图片] 2,注册页面的js文件 [代码]Page({ data: { name: '', zhanghao: '', mima: '' }, //获取用户名 getName(event) { console.log('获取输入的用户名', event.detail.value) this.setData({ name: event.detail.value }) }, //获取用户账号 getZhangHao(event) { console.log('获取输入的账号', event.detail.value) this.setData({ zhanghao: event.detail.value }) }, // 获取密码 getMiMa(event) { console.log('获取输入的密码', event.detail.value) this.setData({ mima: event.detail.value }) }, //注册 zhuce() { let name = this.data.name let zhanghao = this.data.zhanghao let mima = this.data.mima console.log("点击了注册") console.log("name", name) console.log("zhanghao", zhanghao) console.log("mima", mima) //校验用户名 if (name.length < 2) { wx.showToast({ icon: 'none', title: '用户名至少2位', }) return } if (name.length > 10) { wx.showToast({ icon: 'none', title: '用户名最多10位', }) return } //校验账号 if (zhanghao.length < 4) { wx.showToast({ icon: 'none', title: '账号至少4位', }) return } //校验密码 if (mima.length < 4) { wx.showToast({ icon: 'none', title: '密码至少4位', }) return } //注册功能的实现 wx.cloud.database().collection('user').add({ data: { name: name, zhanghao: zhanghao, mima: mima }, success(res) { console.log('注册成功', res) wx.showToast({ title: '注册成功', }) wx.navigateTo({ url: '../login/login', }) }, fail(res) { console.log('注册失败', res) } }) } }) [代码] 3,注册页面的wxss(样式)页面很简单 [图片] 我这只做下简单的样式美化,主要还是来实现功能的。 五,编写登陆页面的代码 1,登陆页面的wxml文件 [图片] 2,登陆页的js(逻辑编写)页 [代码]Page({ data: { zhanghao: '', mima: '' }, //获取输入的账号 getZhanghao(event) { //console.log('账号', event.detail.value) this.setData({ zhanghao: event.detail.value }) }, //获取输入的密码 getMima(event) { // console.log('密码', event.detail.value) this.setData({ mima: event.detail.value }) }, //点击登陆 login() { let zhanghao = this.data.zhanghao let mima = this.data.mima console.log('账号', zhanghao, '密码', mima) if (zhanghao.length < 4) { wx.showToast({ icon: 'none', title: '账号至少4位', }) return } if (mima.length < 4) { wx.showToast({ icon: 'none', title: '账号至少4位', }) return } //登陆 wx.cloud.database().collection('user').where({ zhanghao: zhanghao }).get({ success(res) { console.log("获取数据成功", res) let user = res.data[0] console.log("user", user) if (mima == user.mima) { console.log('登陆成功') wx.showToast({ title: '登陆成功', }) // wx.navigateTo({ // url: '../home/home?name=' + user.name, // }) wx.navigateTo({ url: '/pages/me/me', }) //保存用户登陆状态 wx.setStorageSync('user', user) } else { console.log('登陆失败') wx.showToast({ icon: 'none', title: '账号或密码不正确', }) } }, fail(res) { console.log("获取数据失败", res) } }) } }) [代码] 3,样式比较简单 [图片] 六,编写个人中心登陆和未登陆状态的展示,含退出登陆功能 1,wxml文件如下 [图片] 2,js文件如下,退出登陆和保存登陆状态也在里面 [代码]Page({ data: { loginOK: false }, //去登陆页 denglu() { wx.navigateTo({ url: '/pages/login/login', }) }, //去注册页 zhuce() { wx.navigateTo({ url: '/pages/index/index', }) }, onShow() { let user = wx.getStorageSync('user') if (user && user.name) { this.setData({ loginOK: true, name: user.name }) } else { this.setData({ loginOK: false }) } }, //退出登陆 tuichu() { wx.setStorageSync('user', null) let user = wx.getStorageSync('user') if (user && user.name) { this.setData({ loginOK: true, name: user.name }) } else { this.setData({ loginOK: false }) } } }) [代码] 3,个人中心登陆成功的状态如下 [图片] 到这里我们就完整的实现了小程序的登陆注册功能了,虽然比较简单,没有做密码加密等一些复杂的操作,但是我们基本的登陆注册原理就是这样实现的,你只有先把最基础的登陆注册功能实现,学习后面复杂的登陆注册,验证码登陆等一系列知识,才会游刃有余。 我把这节登陆注册功能的实现录制了一套课程出来,感兴趣的同学可以去看下,支持下石头哥。 https://edu.csdn.net/course/play/26948/348188
2019-12-09 - 小程序获取总是报openid错误怎么搞,求救
总是偶发性的报下面错误,怎么搞!!!求救[代码]VM15942:1 thirdScriptError[代码][代码]Cannot read property [代码][代码]'openid'[代码] [代码]of undefined;at pages/index/index onLoad [代码][代码]function[代码][代码];at api request success callback [代码][代码]function[代码][代码]TypeError: Cannot read property [代码][代码]'openid'[代码] [代码]of undefined[代码][代码] [代码][代码]at success (http:[代码][代码]//127.0.0.1:20272/appservice/pages/index/index.js:32:50)[代码][代码] [代码][代码]at Function.[代码][代码]function[代码][代码].u.(anonymous [代码][代码]function[代码][代码]) (http:[代码][代码]//127.0.0.1:20272/appservice/__dev__/WAService.js:5:26985)[代码][代码] [代码][代码]at Object.success (http:[代码][代码]//127.0.0.1:20272/appservice/__dev__/WAService.js:5:3530)[代码][代码] [代码][代码]at s.<anonymous> (http:[代码][代码]//127.0.0.1:20272/appservice/__dev__/WAService.js:13:22198)[代码][代码] [代码][代码]at s.emit (http:[代码][代码]//127.0.0.1:20272/appservice/__dev__/WAService.js:7:14391)[代码][代码] [代码][代码]at Function.<anonymous> (http:[代码][代码]//127.0.0.1:20272/appservice/__dev__/WAService.js:13:23534)[代码][代码] [代码][代码]at http:[代码][代码]//127.0.0.1:20272/appservice/__dev__/WAService.js:6:17573[代码][代码] [代码][代码]at a (http:[代码][代码]//127.0.0.1:20272/appservice/appservice?t=1530603174244:1033:7423)[代码][代码] [代码][代码]at b.<anonymous> (http:[代码][代码]//127.0.0.1:20272/appservice/appservice?t=1530603174244:1033:7510)[代码][代码] [代码][代码]at b.emit (http:[代码][代码]//127.0.0.1:20272/appservice/appservice?t=1530603174244:1033:22796)[代码]
2018-07-03 - 报错Cannot read property '_id' of undefined ?
虽然报错,但在模拟器上,和测试手机上都可以正常显示。 提交小程序审核,就显示不出来任何数据 VM494:1 (in promise) MiniProgramError[图片] Cannot read property '_id' of undefined TypeError: Cannot read property '_id' of undefined at http://127.0.0.1:36188/appservice/pages/shouye/shouye.js:69:29 提交审核的截图没有数据显示 [图片] [图片][图片] 打印res.data[i] [图片]
2020-07-21 - 为什么不建议用openid作为登录凭证?
在开发小程序的过程中,登录是一个入口场景,基本每个开发者都会遇到, 那么在开发过程中,我们知道 既然openid是唯一的,那我为什么不能用openid作为凭证,还要麻烦的用个第三方session 其实我之前也一直不明白,今天看了下面这个例子,顿时豁然开朗 有可能造成数据越权。 比如今天我通过我的手机登录了微信,打开了小程序。但是明天有个朋友想用我的手机登一下微信。如果用openid作为登录凭证,登录小程序的时候检测到openid已经存在,所以不会再走登录过程,这样我的数据就让我的朋友看到了。所以还是要按照官方推荐的步骤来。 ### 20191224 https://developers.weixin.qq.com/community/develop/doc/0002a028214de86e94079941551800 小明同学很稀罕同桌小花,有天看到小花在某个微信公众号写日记,好巧,猥琐的小明看到并记住了小花的开屏密码。等课间小花同学出去时,将她手机开机并打开了那个公众号,进入了个人中心。 哎呀,时间不够看呀,于是选择了用浏览器打开看到了URL。 你说巧不巧,这个站竟然在URL里有个openid的传值,没有登陆鉴权。 小明用他无比迅捷的手速把url发给了自己的号,还不着痕迹地打扫了战场。 以后的日子里,小明时刻都能通过点击那个url翻看小花的日记,真是爽煞,发起了向女神攻心的神级技能。 ### 20200107 更新:下面这个文章有说明为什么不用openid作为登录态 https://developers.weixin.qq.com/community/develop/doc/000c2424654c40bd9c960e71e5b009 Q2: 既然用户的openId是永远不变的,那么开发者可以使用openId作为用户的登录态么? A:行,这是非常危险的行为。因为openId是不变的,如果有坏人拿着别人的openId来进行请求,那么就会出现冒充的情况。所以我们建议开发者可以自己在后台生成一个拥有有效期的第三方session来做登录态,用户每隔一段时间都需要进行更新以保障数据的安全性。
2020-01-07 - 微信小程序获取openid的两种方法
第一种:使用云开发 这种比较简单,只需要开通云开发,创建云函数,调用云函数就可获得。 调用云函数 Promise Cloud.callFunction(Object object) 返回一个Promise对象,所以不用考虑异步问题。 callFunction说明 https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-sdk-api/functions/Cloud.callFunction.html具体代码如下: 我这里云函数名为helloCloud // helloCloud-index.js 云函数入口函数 exports.main = async (event, context) => { let{ APPID,OPENID}=cloud.getWXContext() return { APPID, OPENID } //------------------------------------------------------ //云函数调用 wx.cloud.callFunction({ name:'helloCloud', data:{ message:'helloCloud', } }).then(res=>{ console.log(res)//res就将appid和openid返回了 //做一些后续操作,不用考虑代码的异步执行问题。 }) 第二种:不使用云开发 这种方式就需要开发者有自己的后台了。 首先需要在微信小程序调用登录开放接口 wx.login() 获取用户登陆凭证code。 wx.login()接口说明 https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html 然后,向自己的服务器发送请求,并将code一起发送过去。 wx.login({ success (res) { if (res.code) { //发起网络请求 wx.request({ url: '自己的服务器请求接口', data: { code: res.code } }) } else { console.log('登录失败!' + res.errMsg) } } }) 接下来,在自己的服务端调用auth.code2Session接口,我这里是用Java后台。 auth.code2Session接口说明 https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html @RequestMapping("/testopenid") public String getUserInfo(@RequestParam(name = "code") String code) throws Exception { System.out.println("code" + code); String url = "https://api.weixin.qq.com/sns/jscode2session"; url += "?appid=xxxxxxxxxxxxx";//自己的appid url += "&secret=xxxxxxxxxxxxxxxxxxx";//自己的appSecret url += "&js_code=" + code; url += "&grant_type=authorization_code"; url += "&connect_redirect=1"; String res = null; CloseableHttpClient httpClient = HttpClientBuilder.create().build(); // DefaultHttpClient(); HttpGet httpget = new HttpGet(url); //GET方式 CloseableHttpResponse response = null; // 配置信息 RequestConfig requestConfig = RequestConfig.custom() // 设置连接超时时间(单位毫秒) .setConnectTimeout(5000) // 设置请求超时时间(单位毫秒) .setConnectionRequestTimeout(5000) // socket读写超时时间(单位毫秒) .setSocketTimeout(5000) // 设置是否允许重定向(默认为true) .setRedirectsEnabled(false).build(); // 将上面的配置信息 运用到这个Get请求里 httpget.setConfig(requestConfig); // 由客户端执行(发送)Get请求 response = httpClient.execute(httpget); // 从响应模型中获取响应实体 HttpEntity responseEntity = response.getEntity(); System.out.println("响应状态为:" + response.getStatusLine()); if (responseEntity != null) { res = EntityUtils.toString(responseEntity); System.out.println("响应内容长度为:" + responseEntity.getContentLength()); System.out.println("响应内容为:" + res); } // 释放资源 if (httpClient != null) { httpClient.close(); } if (response != null) { response.close(); } JSONObject jo = JSON.parseObject(res); String openid = jo.getString("openid"); System.out.println("openid" + openid); return openid; } 部分参考 https://blog.csdn.net/qq_42940875/article/details/82706638?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task 这样就获得openid了。 但是在实际应用场景中,往往需要在界面展示之前获得openid来做一些操作或者什么。 用以上代码会发现,openid后台虽然获取到了,但是小程序端页面刚展示时好像并没有获取到openid,但是之后查看数据能看到openid。 这是因为wx.request()是异步请求。也就是在请求的过程中,小程序的其他工作没有因为请求而停止。 所以,我们需要将请求封装成一个返回Promise对象的函数。 廖雪峰老师讲的Promise使用 https://www.liaoxuefeng.com/wiki/1022910821149312/1023024413276544 这样就能在请求完做一些后续操作。 代码如下: //封装wx.request() function request(requestMapping, data, requestWay, contentType) { wx.showLoading({ title: '请稍后', }) return new Promise(function(resolve, reject) { console.log('请求中。。。。。') wx.request({ url: '自己的服务器地址' + requestMapping, data: data, header: { 'content-type': contentType // 默认值 }, timeout: 3000, method: requestWay, success(res) { //console.log(res) if (res.data.success == false || res.data.statusCode == 404) { reject(res) } else { resolve(res) } }, fail: (e) => { wx.showToast({ title: '连接失败', icon: 'none' })}, complete: () => { wx.hideLoading() } }) }) } //获取openid function getOpenId(app, that){ return new Promise(function (resolve, reject) { wx.login({ success: function (yes) { // 发送 res.code 到后台换取 openId, sessionKey, unionId var requestMapping = '/testopenid' var data = { code: yes.code } var requestWay = 'GET' var contentType = 'application/json' var p =request(requestMapping, data, requestWay, contentType) p.then(res => { //console.log(res) 做一些后续操作 app.globalData.openId = res.data; resolve(res) }).catch(e => { reject(e) }) }, fail(e) { console.log(e) } }) }) } 这样就解决了因为异步获取不到数据的问题。 技术有限,欢迎交流。 觉得有用请点个赞。
2020-12-05 - 微信小程序用户授权登录机制研究和实现
微信小程序的出现,一方面缓解了用户手机安装大量APP浪费手机存储资源并导致手机速度变慢的问题,另一方面,也减轻了开发者为不同手机操作系统(Android, iOS)分别开发程序的工作负担.微信小程序应用开发是以MVC模式的JSON作为数据交换格式的以WEB开发为基础的开发技术,但是也有很多不同于以往WEB开发的地方,尤其是用户授权登录方面,用户认证信息需要在微信小程序,开发者服务器和微信接口服务器之间传递,这个过程中要考虑用户认证信息传递的流程和数据安全问题.
2021-07-14 - 微信小程序用户授权登录后,下次打开时还需要再次授权登录,为什么会这样?
为什么会出现这个问题,请解答。
2021-09-16 - 微信小程序使用微信授权登录流程,附源码易上手!
官方文档我就不贴了,写那么多我也看不下去,直接说一下流程,第一步用户触发js方法,跳转到下面的授权登录界面,用户点击授权之后就会弹出图二,用户和点击拒绝或应许之后就看下面的js流程就好 [图片] [图片] WXML <!--授权页面--> <view wx:if="{{canIUse}}"> <view class='header'> <image class="my-img" src='../../image/icon/3.jpg'></image> </view> <view class='content'> <view>申请获取以下权限</view> <text>获得你的公开信息(昵称,头像等)</text> </view> <button class='bottom' type='primary' open-type="getUserInfo" lang="zh_CN" bindgetuserinfo="bindGetUserInfo"> 点击授权 </button> </view> <view wx:else>请升级微信版本</view> wxss .header { margin: 90rpx 0 90rpx 50rpx; border-bottom: 1px solid #ccc; text-align: center; width: 650rpx; height: 300rpx; line-height: 450rpx; } .my-img { width: 120rpx; height: 120rpx; } .content { margin-left: 50rpx; margin-bottom: 90rpx; } .content text { display: block; color: #9d9d9d; margin-top: 40rpx; } .bottom { border-radius: 80rpx; margin: 70rpx 50rpx; font-size: 35rpx; } JS const app = getApp(); Page({ /** * 页面的初始数据 */ data: { // 判断小程序的API,回调,参数,组件等是否在当前版本可用。 canIUse: wx.canIUse('button.open-type.getUserInfo') //获取用户信息是否在当前版本可用 }, /** * 生命周期函数--监听页面加载 */ onLoad: function (options) {}, bindGetUserInfo: function (e) { //点击的“拒绝”或者“允许 if (e.detail.userInfo) { //点击了“允许”按钮, wx.login({ // 调用微信登录api success: function (res) { // 这一步是获取用户在小程序里的临时code码 app.http.getOpenId({ // 请求后台接口,用code码换取用户信息openid或者token js_code: res.code, }).then(res => { wx.setStorageSync('openid', res.data.openid) wx.setStorageSync('Token', res.data.Token) }) }, fail: function (res) { // 获取code码失败的方法 return app.ShowToast('授权失败' + res.Msg) } }) } else { //用户点击拒绝逻辑 } } })
2021-06-19 - (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 - 微信小程序三种授权登录的方式
经过一段时间对微信小程序的研发后 总结出以下三种授权登录的方式,我给他们命名为‘一次性授权’‘永久授权’‘不授权’ 1.一次性授权 常规写法,需要获取用户公开信息(头像,昵称等)时,判断调取授权登录接口,但是此方法如果不经处理的话 用户如果拒绝授权或者删除该微信小程序后 需要重新调取并获取用户公开信息(头像,昵称等),此方法用户体验较差,不建议使用; 2.永久授权 在不必要使用用户公开信息(头像,昵称等)时,不调取授权登录接口,只有在必要的时候再去判断调取授权登录接口并把获取到的用户公开信息存入数据库,这样在每次登录时直接先运行指定函数从数据库索取需要的用户公开信息(头像,昵称等)即可,此方法在删除小程序后不用再次去授权登录(因为在用户第一次授权登录时已经把用户的公开信息存入数据库了以后直接向数据库索取即可),建议使用; 3.不授权 不需要授权登录获取用户公开信息(头像,昵称等),使用wx.login获取用户code并传入后台,后台可以通过用户的code值向微信要一个值(具体需要问后台,我只是个小前端,后台的东西不是很懂,只是知道一些逻辑而且也已经成功实现)然后通过这个用code换取的值就可以识别到指定用户,如果需要的话,前端要显示的头像、昵称等这些信息可以使用自定义可编辑的功能,当然,也可以通过<open-data type=“userAvatarUrl”></open-data><open-data type=“userNickName”></open-data>小程序提供的这个组件显示用户的头像及昵称(不过这个组件只有显示功能),用户如果想直接使用自己的头像昵称,也可以自行授权(比如添加个引导按钮什么之类的),建议使用; [图片][图片] 文中使用的微信自带接口、组件及函数: <open-data type=“userAvatarUrl”></open-data> <open-data type=“userNickName”></open-data> wx.login({ success(res){ console.log(res.code) } }) 微信授权登录 以上三种方式可以灵活运用,也可以把需要的结合到一起,并不冲突; 当然,大佬很多,我也只是个小前端而已,第一次发表技术方面的帖子,希望互相学习,互相指导,如有说的不对的地方还望大佬们及时指出!!! 谢谢
2019-04-18 - 微信小程序setData源码分析
背景 setData 是小程序开发中使用最频繁的接口,也是最容易引发性能问题的接口。详见官网描述 常见的 setData 操作错误 频繁的去 setData 每次 setData 都传递大量新数据 后台态页面进行 setData 针对第二点官网给出意见是,其中 key 可以以数据路径的形式给出,支持改变数组中的某一项或对象的某个属性,如 array[2].message,a.b.c.d,并且不需要在 this.data 中预先定义 下面通过源码深入分析的方式了解小程序是怎么针对数据路径进行组装和构造数据 小程序逻辑层框架源码 微信小程序运行在三端:iOS(iPhone/iPad)、Android 和 用于调试的开发者工具。在开发工具上,小程序逻辑层的 javascript 代码是运行在 NW.js 中,视图层是由 Chromium 60 Webview 来渲染的。这里简单点就直接通过开发者工具来查找源码。 在微信开发者工具中,编译运行你的小程序项目,然后打开控制台,输入 document 并回车,就可以看到小程序运行时,WebView 加载的完整的 WAPageFrame.html,如下图: [图片] 可以看到[代码]./__dev__/WAService.js[代码]这个库就小程序逻辑层基础库,提供逻辑层基础的 API 能力 查找WAService.js源码 在微信小程序 IDE 控制台输入 openVendor 命令,可以打开微信小程序开发工具的资源目录 [图片] 我们可以看到小程序各版本的运行时包 .wxvpkg。.wxvpkg 文件可以使用 wechat-app-unpack 解开,解开后里面就是[代码]WAService.js[代码] 和 [代码]WAWebView.js[代码] 等代码 [图片] 另外也可以只直接通过开发者工具的Sources面板查找到WAService.js的源码 [图片] 分析setData源码 在WAService.js中全局查找setData方法,找到定义此方法的地方,如下 [图片] 源代码使用了大量的逗号运算符,逗号运算符的优先级是最低的,比条件选择符还低 大量使用void 0 表示undefined setData函数定义中添加了关键的注释如下: [代码]function(c, e) { // 保存闭包内的this对象,即常用的that var u = this; // 官网定义 Page.prototype.setData(Object data, Function callback), // 即 c: Object对象,e: Function界面更新渲染完毕后的回调函数 try { // 返回 [object Object] 中的Object var t = v(c); if ("Object" !== t) return void E("类型错误", "setData accepts an Object rather than some " + t); Object.keys(c).forEach(function(e) { // e: 可枚举属性的键值, void 0 表示undefined (https://github.com/lessfish/underscore-analysis/issues/1) void 0 === c[e] && E("Page setData warning", 'Setting data field "' + e + '" to undefined is invalid.'); // t为包含子对象属性名的属性数组, u.data和u.__viewData__都是page.data的深拷贝副本 var t = N(e) , n = j(u.data, t) , r = n.obj , o = n.key; if (r && (r[o] = y(c[e])), void 0 !== c[e]) { var i = j(u.__viewData__, t) , a = i.obj , s = i.key; a && (a[s] = y(c[e])) } }), __appServiceSDK__.traceBeginEvent("Framework", "DataEmitter::emit"), this.__wxComponentInst__.setData(JSON.parse(JSON.stringify(c)), e), __appServiceSDK__.traceEndEvent() } catch (e) { k(e) } } [代码] 关键函数N(e),解析属性名(包含.和[]等数据路径符号),返回相应的层级数组,如 [代码]{abc: 1}中abc属性名 => [abc], {a.b.c: 1}中'a.b.c'属性 => [a,b,c], {"array[0].text": 1} => [array, 0, text][代码] 关键的注释如下 [代码]function N(e) { // 如果属性名不是String字符串就抛出异常 if ("String" !== v(e)) throw E("数据路径错误", "Path must be a string"), new M("Path must be a string"); for (var t = e.length, n = [], r = "", o = 0, i = !1, a = !1, s = 0; s < t; s++) { var c = e[s]; if ("\\" === c) // 如果属性名中包含\\. \\[ \\] 三个转义属性字符就将. [ ]三个字符单独拼接到字符串r中保存,否则就拼接\\ s + 1 < t && ("." === e[s + 1] || "[" === e[s + 1] || "]" === e[s + 1]) ? (r += e[s + 1], s++) : r += "\\"; else if ("." === c) // 遇到.字符并且r字符串非空时,就将r保存到n数组中并清空r; 目的是将{ a.b.c.d: 1 }中的链式属性名分开,保存到数组n中,如[a,b,c,] r && (n.push(r), r = ""); else if ("[" === c) { // 遇到[字符并且r字符串非空时,就将r保存到n数组中并清空r;目的是将{ array[11]: 1 }中的数组属性名保存到数组n中,如[array,] // 如果此时[为属性名的第一个字符就报错,也就是说属性名不能直接为访问器, 如{ [11]: 1} if (r && (n.push(r), r = ""), 0 === n.length) throw E("数据路径错误", "Path can not start with []: " + e), new M("Path can not start with []: " + e); // a赋值为true, i赋值为false i = !(a = !0) } else if ("]" === c) { if (!i) throw E("数据路径错误", "Must have number in []: " + e), new M("Must have number in []: " + e); // 遍历到{ array[11]: 1 }中的']'的时候,就将a赋值为false, 并将o保存到数组n中,如[array,11,] a = !1, n.push(o), o = 0 } else if (a) { if (c < "0" || "9" < c) throw E("数据路径错误", "Only number 0-9 could inside []: " + e), new M("Only number 0-9 could inside []: " + e); // 遍历到{ array[11]: 1 }中的'11'的时候,就将i赋值为true, 并将string类型的数字计算成Number类型保存到o中 i = !0, o = 10 * o + c.charCodeAt(0) - 48 } else r += c // 普通类型的字符就直接拼接到r中 } // 将普通的字符串属性名,.和]后面剩余的字符串保存到数组n中,如{abc: 1} => [abc], {a.b.c: 1} => [a,b,c], {array[0].text: 1} => [array, 0, text] if (r && n.push(r),0 === n.length) throw E("数据路径错误", "Path can not be empty"), new M("Path can not be empty"); return n } [代码] 关键函数j(e, t),解析出属性最终对应的子对象的属性名,以及对应的子对象 [代码]var x = Object.prototype.toString; function _(e) { return "[object Object]" === x.call(e) } function j(e, t) { // e: page.data的深拷贝副本, t为包含子对象属性名的属性数组 /* - 遍历属性数组[a,b], e={a: {b: 1}} 1. i=0, 此时o为Object类型时, n = a, r = {a: {b: 1}}, o = {b: 1}; 2. i=1, 此时o为Object类型时, n = b, r = {b: 1}, o = 1; retrun { obj: {b: 1}, key: b} - 遍历属性数组[a,0,b], e={a: [{b: 1}]} 1. i=0, 此时t[i]=a, o为Object类型时, n = a, r = {a: [{b: 1}]}, o = [{b: 1}]; 2. i=1, 此时t[i]=0, o为Array类型时, n = 0, r = [{b: 1}], o = {b: 1}; 3. i=2, 此时t[i]=b, o为Object类型时, n = b, r = {b: 1}, o = 1; retrun { obj: {b: 1}, key: b} */ for (var n, r = {}, o = e, i = 0; i < t.length; i++) Number(t[i]) === t[i] && t[i] % 1 == 0 ? // t[i]是否为有效的Number Array.isArray(o) || (r[n] = [], o = r[n]) : _(o) || (r[n] = {}, o = r[n]), n = t[i], o = (r = o)[t[i]]; //注意由于逗号分隔符的优先级是最低的,所以这一行会在前面的条件运算符执行完,再执行 return { obj: r, key: n } } [代码] 最后通过[代码]r && (r[o] = y(c[e]))[代码]的方式将新的值赋给匹配出的子对象的属性,这里j(e,t)函数内部是通过引用的方式向外传递出[代码]r[代码],所以这里改变[代码]r[o][代码]的值也会将[代码]u.data[代码]内部的值相应修改,完成局部刷新 由于不同的版本解包后,里面压缩之后的方法名称可能跟上面的对不上,但是大体的结构都是一样的 总结 官方提供的array[2].message,a.b.c.d方式就是通过解析成[array,2,message]和[a,b,c,d],找到相应的子结构进行复制操作,到达减少数据量的目的; 分页加载的时候,为了避免将整个list数据重新传输,就可以利用数据路径的方式只追加新的数据 [代码]假设原数组长度 length 为 10,新数组 newList 长度为 3 this.setData{ 'list[10]': newList[0], 'list[11]': newList[1], 'list[12]': newList[2], } [代码] 参考资料 微信小程序技术原理分析 小程序开发指南
2019-08-24 - 如何解决_this.setData与this.setData都无法赋值?
onLoad: function (options) { const db = wx.cloud.database({ env: 'ka-tset-pz57d' }) db.collection('readergoods').get({ success: res=> { console.log(res.data) , console.log(res.data[0].goods_name) this.setData({ goodslists: res.data, name:res.data[0].goods_name, price:res.data[0].goods_price }) } }) }, 第二种方法 onLoad: function (options) { var _this = this; const db = wx.cloud.database({ env: 'ka-tset-pz57d' }) db.collection('readergoods').get({ success: function(res) { console.log(res.data) , console.log(res.data[0].goods_name) _this.setData({ goodslists: res.data, name:res.data[0].goods_name, price:res.data[0].goods_price }) } }) }, 这两个都没有赋值成功 [图片]但是都可以console.log在控制台输出出来
2020-05-21 - 如何使用微信开发者工具发布小程序?
微信开发者工具一般由于小程序包的上传与发布。 1、到官方文档小程序工具栏目,下载开发者工具软件到桌面。其实也可以直接网页搜索“微信开发者工具”,认准微信网页进行点击下载。 [图片] 2、在电脑桌面安装后,扫码登录,点击导入项目,并填写APPID,ID信息可在腾讯小程序账号后台设置-开发者设置里进行查看。 [图片] 3、在导入项目后,软件会自动进入开发者界面,在预览小程序没有问题后,点击右上角发布按钮,即可上传发布。 [图片] 4、登录腾讯小程序后台,点击提交审核,在审核通过后,点击发布上线。 [图片] 微信小程序发布完成后,我们可以通过扫描二维码、搜一搜和绑定公众号进行快速找到和使用它。 由于技术的发展,一些智能型平台已经实现与第三方平台接口对接,已实现一键发布,告别通过开发者工具进行传输。但为了小部分的需求者学习,使用开发者工具发布小程序的教程,小编将它们附在结尾。 在鸣蝉建站上平台已升级微信小程序打包方式,可以不再使用微信小程序工具进行上传,直接在后台*可以同步至微信小程序后台。 第1步:打包小程序。 [图片] 第2步:上传小程序密钥配置白名单,具体配置说明,可以点击参考系统提供的“如何获取”查看详细的说明文档教程。 [图片] 第3步:一键上传至微信公众平台,不再需要通过工具上传。 [图片] [图片] 第4步:登录微信公众平台,提交代码审核发布即可。 [图片] 该平台直接跳过开发者工具的使用,简化小程序制作与发布的流程,适合新手与小白的快速学习和搭建自己的小程序。
2021-08-08 - 小程序代码审核新手入门篇
微信小程序在注册完成,需提交代码审核通过才能顺利发布,小程序从开发到发布的具体流程:微信小程序完成注册、信息设置、类目设置后,代码提审从开发到发布一般要经过:预览-> 上传代码 -> 提交审核 -> 发布等步骤,以下为大家介绍注册到发布前必经流程及代码审核注意事项: 整体流程 [图片] 一、板块分点 信息设置:昵称(简称)、简介、头像设置 类目设置:小程序服务类目申请 代码审核:流程步骤 小程序功能:小程序的功能可用性、内容完整性等进行整体审核 二、板块审核注意事项 1、信息设置 ①昵称板块: 不直接使用广义归纳类、营销词、热门关键词、产品分类词汇命名 未经授权不得擅自使用他人已注册企业名称、商标、他人姓名命名 详情可参考:https://developers.weixin.qq.com/community/operate/doc/00060288824708b8d588e4ae25bc01 ②简介: 明确介绍小程序的功能点、表达的意思需与实际提供的功能一致 ③头像(logo):选用清晰度高,表达内容应与小程序名称、简介、功能相符,且未经授权不得使用腾讯、微信官方或其他官方头像 2、类目设置 1、①自身运营功能与类目保持一致性(提供社交属性服务,应选择社交类目;提供时政信息服务,应选择时政信息类目) 2e ②注册主体不一样,对应开放类目范围不一样,非个人主体、个人主体、境外主体开放详细可参考: https://developers.weixin.qq.com/miniprogram/product/material/ 3、③当所选类目当涉及需报备送属地网信办审核,建议至少上线前14天进行提交审核,避免因二次审核流程过长,延误项目上线时间,报备类目详情可参考: https://developers.weixin.qq.com/community/operate/doc/00002a6a0b8d98a965993666a51001?blockType=5 3、小程序从开发到发布的具体流程: 微信小程序完成注册、信息设置、类目设置后,从开发到发布一般要经过 预览-> 上传代码 -> 提交审核 -> 发布等步骤,以下为大家介绍代码提审流程的注意事项: 3.1预览 使用开发者工具可以预览小程序,帮助开发者检查小程序在移动客户端上的真实表现。 点击开发者工具顶部操作栏的预览按钮,开发者工具会自动打包当前项目,并上传小程序代码至微信的服务器,成功之后会在界面上显示一个二维码。使用当前小程序开发者的微信扫码即可看到小程序在手机客户端上的真实表现。 [图片] 3.2上传代码 同预览不同,上传代码是用于提交体验或者审核使用的。 点击开发者工具顶部操作栏的上传按钮,填写版本号以及项目备注,需要注意的是,这里版本号以及项目备注是为了方便管理员检查版本使用的,开发者可以根据自己的实际要求来填写这两个字段。 [图片] [图片] 上传成功之后,【登录小程序管理后台 - 版本管理 - 开发版本】就可以找到刚提交上传的版本了,可以将这个版本设置体验版或者是提交审核。 [图片] [图片] 3.3 提交审核 为了保证小程序的质量,以及符合相关的规范,小程序的发布是需要经过审核的。 在开发者工具中上传了小程序代码之后,【登录小程序管理后台 - 版本管理 - 开发版本】找到提交上传的版本。在开发版本的列表中,点击 提交审核 按照页面提示,填写相关的信息,即可以将小程序提交审核。 需要注意的是,请开发者严格测试了版本之后,再提交审核,过多的审核不通过,可能会影响后续的审核时长。 [图片] [图片] [图片] [图片] 3.4 发布审核通过之后,管理员的微信中会收到小程序通过审核的通知,此时可以通过电脑端和手机端两种方式来查看审核通知: ①电脑端:【登录小程序管理后台 -通知中心】中可以看到具体的审核结果 [图片] ②手机端:模板消息代码发布审核结果 [图片] 审核通过后,可以点击发布,即可发布小程序。小程序提供了两种发布模式:全量发布和分阶段发布。全量发布是指当点击发布之后,所有用户访问小程序时都会使用当前最新的发布版本。分阶段发布是指分不同时间段来控制部分用户使用最新的发布版本,分阶段发布我们也称为灰度发布。一般来说,普通小程序发布时采用全量发布即可,当小程序承载的功能越来越多,使用的用户数越来越多时,采用分阶段发布是一个非常好的控制风险的办法。 [图片] 4、小程序功能 ①可用性 a、功能运行稳定:确保功能可打开、运行、无报错 b、体验有登录限制:应在提审之前上传有效测试信息、运行录屏,用于辅助审核判断 详情可参考:https://developers.weixin.qq.com/community/develop/doc/0002caeb3c82583722f9cb09456409 ②登录规范合规性 a、特定范围:首页应明确文案提示,服务仅为特定人群使用 b、公开范围:授权个人信息功能后置,给予用户事前了解功能后,由用户主动使用功能时,再进一步进行授权提醒 详情可参考:https://developers.weixin.qq.com/community/operate/doc/000640bb8441b82900e89f48351401 ③小程序内容完整性:提审前确保运营内容的完整性,避免出现如下无法判断的运营内容导致审核失败 ,具体如下: 【测试商品】示例: [图片] 【功能无具体运营内容】示例: [图片] 本文档为初次提交代码审核的开发者了解提审前必经流程、提审注意事项,如存在上述问题应及时调整、修正,同时提前规划好提审时间,避免后续因存在上述问题审核失败或重复提审导致无法如期上线发布。
1天前