个人案例
- 同步作品集
同步作品集
同步作品集扫码体验
- #小程序云开发挑战赛#【简易IOT】温湿度实时监控及开关控制小demo的设计
【一】产品功能概述: 1、能实时监控硬件所在地的温湿度,不限空间 2、远程的家电简易开关,硬件上以点亮LED灯进行模拟 展示网站:https://v.qq.com/x/page/u315399qtwq.html [图片] 项目的设计主要分为四个部分:①硬件选型;②硬件编程;③服务器搭建EMQ;④小程序编程 【二】硬件部分 一、选取 硬件上,主要选取单片机,esp8266,DHT11和SYN6288喇叭模块。 [图片] 二、编程 1.采用的网络协议——MQTT [图片] MQTT协议是一种消息订阅和发布为形式的网络通信协议。只要硬件和小程序用的是同一个服务器,订阅的是同一个主题,就能实现消息互通,进而用网络远程操控设备。消息之间以Json格式数据进行传输,根据不同对象设置不同键值对进行数据交互。该项目并没有涉及过于复杂的键值对数据。 2.硬件上的主题订阅,Json格式数据 [图片][图片] 3.小程序与硬件关联 [图片] [图片] [图片] 图三中,由于要说明的点较多,这里文字叙述;小程序和硬件都订阅同样的主题“SmartHome”,这样就可以实现温湿度数据的交互,中间靠服务器转接;像开关按钮这种,不属于简单的数据上传显示,这里小程序采用事件绑定,当开关组件反转时,触发事件,向SmartHome主题发布键为“LED”,值为“Value”的键值对数据,从而控制硬件。 【三】服务器搭建 一、引擎的选取 服务器引擎选用5G物联网引擎——EMQ [图片] 快速安装指令[图片] 配置软件采用FinalShell [图片] 二、服务器的配置 因为微信小程序中的服务器接口要求采用wxs和域名,就需要给服务器配置个域名,并将SSL证书装进emq的证书目录,这里不是重点,就不赘述。 [图片] 三、添加证书,使之支持wxs 把上述两个证书文件配置进configuration文件。这里也不是重点,不赘述。 [图片] 到这里,我的'wxs://stm32.mqtt-8266.xyz:8084/mqtt'接口就可以使用了!!! 【四】小程序总体编程思路 一、我的开发环境配置 [图片] 二、工程模板的生成顺序 ①mpvue快速模板生成命令: vue init mpvue/mpvue-quickstart weixin_app ②安装开发环境所需要的依赖: npm install ③安装SCSS语法的支持(主要用于改小程序图片和组件的排版) npm install -D sass-loader node-sass ④安装mqtt组件的支持 npm install --save mqtt 具体硬件与小程序联通方面的编程,已在上述介绍!!! 关于SCSS对布局的配置,主要采用B站博主的经验值进行配置 [图片] 三、编程tips 本工程采用mpvue快速生成模板进行开发,我实际需要动的只有4-5个文件,手写代码量在500行左右。 这几个需要动的文件分别是Pages下的app.json,Pages\index\index.vue,Pages\login\index.vue,Pages\logs\index.vue等 [图片] app.json文件下该部分,声明了小程序会调用的三个界面 [图片] 四、登陆界面的设计 [图片] 这个登陆界面,主要含有的元素有账户密码,以及“WanderingSun”为昵称的作者标识。在注册账户时,新增一个电话号码元素;忘记密码时,主要采取对输入电话号码核对来重置密码。这个登陆界面的设置没有用数据库,而是微信开发者工具API中自带的储存功能,具体体现在下面的函数 [图片] 1、采用的Vant-Weapp组件库 主要调用的组件(在Pages\app.json下) [图片] 2、大概设计思路(具体请评委看源代码) [图片] 实现的大部分逻辑都在methods内的事件函数中。 设立的值: [图片] 用户通过在输入框组件内输入,触发事件,实时将输入的数据同步到输入框内,主要是methods里面的前三个事件。 接下来是点击“登陆”键后,有一个判定机制,首先进行1s的模拟延时,展示“正在登陆”的动态组件,然后就是账密正确的判断,如果正确,则转入index的内容 [图片] 其他关于注册,找回密码的事件逻辑也是类似,最主要的是注意页面的回转规划,避免卡死在一处。
2020-09-21 - 微信人脸核身接口能力
一、能力背景 近年来,国家在医疗挂号、APP注册、快递收寄、客运、运营商等多领域规定,需要用户实名才可办理业务,预计后续也会有越来越多的此类法规。因此,微信参照公安部“互联网+”可信身份认证服务平台标准,依托腾讯公司及微信的生物识别技术,建立微信“实名实人信息校验能力” ,即通过人脸识别+权威源比对,校验用户实名信息和本人操作(简称微信人脸核身)。 目前接口限定主体及行业类目开放公测,提供给资质符合要求的业务方,在合适的业务场景内使用。目前仅支持持二代身份证的大陆居民。 由于人脸核身功能涉及到用户的敏感、隐私信息,因此调用此接口的小程序,需要满足一定的条件。即:小程序的主体以及类目,需要在限定的类目范围内,且与小程序的业务场景一致。开展的业务也需要是国家相关法规、政策规定的需要“实名办理”的相关业务(其他未在范围内的业务,则暂不支持)。 以下为接口接入及开发的详细内容。如开发中遇到任何疑问,可以点击此处通过社区反馈,将有工作人员跟进回复。 文档第四部分【再次获取核验结果api】,有助于提高业务方安全性,请务必接入! 现阶段微信人脸核验能力,针对小程序,开放的主体类目范围包含: 小程序一级类目 小程序二级类目 小程序三级类目 使用人脸核验接口所需资质 物流服务 收件/派件 / 《快递业务经营许可证》 物流服务 货物运输 / 《道路运输经营许可证》(经营范围需含网络货运) 教育 学历教育(学校) / (2选1):1、公立学校:由教育行政部门出具的审批设立证明 或 《事业单位法人证书》;2、私立学校:《民办学校办学许可证》与《民办非企业单位登记证书》 医疗 公立医疗机构 / 《医疗机构执业许可证》与《事业单位法人证书》 医疗 互联网医院 / 仅支持公立医疗机构互联网医院(2选1):1、卫生健康部门的《设置医疗机构批准书》;2、 《医疗机构执业许可证》(范围均需含“互联网诊疗”或名称含“互联网医院”等相关内容 医疗服务 三级私立医疗机构 / 仅支持三级以上私立医疗机构,提供《医疗机构执业许可证》、《营业执照》及《医院等级证书》 政务民生 所有二级类目 / 仅支持政府/事业单位,提供《组织机构代码证》或《统一社会信用代码证》。 金融业 银行 / (2选1):1、《金融许可证》; 2、《金融机构许可证》。 金融业 信托 / (2选1):1、《金融许可证》; 2、《金融机构许可证》。 金融业 公募基金 / (4选1):1、《经营证券期货业务许可证》且业务范围必须包含“基金”;2、《基金托管业务许可证》; 3、《基金销售业务资格证书》;4、《基金管理资格证书》。 金融业 证券/期货 / 《经营证券期货业务许可证》 金融业 保险 / (8选1):1、《保险公司法人许可证》;2、《经营保险业务许可证》;3、《保险营销服务许可证》;4、《保险中介许可证》;5、《经营保险经纪业务许可证》;6、《经营保险公估业务许可证》或《经营保险公估业务备案》;7、《经营保险资产管理业务许可证》 ;8、《保险兼业代理业务许可证》。 金融业 消费金融 / 银监会核准开业的审批文件与《金融许可证》与《营业执照》 金融业 汽车金融/金融租赁 / 仅支持汽车金融/金融租赁主体,同时提供:1、《营业执照》(公司名称包含“汽车金融” /“金融租赁”;营业范围包含“汽车金融”/“金融租赁”业务);2、《金融许可证》或银保监会及其派出机构颁发的开业核准批复文件。 交通服务 网约车 快车/专车/其他网约车 (自营性网约车)提供《网络预约出租汽车经营许可证》。(网约车平台)提供与网约车公司的合作协议以及合作网约车公司的《网络预约出租汽车经营许可证》。 交通服务 航空 / (航司)提供《公共航空运输企业经营许可证》。(机场)提供《民用机场使用许可证》或《运输机场使用许可证》。 交通服务 公交/地铁 / 提供公交/地铁/交通卡公司《营业执照》 交通服务 水运 / (船企)提供《水路运输许可证》。(港口)提供《港口经营许可证》 交通服务 骑车 / 仅支持共享单车,提供共享单车公司《营业执照》 交通服务 火车/高铁/动车 / 仅支持铁路局/公司官方,提供铁路局/公司《营业执照》 交通服务 长途汽车 / (2选1):1、《道路运输经营许可证》(经营范围需含客运);2、官方指定联网售票平台(授权或协议或公开可查询文件)。 交通服务 租车 / 运营公司提供《备案证明》与对应公司《营业执照》,且营业执照中包含汽车租赁业务 交通服务 高速服务 / 仅支持ETC发行业务,(2选1):1、事业单位主体,需提供《事业单位法人证书》;2、官方指定的发行单位(一发单位),需提供“官方授权或协议,或公开可查询的文件”; 生活服务 生活缴费 / (供电类)提供《电力业务许可证》与《营业执照》,且《营业执照》且经营范围含供电。(燃气类)提供《燃气经营许可证》与《营业执照》,且《营业执照》且经营范围含供气。(供水类)提供《卫生许可证》与《营业执照》。(供热类)提供《供热经营许可证》与《营业执照》,且《营业执照》且经营范围含供热。 IT科技 基础电信运营商 / (2选1):1、基础电信运营商:提供《基础电信业务经营许可证》;2、运营商分/子公司:提供营业执照(含相关业务范围)。 IT科技 转售移动通信 / 仅支持虚拟运营商,提供《增值电信业务许可证》(业务种类需含通过转售方式提供移动通信业务) 旅游服务 住宿服务 / 仅支持酒店,提供《酒店业特种行业经营许可证》 商业服务 公证 / 仅支持公证处,提供《公证处执业许可证》或《事业单位法人证书》 社交 直播 / (2选1):1、《信息网络传播视听节目许可证》;2、《网络文化经营许可证》(经营范围含网络表演)。 如对以上类目或资质有疑问,可点击参考小程序“非个人主体开放的服务类目”,详细了解小程序开放的服务类目及对应资质。 二、准备接入 (请在小程序发布后,再提交人脸核身接口申请) 满足第一节中描述的类目和主体的小程序,可申请微信人脸核验接口。目前微信人脸核身接口已改为线上自助申请方式,需按照如下图例指引,进行接口申请: 第一步:请通过mp.weixin.qq.com登录小程序账号在后台“功能-人脸核身”的路径,点击开通按钮—— [图片] 第二步:仔细查阅《人脸识别身份信息验证服务条款》后,点击“同意并下一步”—— [图片] 第三步:请正确填写服务信息,并上传该小程序类目下所要求的资质—— [图片] 第四步:请按照业务实际需求填写使用人脸接口的场景和用途—— [图片] 第五步:请完善测试信息和联系人—— [图片] 第六步:提交后请耐心等待1-3个工作日的审核期,审核结果将以站内信通知—— 如申请期间遇到问题,可联系腾讯工作邮箱 wx_city@tencent.com,将会有相关工作人员进一步指引。 三、接口文档: (一)接口描述 名称: wx.startFacialRecognitionVerify(OBJECT) 功能:请求进行基于生物识别的人脸核身 验证方式:在线验证 兼容版本: 一闪:android 微信7.0.22以上版本, iOS 微信7.0.18以上版本 建议在微信官网升级至最新版本 (二)参数说明 1、OBJECT参数说明: 参数 类型 必填 说明 name String 是 姓名 idCardNumber String 是 身份证号码 success Function 否 调用成功回调 fail Function 否 调用失败回调 complete Function 是 调用完成回调(成功或失败都会回调) 2、CALLBACK返回参数 参数 类型 说明 errMsg String 错误信息 errCode Number 错误码 verifyResult String 本次认证结果凭据,第三方可以选择根据这个凭据获取相关信息 注 1:传递用户姓名和身份证有两种方式 业务方没有用户实名信息,用户需要在前端填写身份证和姓名,那么前端直接通过jsapi 调用传递 name 和 idCardNumber。 业务方已经有用户实名信息,后台通过微信提供的 api(详情见文档后面“上传姓名身份证后台 api”)上传用户身份证姓名和身份证,api 返回 user_id_key 作为凭证传给前端,前端再调用 jsapi,用户姓名、身份证信息不需要经过前端,参数只需要传递 userIdKey。Tips:使用该功能需要小程序基础库版本号>=1.9.3。 3、回调结果说明 回调结果请参考以下释义: [图片] [图片] [图片] 4、示例代码 [图片] [图片] (三)上传用户姓名身份证的后台api 1、API说明 1.1说明 业务方上传用户姓名和身份证,获取用户凭证,把凭证给到前端通过 jsapi 调用。 Tips :使用该功能需要小程序基础库版本号>=1.9.3。 1.2请求URL https://api.weixin.qq.com/cityservice/face/identify/getuseridkey?access_token={ac cess_token} 1.3请求方式 POST 2、请求数据格式 [代码]Json { "name" : “张三”, "id_card_number" : "452122xxxxxxx43215" } [代码] 请求示例 [代码]#!/bin/bash TOKEN='xxxxxxxxxxxx' URL='https://api.weixin.qq.com/cityservice/face/identify/getuseridkey' JSON='{ "name": "张三", "id_card_number": "452344xxxxxxxxxxxxx234"}' curl "${URL}?access_token=${TOKEN}" -d "${JSON}" [代码] 参数说明 json 字段 中文显示 是否必传 name 姓名 是 id_card_number 身份证号码 是 out_seq_no 业务方唯一流水号 否 3、返回数据 参数 类 型 说明 errcode int 错误码 errmsg string 错误信息 user_id_key string 用于后台交互表示用户姓名、身份证的凭证 expires_in uint32 user_id_key 有效期,过期需重新获取 [代码]{ "errcode" : 0, "errmsg" : "ok", "user_id_key" : "id_key_xxxx", "expires_in": 3600 } [代码] 4、后台消息推送 如果业务方传入out_seq_no,核身完成后会通过消息推送回调给业务方的服务器,如果回调业务方失败,会在5s尽力推送,超过5s不再推送。 参数说明 参数 类 型 说明 ToUserName string 小程序原始ID FromUserName string 事件消息openid CreateTime uint32 消息推送时间 MsgType string 消息类型 Event string 事件类型 openid string 核身用户的openid out_seq_no string 业务方唯一流水号 verify_result string 核身返回的加密key(凭据) 返回示例 [代码]{ "ToUserName": "gh_81fxxxxxxxx", "FromUserName": "oRRn15NUibBxxxxxxxxx", "CreateTime": 1703657835, "MsgType": "event", "Event": "face_identify", "openid": "oRRn15NUibBxxxxxxxxx", "out_seq_no": "test1234", "verify_result": "XXIzTtMqCxwOaawoE91-VNGAC3v1j9MP-5fZJxv0fYT4aGezzvYlUb-n6RWQa7XeJpQo0teKj8mGE4ZcRe1JI3GqzADBYORBu613rKjKAFfEXTXw_bu1bs7MnmPOpguS" } [代码] 四、再次获取核验结果api 此接口是前端完成人脸核身后,基于前端返回的凭据,通过后台api再次进行核验结果和身份信息的校验,有助于提高安全性,请务必接入! 前端获取结果不可信,存在被篡改的风险,为了保障请求结果安全性,请务必对identify_ret、id_card_number_md5、name_utf8_md5字段进行校验! (一)API说明 1、说明 人脸核身之后,开发者可以根据jsapi返回的verify_result向后台拉取当次认证的结果信息。 2、请求URL https://api.weixin.qq.com/cityservice/face/identify/getinfo?access_token={access_token} 3、请求方式 POST 4、请求格式 json (二)请求数据说明 1、请求 参数 类型 是否必填 描述 verify_result String 是 jsapi返回的加密key(凭据) 2、数据返回 HTTP 头如下 Date: Mon, 06 Feb 2017 08:12:58 GMT Content-Type: application/json; encoding=utf-8 Content-Length: 85 Connection: close json示例 [代码]{ "errcode" : 0, [代码] [代码]"errmsg" : "ok", "identify_ret" : 0, "identify_time" : 1486350357 "validate_data": "8593" [代码] [图片] (三)返回参数说明 1、返回参数 注:errcode和identify_ret同时为0,代表本次认证成功。 参数 类型 描述 errcode int 错误码, 0表示本次api调用成功 errmsg string 本次api调用的错误信息 identify_ret int 人脸核身最终认证结果 identify_time uint32 认证时间 validate_data string 用户读的数字(如是读数字) openid string 用户openid user_id_key string 用于后台交互表示用户姓名、身份证的凭证 finish_time uint32 认证结束时间 id_card_number_md5 string 身份证号的md5(最后一位X为大写) name_utf8_md5 string 姓名MD5 2、错误码对应信息 errcode 备注 84001 非法identity_id 84002 用户信息过期 84003 用户信息不存在 五、小程序辅助接口:检查设备是否支持人脸检测 1、接口名称 接 口 :wx.checkIsSupportFacialRecognition(OBJECT) 功能:检查设备是否支持人脸检测 2、接口说明和使用 小程序调用该接口,可以检测当前手机设备是否具备支持人脸检测的能力,可与以上接口分开使用,为了用户体验,建议调用后对手机设备不支持的用户做对应功能处理。 3、接口说明和使用 01 OBJECT 参数说明: 参数 类型 是否必填 描述 success Function 否 调用成功回调 fail Function 否 调用失败回调 complete Function 是 调用完成回调(成功或失败都会回调) checkAliveType Number 否 人脸核验的交互方式,默认读数字(见表 2) 表 2:checkAliveType 的值和对应的解释: 参数 解释 2 先检查是否可以屏幕闪烁,不可以则自动为读数字 02 CALLBACK 返回参数 参数 类型 说明 errMsg Boolean 错误信息 errCode Number 错误码 03 回调结果说明 回调类型 ErrCode 说明 sucess 0 支持人脸采集 fail 10001 不支持人脸采集:设备没有前置摄像头 fail 10002 不支持人脸采集:没有下载到必要模型 fail 10003 不支持人脸采集:后台控制不支持 回调结果说明仅对Android生效,iOS不返回errcode。 04 示例代码 [图片] 六、安全性说明 为保障业务可用性以及安全性,请详细研读微信人脸核身接口相关基础说明及安全说明文档:https://docs.qq.com/doc/DTFB0YWFIdGV6amly 备注:如开发中遇到任何疑问,可以点击此处通过社区反馈,将有工作人员跟进回复。 七、案例展示及补充说明 安徽医科大学第二附属医院,微信人脸核验登录: 安徽医科大学第二附属医院,是三级甲等综合医院。其小程序为用户提供挂号、门诊费用、住院费用、检查报告、体检等医疗服务,同时也提供停车、餐饮等便民服务,是医疗小程序中完整的案例。 小程序使用了微信人脸核验能力作为登录的核验。满足医院管理要求,也满足国家对于实名就医的管理规则。 案例实现的截图效果如下: [图片] [图片] 针对近期少数小程序方面反馈的两类问题,也在本课程进行补充说明。 1、本接口的开放范围,即:可支持的主体类目,是否可以扩大? 说明:基于本接口整体使用范围的评估、相关法规的参考、监管策略的理解执行等,暂时未立刻进行扩大开放范围的工作。 但我们会持续基于不同行业的法规、政策及监管要求等,逐一进行研究考量,以便确认如何扩大开放范围。 2、小程序如果涉及用户本人的生物特征采集,(如本人人脸照片、人脸视频),或涉及采集用户本人生物特征信息并开展人脸核验功能,则存在被驳回的情况? 说明:近两年“人脸识别”技术在社会上掀起了热潮。人脸识别虽然作为摆脱“中间媒介”或“承载载体”的一种直接技术手段,解决了部分政务、交通、医疗、零售等证明“操作者是本人”的问题,但也因此,引入了新的更大的安全风险。 一是,虚假安全风险。 身份认证领域的安全三因素包括“我知道什么”、“我拥有什么”、“我的特征是什么”,通用的安全做法,是要双因素认证(2FA),人脸识别技术如仅凭“我的特征是什么”这一个因素,则容易被攻破或利用。表象给用户以安全的感觉,但实际并不能达到安全效果。 二是,信息泄漏的风险。 越来越多的组织或个人,在并非必需用户敏感信息、生物特征的情况下,采集并存储此类信息。在信息加密、传输、存储过程中,容易暴漏更多的网络节点,使得此类信息有更大的风险被网络黑客拦截、窃听、窃取,或直接被脱库。 三是,消除风险的难度大。 以往基于“中间媒介”或“承载载体”的方式,如出现丢失、被冒用、恶意盗用等风险,可以通过挂失、更换、使用新载体或新媒介等方式,快速排除一定的风险。C端主动,B端主动,都能解决一部分问题。但人脸识别做为更直接的方式,一旦出现冒用、盗用,受害者将面临更大的财产及人生安全风险,且C端用户更多时候无法主动消除风险。 基于以上问题风险,加之国家出台《网络安全法》、《用户隐私保护条例》等法律法规标准,网信办、公安部、工信部及市场监管总局等四部委发起的app获取隐私整治,结合平台安全、用户敏感隐私信息保护要求及监管,针对部分暂无相关法规或要求,需要采集或生物认证方式进行身份核验的,或以“追热点”或“尝鲜”为目的,采集用户生物特征或进行身份核验的,进行严格审核,必要时不予以支持。
星期一 15:19 - weapp-qrcode-canvas-2d在微信小程序中生成二维码,新版canvas-2d接口
weapp-qrcode-canvas-2d weapp-qrcode-canvas-2d 是使用新版canvas-2d接口在微信小程序中生成二维码(外部二维码)的js包。canvas 2d 接口支持同层渲染且性能更佳,建议切换使用,可大幅提升生成图片的速度。 仓库地址 weapp-qrcode-canvas-2d【码云gitee】 weapp-qrcode-canvas-2d【github】 [图片] 测试环境 微信小程序基础库版本:2.10.4 开发者工具版本:Stable 1.03.2101150 Usage 先在 wxml 文件中,创建绘制的 [代码]canvas[代码],并定义好 [代码]width[代码], [代码]height[代码], [代码]id[代码] , [代码]type[代码] ,其中type的值必须为[代码]2d[代码] [代码]<canvas type="2d" style="width: 260px; height: 260px;" id="myQrcode"></canvas> [代码] 安装方法1:直接引入 js 文件 直接引入 js 文件,使用 [代码]drawQrcode()[代码] 绘制二维码 [代码]// 将 dist 目录下,weapp.qrcode.esm.js 复制到项目中。路径根据实际引用的页面路径自行改变 import drawQrcode from '../../utils/weapp.qrcode.esm.js' [代码] 安装方法2:npm安装 [代码]npm install weapp-qrcode-canvas-2d --save [代码] // 然后需要在小程序开发者工具中:构建npm [代码]import drawQrcode from 'weapp-qrcode-canvas-2d' [代码] 安装完成后调用 例子1:没有使用叠加图片 [代码]const query = wx.createSelectorQuery() query.select('#myQrcode') .fields({ node: true, size: true }) .exec((res) => { var canvas = res[0].node // 调用方法drawQrcode生成二维码 drawQrcode({ canvas: canvas, canvasId: 'myQrcode', width: 260, padding: 30, background: '#ffffff', foreground: '#000000', text: 'abc', }) // 获取临时路径(得到之后,想干嘛就干嘛了) wx.canvasToTempFilePath({ canvasId: 'myQrcode', canvas: canvas, x: 0, y: 0, width: 260, height: 260, destWidth: 260, destHeight: 260, success(res) { console.log('二维码临时路径:', res.tempFilePath) }, fail(res) { console.error(res) } }) }) [代码] 例子2:使用叠加图片(在二维码中加logo) [代码]const query = wx.createSelectorQuery() query.select('#myQrcode') .fields({ node: true, size: true }) .exec((res) => { var canvas = res[0].node var img = canvas.createImage(); img.src = "/image/logo.png" img.onload = function () { // img.onload完成后才能调用 drawQrcode方法 var options = { canvas: canvas, canvasId: 'myQrcode', width: 260, padding: 30, paddingColor: '#fff', background: '#fff', foreground: '#000000', text: '123456789', image: { imageResource: img, width: 80, // 建议不要设置过大,以免影响扫码 height: 80, // 建议不要设置过大,以免影响扫码 round: true // Logo图片是否为圆形 } } drawQrcode(options) // 获取临时路径(得到之后,想干嘛就干嘛了) wx.canvasToTempFilePath({ x: 0, y: 0, width: 260, height: 260, destWidth: 600, destHeight: 600, canvasId: 'myQrcode', canvas: canvas, success(res) { console.log('二维码临时路径为:', res.tempFilePath) }, fail(res) { console.error(res) } }) }; }) [代码] API drawQrcode([options]) options Type: Object 参数 必须 说明 示例 canvas 必须 画布标识,传入 canvas 组件实例 canvasId 非 绘制的[代码]canvasId[代码] [代码]'myQrcode'[代码] text 必须 二维码内容 ‘123456789’ width 非 二维码宽度,与[代码]canvas[代码]的[代码]width[代码]保持一致 260 padding 非 空白内边距 20 paddingColor 非 内边距颜色 默认与background一致 background 非 二维码背景颜色,默认值白色 [代码]'#ffffff'[代码] foreground 非 二维码前景色,默认值黑色 [代码]'#000000'[代码] typeNumber 非 二维码的计算模式,默认值-1 8 correctLevel 非 二维码纠错级别,默认值为高级,取值:[代码]{ L: 1, M: 0, Q: 3, H: 2 }[代码] 1 image 非 在 canvas 上绘制图片,层级高于二维码,v1.1.1+版本支持。具体使用见:例子2 [代码]{imageResource: '', width:80, height: 80, round: true}[代码]
2023-04-02 - 利用onAccelerometerChange实现水平仪 加速计
小程序的加速计的接口 wx.onAccelerometerChange(function callback) 监听加速度数据事件。频率根据 wx.startAccelerometer() 的 interval 参数, 接口调用后会自动开始监听。 参数 function callback 加速度数据事件的回调函数 参数 Object res 属性 类型 说明 x number X 轴 y number Y 轴 z number Z 轴 通过以上API我们可以得到下面一段代码,这块可以放到小程序onLoad中回调中 [代码] wx.onAccelerometerChange(function (res) { const { x,y,z} = res; }) [代码] 手机的xyz轴 那么 x y z,分别代表 x轴 Y轴 z轴 哪在手机上上如何展示呢 [图片] 从上图我们可以看到手机的坐标,那么假如我们有一条线为水平在手机中显示 [图片] 数学知识 如上图,这样我们只要计算x与y的夹角就可以了,接下来怎么计算呢,我们用到两个数学知识 1. Math.atan2() [图片] ** Math.atan2()接受两个参数x和y,方法如下:** angel=Math.atan2(y,x) x 指定点的 x 坐标的数字。 y 指定点的 y 坐标的数字。 计算出来的结果angel是一个弧度值,也可以表示相对直角三角形对角的角,其中 x 是临边边长,而 y 是对边边长。 **2. 角度=弧度*180/Math.PI [图片] 清楚了上面两个知识那么我代码继续写 [代码] wx.onAccelerometerChange(function (res) { const { x,y,z} = res; //根据公式计算出角度 const rotateXY = Math.atan2(x,y) * 180 / Math.PI; // 这里角度就可以赋值到data上,视图层就可以调这个角度了 this.setData({ rotateXY: rotateXY }) }) [代码] 下面是wxml中的内容 [代码]<view style="width:600rpx; height:2rpx;background:red;transform:rotate({{rotateXY}}deg)"> [代码] 扫码体验 好了,整体就结束了 底部再添加上camera 就可以通过摄像头,来测量物体是否水平, 以下图片可以扫码体验 [图片]
2020-11-04 - 为什么拓展组件tabs在上拉加载更多数据后滚动条会回到顶部?
最近做项目 , 有一个左右滑动切换的需求 ,用了微信拓展组件tabs , 但是在用scroll-view做上拉加载更多数据这个功能的时候 , 发现只要加载出新的数据,scroll-view就会自动回到最顶部 , 后来发现可能是setData的时候导致页面重置, 于是去网上搜索到了一种局部刷新的方法 ,发现也不行 ,这里附上代码片段 ,我这里只用setData更新了第一行数据 ,也导致scrollview滚到了最顶部 https://developers.weixin.qq.com/s/GqsZOgmg7jhp
2020-05-11 - 小程序没有 DOM 接口,原因竟然是……?
拥有丰富的 Web 前端开发经验的工程师小赵今天刚刚来到新的部门,开始从事他之前没有接触过的微信小程序开发。在上手的第一天,他就向同办公室的小程序老手老李请教了自己的问题。 小赵:翻了一圈文档,小程序好像并不提供 DOM 接口?我还以为可以像之前一样用我喜欢的前端框架来做开发呢。老李,你说小程序为什么不给我们提供 DOM 接口呀。 老李:要提供 DOM 接口也没那么容易。你知道小程序的双线程模型吗?(小赵漏出了疑惑的表情)小程序是基于 Web 技术的,这你应该知道,但小程序和普通的移动端网页也不一样。你做了很多前端项目了,应该知道在浏览器里,UI 渲染和 JavaScript 逻辑都是在一个线程中执行的? 小赵:这我知道,在同一个线程中,UI 渲染和 JavaScript 逻辑交替执行,JavaScript 也可以通过 DOM 接口来对渲染进行控制。 老李:小程序使用的是一种两个线程并行执行的模式,叫做双线程模型。像我画的这样,两个线程合力完成小程序的渲染:一个线程专门负责渲染工作,我们一般称之为渲染层;而另外有一个线程执行我们的逻辑代码,我们一般叫做逻辑层。这两个线程同时运行,并通过微信客户端来交换数据。在小程序运行的时候,逻辑层执行我们编写的逻辑,将数据通过 setData 发送到渲染层;而渲染层解析我们的 WXML 和 WXSS,并结合数据渲染出页面。一方面,每个页面对应一个 WebView 渲染层,对于用户来说更加有页面的感觉,体验更好,而且也可以避免单个 WebView 的负担太重;另一方面,将小程序代码运行在独立的线程中的模式有更好的安全表现,允许有像 open-data 这样的组件可以在确保用户隐私的前提下让我们展示用户数据。 [图片] 小赵:怪不得所有和页面有关的改动都只能通过 setData 来完成。但是用两个线程来渲染我们平时用单线程来渲染的 Web 页面,会不会有些「浪费」?而且每一个页面有一个对应的渲染层,那页面变多的时候,岂不是会有很大的开销? 老李: 并不浪费,因为界面的渲染和后台的逻辑处理可以在同一时间运行了,这使得小程序整体的响应速度更快了。而在小程序的运行过程中,逻辑层需要常驻,但渲染层是可以回收的。实际上,当页面栈的层数比较高的时候,栈底页面的渲染层是会被慢慢回收的。 小赵: 原来如此。这么说的话,实际的 DOM 树是存在于渲染层的,逻辑层并不存在,所以逻辑层才没有任何的 DOM 接口,我明白了。但是……既然可以实现像 setData 这样的接口,为什么不能直接把 DOM 接口也代理到逻辑层呢?我觉得小程序可以做一个封装,让我们在逻辑层调用 DOM 接口,在渲染层调用接口后再把结果返回给我们呀。 老李:从理论上来说确实是可以的。但是线程之间的通信是需要时间的呀。将调用发送到渲染层,再将 DOM 调用结果发送回来,这中间由于线程通信发生的时间损耗可能会比这个接口本身需要的时间要多得多。如果以此为基础使用基于 DOM 接口的前端框架,大量的 DOM 调用可能会非常缓慢,让这个设计失去意义。 在实际测试中,如果每次 DOM 调用都进行一次线程通信,耗时大约是同等节点规模直接在渲染层调用的百倍以上;如果忽略通信需要的时间,一个实现良好的基于 DOM 代理的框架可以近似地看成一个动态模板的框架,而动态模板和静态模板相比要慢至少 50% 小赵:原来如此,线程通信的时间确实是我没有考虑到的问题。那现在的小程序框架中难道不存在这个问题吗? 老李: 在现在的小程序框架中,这个问题也是存在的,这也是现在的框架基于静态模板渲染的原因。静态模板可以在运行前就做好打包,直接注入到渲染层,省去线程传输的时间。在运行时,逻辑层只和渲染层进行最少的、必要的数据交换:也就是渲染用的数据,或者说 data 。另一方面,静态模板让两个线程都在启动时就拥有模板相关的所有数据,所以框架也充分利用了这一点,进行了很多优化。 小赵: 怪不得我在文档里发现很多和 setData 有关的性能提示,都提醒尽量减少设置不必要的数据,现在总算是知道为什么了。但是具体到实际开发里的时候,还是总觉得很难每次只设置需要的数据啊,像对象里或者数组里的数据怎么办呢? 老李: 如果只改变了对象里或者数组里的一部分数据,可以通过类似 array[2].message , a.b.c.d 这样的 数据路径 来进行「精准设置」。另外,现在自定义组件也支持 纯数据字段 了,只要在自定义组件的选项中设置好名为 pureDataPattern 的正则表达式, data 中匹配这个正则的字段将成为纯数据字段,例如,你可以用 /^_/ 来指定所有 开头的数据字段为纯数据字段。所有纯数据字段仅仅被记录在逻辑层的 this.data 中,而不会被发送到渲染层,也不参与任何界面渲染过程,节省了传输的时间,这样有助于提升页面更新性能。 小赵:小程序还有这样的功能,受教了。不过说来说去,我还是想在小程序里用我顺手的框架来开发,毕竟这样事半功倍嘛。我在网上搜索了一下,发现现在有很多支持用 Web 框架做小程序开发的框架,但好像都是将模板编译成 WXML,最终由小程序来做渲染,但这样的方法好像兼容性也不是很好。我在想,我们能不能在逻辑层仿造一套 DOM 接口,然后在运行时将 DOM 调用适配成小程序调用? 老李: 你的这个脑洞有一些意思。在逻辑层仿造一套 DOM 接口,直接维护一棵 DOM 树,这当然没问题。但是没有代理 DOM 接口,逻辑层的 DOM 树没法反映到渲染层,因为渲染层具体会出现什么样的组件,是运行时才能知道的,这不就没法生成静态模板了? 小赵:静态模板确实是没法生成了,但我看到小程序的框架支持自定义组件,我是不是可以做一个通用的自定义组件,让它根据传入的参数不同,变成不同的小程序内置组件。而且自定义组件还支持在自己的模板中引用自己,那么我只需要一个这个通用组件,然后从逻辑层用代码去控制当前组件应该渲染成什么内置组件,再根据它是否有子节点去递归引用自己进行渲染就可以了。你看这样可行吗? [图片] 老李: 这样的做法确实可行,而且微信官方已经按照这个思路推出小程序和 Web 端同构的解决方案 Kbone 了。Kbone 的原理就像你刚才说的那样,它提供一个 Webpack 插件,将项目编译成小程序项目;同时提供两个 npm 包,分别提供 DOM 接口模拟和你说的那个通用的自定义组件作为运行时依赖。要不你赶紧试试? 小赵:还有这么好的事,那我终于可以用我喜欢的框架开发小程序了!这么好的框架,为什么不直接内置到小程序的基础库里呀? 老李: 因为这样的功能完全可以用现在已有的基础库功能实现出来呀。Kbone 现在是 npm 包的形式,使得它的功能、问题修复可以随着自己的版本来发布,不需要依赖于基础库的更新和覆盖率,不是挺好的吗? 小赵: 好是好,但我担心的是代码包大小限制的问题。除了我们已经写好的业务逻辑之外,现在还得加上 Kbone,会不会装不下呀? 老李: 原来你是担心这个呀,放心,Kbone 现在已经可以在 扩展库 里一键搞定啦。扩展库是帮我们解决依赖的全新功能,只要在配置项中指定 Kbone 扩展库,就相当于引入了 Kbone 相关的最新版本的 npm 包,这样就不占用小程序的代码包体积了,快试试吧! 小赵:哇,那可太爽了,马上就搞起! 最后 如果你对 Kbone 感兴趣或者有相关问题需要咨询, 欢迎加入 Kbone 技术交流 QQ 群:926335938
2020-01-14 - (3)强制更新
背景 此前有开发者反馈小程序发布新版本后,新版本覆盖率比较慢,因为小程序的更新机制是异步的,部分用户不会马上应用上新版本。 小程序启动会有两种情况,一种是「冷启动」,一种是「热启动」。 假如用户已经打开过某小程序,然后在一定时间内再次打开该小程序,此时无需重新启动,只需将后台态的小程序切换到前台,这个过程就是热启动;冷启动指的是用户首次打开或小程序被微信主动销毁后再次打开的情况,此时小程序需要重新加载启动。 小程序的异步更新发生在冷启动过程,当发现新版本后,会异步下载新版本的代码包,但不会马上应用上最新版本,需要等小程序下一次冷启动,才会应用上新版本。 解决思路为了解决这个问题,我们内部也经历了数个方案的讨论,这里简单介绍下: 1. 同步检查更新(放弃):可能是最直接的解决思路,但主要问题是会影响小程序的启动速度,当下小程序的更新迭代是非常频繁的,部分用户可能每次启动都命中更新,如果需要同步检查更新+同步下载新的版本,那将会影响这部分用户的启动体验。 2. 模块热替换(放弃):从技术上来说,这是最好的方案,小程序运行起来后,在打开新页面时,马上应用新版本里的页面,但这就会存在新旧逻辑、页面共存问题,对于开发者来说,反而更不好处理,特别是涉及到全局变量时,情况会更复杂,对于我们已有的框架来说,也是一个大挑战,不过这个也是我们之后努力的方向。 3. 定时 check 新版本(目前方案):6.6.3 及以上版本的客户端,会定时 check 最近使用过的小程序是否有发布新版本;如果有,下次打开的时候会同步更新新版本再打开。这可以保证在新版本发布 24 小时后,所有小程序都能使用最新版本。(这部分是微信客户端自身优化,开发者无需关心) 4. 异步更新 + 强制更新(目前方案):同步检查更新与模块热替换两者之间的折衷方案,即还是维持异步更新机制,在异步下载完小程序代码包后,提供重启小程序的能力,这样在遇到紧急问题时可以马上解决。 异步更新 + 强制更新方案介绍从基础库 1.9.90 开始,我们提供了 wx.getUpdateManager 接口,使用该接口,可以获知是否有新版本小程序、新版本是否下载好以及应用新版本的能力。 当小程序冷启动时,会自动向微信后台请求新版本信息,如果有新版本,会马上触发新版本的下载。开发者可以通过 wx.getUpdateManager,获知当前更新的状态。 wx.getUpdateManager 接口会返回一个 UpdateManager 实例,UpdateManager 包含了三个回调: 1. onCheckForUpdate:当小程序向后台请求完新版本信息,会通知这个版本告知检查结果 2. onUpdateReady:当新版本下载完成,会回调这个事件 3. onUpdateFailed: 当新版本下载失败,会回调这个事件 还有重启应用新版本的接口: 1. applyUpdate:当新版本下载完成(onUpdateReady),调用该方法会强制当前小程序应用上新版本并重启 具体示例: [代码]// wx.getUpdateManager 在 1.9.90 才可用,请注意兼容[代码] [代码]const updateManager = wx.getUpdateManager()[代码] [代码]updateManager.onCheckForUpdate(function[代码] [代码](res) {[代码] [代码] // 请求完新版本信息的回调[代码] [代码] console.log(res.hasUpdate)[代码] [代码]})[代码] [代码]updateManager.onUpdateReady(function[代码] [代码]() {[代码] [代码] wx.showModal({[代码] [代码] title: '更新提示',[代码] [代码] content: '新版本已经准备好,是否马上重启小程序?',[代码] [代码] success: function[代码] [代码](res) {[代码] [代码] if[代码] [代码](res.confirm) {[代码] [代码] // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启[代码] [代码] updateManager.applyUpdate()[代码] [代码] }[代码] [代码] }[代码] [代码] })[代码] [代码]})[代码] [代码]updateManager.onUpdateFailed(function[代码] [代码]() {[代码] [代码] // 新的版本下载失败[代码] [代码]})[代码] 更详细信息可以参考 UpdateManager 的详细文档 最佳实践从用户体验上来说,我们还是建议只在非常必要时才强制用户重启更新,例如出现线上紧急 BUG。通常情况下,可以选通过 wx.showModal 弹出选择框让用户选择是否重启更新(实现请参考示例代码)。 如何调试最新版本的微信开发者工具提供了强制更新的调试能力,通过编译模式 - 编辑编译模式 - 勾上「下次编译时模拟更新」即可在开发者工具上调试强制更新功能。 最新开发者工具下载链接 点我。
2022-08-08 - 微信小程序UI组件库合集
UI组件库合集,大家有遇到好的组件库,欢迎留言评论然后加入到文档里。 第一款: 官方WeUI组件库,地址 https://developers.weixin.qq.com/miniprogram/dev/extended/weui/ 预览码: [图片] 第二款: ColorUI:地址 https://github.com/weilanwl/ColorUI 预览码: [图片] 第三款: vantUI(又名:ZanUI):地址 https://youzan.github.io/vant-weapp/#/intro 预览码: [图片] 第四款: MinUI: 地址 https://meili.github.io/min/docs/minui/index.html 预览码: [图片] 第五款: iview-weapp:地址 https://weapp.iviewui.com/docs/guide/start 预览码: [图片] 第六款: WXRUI:暂无地址 预览码: [图片] 第七款: WuxUI:地址https://www.wuxui.com/#/introduce 预览码: [图片] 第八款: WussUI:地址 https://phonycode.github.io/wuss-weapp/quickstart.html 预览码: [图片] 第九款: TouchUI:地址 https://github.com/uileader/touchwx 预览码: [图片] 第十款: Hello UniApp: 地址 https://m3w.cn/uniapp 预览码: [图片] 第十一款: TaroUI:地址 https://taro-ui.jd.com/#/docs/introduction 预览码: [图片] 第十二款: Thor UI: 地址 https://thorui.cn/doc/ 预览码: [图片] 第十三款: GUI:https://github.com/Gensp/GUI 预览码: [图片] 第十四款: QyUI:暂无地址 预览码: [图片] 第十五款: WxaUI:暂无地址 预览码: [图片] 第十六款: kaiUI: github地址 https://github.com/Chaunjie/kai-ui 组件库文档:https://chaunjie.github.io/kui/dist/#/start 预览码: [图片] 第十七款: YsUI:暂无地址 预览码: [图片] 第十八款: BeeUI:git地址 http://ued.local.17173.com/gitlab/wxc/beeui.git 预览码: [图片] 第十九款: AntUI: 暂无地址 预览码: [图片] 第二十款: BleuUI:暂无地址 预览码: [图片] 第二十一款: uniydUI:暂无地址 预览码: [图片] 第二十二款: RovingUI:暂无地址 预览码: [图片] 第二十三款: DojayUI:暂无地址 预览码: [图片] 第二十四款: SkyUI:暂无地址 预览码: [图片] 第二十五款: YuUI:暂无地址 预览码: [图片] 第二十六款: wePyUI:暂无地址 预览码: [图片] 第二十七款: WXDUI:暂无地址 预览码: [图片] 第二十八款: XviewUI:暂无地址 预览码: [图片] 第二十九款: MinaUI:暂无地址 预览码: [图片] 第三十款: InyUI:暂无地址 预览码: [图片] 第三十一款: easyUI:地址 https://github.com/qq865738120/easyUI 预览码: [图片] 第三十二款 Kbone-UI: 地址 https://wechat-miniprogram.github.io/kboneui/ui/#/ 暂无预览码 第三十三款 VtuUi: 地址 https://github.com/jisida/VtuWeapp 预览码: [图片] 第三十四款 Lin-UI 地址:http://doc.mini.talelin.com/ 预览码: [图片] 第三十五款 GraceUI 地址: http://grace.hcoder.net/ 这个是收费的哦~ 预览码: [图片] 第三十六款 anna-remax-ui npm:https://www.npmjs.com/package/anna-remax-ui/v/1.0.12 anna-remax-ui 地址: https://annasearl.github.io/anna-remax-ui/components/general/button 预览码 [图片] 第三十七款 Olympus UI 地址:暂无 网易严选出品。 预览码 [图片] 第三十八款 AiYunXiaoUI 地址暂无 预览码 [图片] 第三十九款 visionUI npm:https://www.npmjs.com/package/vision-ui 预览码: [图片] 第四十款 AnimaUI(灵动UI) 地址:https://github.com/AnimaUI/wechat-miniprogram 预览码: [图片] 第四十一款 uView 地址:http://uviewui.com/components/quickstart.html 预览码: [图片] 第四十二款 firstUI 地址:https://www.firstui.cn/ 预览码: [图片]
2023-01-10 - 极致的scroll-view的下拉刷新扩展组件
不敢说是最好的,但是感觉也应该是性能和体验比较极致的下拉刷新扩展了,老规矩,代码片段放最后了~ 2020.2.22 修复了小程序基础库v2.10.2带来的不能滚动的问题,最新代码片段见scroll-view-extends 原理 其实原理很简单,和普通H5以及市面上有的下拉刷新没有特别大的区别,都是基于[代码]touch[代码]手势检测事件来实现下拉刷新的。[代码]touchstart[代码]的时候记录当前触摸点,[代码]touchmove[代码]的时候开始计算移动方向和移动距离, [代码]touchend[代码]的时候计算是否要进行下拉刷新操作。如图所示: [图片] 实现方法 调研了一些实现方法,目前大部分都是通过js计算,然后setData来改变元素的[代码]transform[代码]值实现下拉刷新。考虑到性能问题,此处使用了[代码]wxs[代码]的响应式能力来实现整个计算逻辑,不用通过逻辑层和视图层通信,直接在视图层进行渲染。具体文档请参考wxs响应事件。 这里在[代码]list[代码]组件(由[代码]scroll-view[代码]组成)下抽出了一个[代码]scroll.wxs[代码]作为响应事件的事件处理函数集合,源码基本上就在[代码]scroll.wxs[代码]和[代码]list[代码]组件。 [代码]scroll.wxs[代码]定义了如下变量和函数: [代码]var moveStartPosition = 0 //开始位置 var moveDistance = 0 //移动距离 var moveRefreshDistance = 60 //达到刷新的阈值 var moveMaxDistance = 100 //最大可滑动距离 var isRefreshMaxDown = false //是否达到了最大距离, 用来判断是否要震动提示 var loading = false //是否正在loading ... ... module.exports = { touchStart: touchStart, //手指开始触摸事件 touchMove: touchMove, //手指移动事件 touchEnd: touchEnd, //手指离开屏幕事件 loadingTypeChange: loadingTypeChange, //请求状态变化监听,监听刷新请求开始和请求完成 triggerRefresh: triggerRefresh //主动触发刷新操作,比如点击页面上一个按钮,重新刷新list,这就需要用到这个方法 } [代码] [代码]touchStart[代码]和[代码]touchMove[代码]就不用说了,代码注释都很明白,普通的监听移动和处理逻辑。 [代码]touchEnd[代码]主要是判断移动距离是否达到了阈值,然后根据结果,调用监听实例的[代码]callMethod[代码]方法触发[代码]refreshStart[代码]或者[代码]refreshCancel[代码]方法,这两个方法都是写到[代码]list[代码]组件里面的,用来触发刷新方法或者取消刷新。 [代码]loadingTypeChange[代码]方法主要是监听刷新是否完成,以此来触发动画效果。 [代码]triggerRefresh[代码]通过监听主动触发的变量来处理。如果需要主动触发刷新,则调用[代码]list[代码]组件内部的[代码]forceRefresh[代码]方法,具体使用示例在[代码]index/index/js[代码]的[代码]onLoad[代码]函数有: [代码]this.selectComponent('.list').forceRefresh()[代码] [代码]scroll.wxs[代码]里面还有一个未导出的方法,叫[代码]drawTransitionY[代码],这个方法主要是因为[代码]ios12[代码]对于[代码]transition[代码]动画效果支持的不好,所以自己写了个Y轴方向的动画([代码]linear[代码]线性的),大佬们可以自己往上添加各种[代码]ease-in-out[代码]效果。 里面具体的实现可以查看代码注释哦~ 使用 好了,前面讲了实现的原理和方法,那么在代码里面,应该怎么直接使用呢?如下代码所示: [代码]<!-- 使用示例 --> <list class="list" refresh-loading="{{refreshLoading}}" loading="{{loading}}" bindrefresh="initList" bindloadmore="loadmore"> <!-- your code --> </list> [代码] [代码]refresh-loading[代码]属性用来通过外部loading态来控制刷新动画的开始结束,因为每当变化[代码]refresh-loading[代码]的值时,会将变化同步到组件内的[代码]showRefresh[代码]属性,[代码]wxs[代码]通过监听[代码]showRefresh[代码]来处理动画逻辑。 [代码]loading[代码]属性是上拉加载更多的时候触发的loading态展示,跟刷新无关 [代码]bindrefresh[代码]是刷新触发时绑定的函数,下拉刷新动画成功开始后触发这个函数 [代码]bindloadmore[代码]透传[代码]scroll-view[代码]的加载更多方法 当然,源码里面也包含了一个[代码]list-item[代码]组件,这个跟本文没太大关系,是用来做瀑布流长列表内容太多时的内存不足问题解决方案的,具体请看解决小程序渲染复杂长列表,内存不足问题 干货 最后,上代码片段, 小程序代码片段 github地址
2020-02-22 - 优秀在线答题小程序汇总分享
平时做在线答题小程序,参考过很多有优秀的线上案例,现将曾经参考的一些小程序分享出来,如果有做在线答题的同学可以看看,或许会有一些新的产品idea 以下小程序排名不分先后 ①、班级小管家 [图片] ②、每日交作业 [图片] ③、小打卡 [图片] ④、作业登记簿 [图片] ⑤、班小二 [图片] 以上五个算是头部的几个,下面再总结几个比较平民化的 ⑥、随堂小测 [图片] ⑦、答题助理 [图片] ⑧、在线考试小助手 [图片] ⑨、驾考宝典 [图片] ⑩、万题库 [图片] 11、360考试宝典 [图片] 12、出题答题测试助手 [图片] 13)考研政治题库v抢先版 [图片] 14)小小答题丨在线考试问卷调查 [图片] 先总结这么多,后面如果有机会我会捡几个,把小程序具体描述下。 大家有没有想补充的,可以评论区留言,大家如果有什么好的也可以在评论去推荐
2020-10-23 - 小程序模板消息API 2020年1月10日下线,那么统一服务消息接口有变动吗?
能用统一服务消息接口 继续发小程序消息吗? 求告知!
2019-12-11 - 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 - 使用 MobX 来管理小程序的跨页面数据
在小程序中,常常有些数据需要在几个页面或组件中共享。对于这样的数据,在 web 开发中,有些朋友使用过 redux 、 vuex 之类的 状态管理 框架。在小程序开发中,也有不少朋友喜欢用 MobX ,说明这类框架在实际开发中非常实用。 小程序团队近期也开源了 MobX 的辅助模块,使用 MobX 也更加方便。那么,在这篇文章中就来介绍一下 MobX 在小程序中的一个简单用例! 在小程序中引入 MobX 在小程序项目中,可以通过 npm 的方式引入 MobX 。如果你还没有在小程序中使用过 npm ,那先在小程序目录中执行命令: [代码]npm init -y [代码] 引入 MobX : [代码]npm install --save mobx-miniprogram mobx-miniprogram-bindings [代码] (这里用到了 mobx-miniprogram-bindings 模块,模块说明在这里: https://developers.weixin.qq.com/miniprogram/dev/extended/functional/mobx.html 。) npm 命令执行完后,记得在开发者工具的项目中点一下菜单栏中的 [代码]工具[代码] - [代码]构建 npm[代码] 。 MobX 有什么用呢? 试想这样一个场景:制作一个天气预报资讯小程序,首页是列表,点击列表中的项目可以进入到详情页。 首页如下: [图片] 详情页如下: [图片] 每次进入首页时,需要使用 [代码]wx.request[代码] 获取天气列表数据,之后将数据使用 setData 应用到界面上。进入详情页之后,再次获取指定日期的天气详情数据,展示在详情页中。 这样做的坏处是,进入了详情页之后需要再次通过网络获取一次数据,等待网络返回后才能将数据展示出来。 事实上,可以在首页获取天气列表数据时,就一并将所有的天气详情数据一同获取回来,存放在一个 数据仓库 中,需要的时候从仓库中取出来就可以了。这样,只需要进入首页时获取一次网络数据就可以了。 MobX 可以帮助我们很方便地建立数据仓库。接下来就讲解一下具体怎么建立和使用 MobX 数据仓库。 建立数据仓库 数据仓库通常专门写在一个独立的 js 文件中。 [代码]import { observable, action } from 'mobx-miniprogram' // 数据仓库 export const store = observable({ list: [], // 天气数据(包含列表和详情) // 设置天气列表,从网络上获取到数据之后调用 setList: action(function (list) { this.list = list }), }) [代码] 在上面数据仓库中,包含有数据 [代码]list[代码] (即天气数据),还包括了一个名为 [代码]setList[代码] 的 action ,用于更改数据仓库中的数据。 在首页中使用数据仓库 如果需要在页面中使用数据仓库里的数据,需要调用 [代码]createStoreBindings[代码] 来将仓库中的数据绑定到页面数据中,然后就可以在页面中直接使用仓库数据了。 [代码]import { createStoreBindings } from 'mobx-miniprogram-bindings' import { store } from './store' Page({ onLoad() { // 绑定 MobX store this.storeBindings = createStoreBindings(this, { store, // 需要绑定的数据仓库 fields: ['list'], // 将 this.data.list 绑定为仓库中的 list ,即天气数据 actions: ['setList'], // 将 this.setList 绑定为仓库中的 setList action }) // 从服务器端读取数据 wx.showLoading() wx.request({ // 请求网络数据 // ... success: (data) => { wx.hideLoading() // 调用 setList action ,将数据写入 store this.setList(data) } }) }, onUnload() { // 解绑 this.storeBindings.destroyStoreBindings() }, }) [代码] 这样,可以在 wxml 中直接使用 list : [代码]<view class="item" wx:for="{{list}}" wx:key="date" data-index="{{index}}"> <!-- 这里可以使用 list 中的数据了! --> <view class="title">{{item.date}} {{item.summary}}</view> <view class="abstract">{{item.temperature}}</view> </view> [代码] 在详情页中使用数据仓库 在详情页中,同样可以使用 [代码]createStoreBindings[代码] 来将仓库中的数据绑定到页面数据中: [代码]import { createStoreBindings } from 'mobx-miniprogram-bindings' import { store } from './store' Page({ onLoad(args) { // 绑定 MobX store this.storeBindings = createStoreBindings(this, { store, // 需要绑定的数据仓库 fields: ['list'], // 将 this.data.list 绑定为仓库中的 list ,即天气数据 }) // 页面参数 `index` 表示要展示哪一条天气详情数据,将它用 setData 设置到界面上 this.setData({ index: args.index }) }, onUnload() { // 解绑 this.storeBindings.destroyStoreBindings() }, }) [代码] 这样,这个页面 wxml 中也可以直接使用 list : [代码]<view class="title">{{list[index].date}}</view> <view class="content">温度 {{list[index].temperature}}</view> <view class="content">天气 {{list[index].weather}}</view> <view class="content">空气质量 {{list[index].airQuality}}</view> <view class="content">{{list[index].details}}</view> [代码] 完整示例 完整例子可以在这个代码片段中体验: https://developers.weixin.qq.com/s/YhfvpxmN7HcV 这个就是 MobX 在小程序中最基础的玩法了。相关的 npm 模块文档可参考 mobx-miniprogram-bindings 和 mobx-miniprogram 。 MobX 在实际使用时还有很多好的实践经验,感兴趣的话,可以阅读一些其他相关的文章。
2019-11-01 - 用 HTM 实现小程序 SVG
写在前面 今天你可以在小程序中使用 Cax 引擎高性能渲染 SVG! SVG 是可缩放矢量图形(Scalable Vector Graphics),基于可扩展标记语言,用于描述二维矢量图形的一种图形格式。它由万维网联盟制定,是一个开放标准。SVG 的优势有很多: SVG 使用 XML 格式定义图形,可通过文本编辑器来创建和修改 SVG 图像可被搜索、索引、脚本化或压缩 SVG 是可伸缩的,且放大图片质量不下降 SVG 图像可在任何的分辨率下被高质量地打印 SVG 可被非常多的工具读取和修改(比如记事本) SVG 与 JPEG 和 GIF 图像比起来,尺寸更小,且可压缩性、可编程星更强 SVG 完全支持 DOM 编程,具有交互性和动态性 而支持上面这些优秀特性的前提是 - 需要支持 SVG 标签。比如在小程序中直接写: [代码]<svg width="300" height="150"> <rect bindtap="tapHandler" height="100" width="100" style="stroke:#ff0000; fill: #0000ff"> </rect> </svg> [代码] 上面定义了 SVG 的结构、样式和点击行为。但是小程序目前不支持 SVG 标签,仅仅支持加载 SVG 之后 作为 background-image 进行展示,如 [代码]background-image: url("data:image/svg+xml.......)[代码],或者 base64 后作为 background-image 的 url。 直接看在小程序种使用案例: [代码]import { html, renderSVG } from '../../cax/cax' Page({ onLoad: function () { renderSVG(html` <svg width="300" height="220"> <rect bindtap="tapHandler" height="110" width="110" style="stroke:#ff0000; fill: #ccccff" transform="translate(100 50) rotate(45 50 50)"> </rect> </svg>`, 'svg-a', this) }, tapHandler: function () { console.log('你点击了 rect') } }) [代码] 其中的 svg-a 对应着 wxml 里 cax-element 的 id: [代码]<view class="container"> <cax-element id="svg-c"></cax-element> </view> [代码] 声明组件依赖 [代码]{ "usingComponents": { "cax-element":"../../cax/index" } } [代码] 小程序中显示效果: [图片] 可以使用 [代码]width[代码],[代码]height[代码],[代码]bounds-x[代码] 和 [代码]bounds-y[代码] 设置绑定事件的范围,比如: [代码]<path width="100" height="100" bounds-x="50" bounds-y="50" /> [代码] 需要注意的是,元素的事件触发的包围盒受自身或者父节点的 transform 影响,所以不是绝对坐标的 rect 触发区域。 再来一个复杂的例子,用 SVG 绘制 Omi 的 logo: [代码]renderSVG(html` <svg width="300" height="220"> <g transform="translate(50,10) scale(0.2 0.2)"> <circle fill="#07C160" cx="512" cy="512" r="512"/> <polygon fill="white" points="159.97,807.8 338.71,532.42 509.9,829.62 519.41,829.62 678.85,536.47 864.03,807.8 739.83,194.38 729.2,194.38 517.73,581.23 293.54,194.38 283.33,194.38 "/> <circle fill="white" cx="839.36" cy="242.47" r="50"/> </g> </svg>`, 'svg-a', this) [代码] 小程序种显示效果: [图片] 在 omip 和 mps 当中使用 cax 渲染 svg,你可以不用使用 htm。比如在 omip 中实现上面两个例子: [代码] renderSVG( <svg width="300" height="220"> <rect bindtap="tapHandler" height="110" width="110" style="stroke:#ff0000; fill: #ccccff" transform="translate(100 50) rotate(45 50 50)"> </rect> </svg>, 'svg-a', this.$scope) [代码] [代码]renderSVG( <svg width="300" height="220"> <g transform="translate(50,10) scale(0.2 0.2)"> <circle fill="#07C160" cx="512" cy="512" r="512"/> <polygon fill="white" points="159.97,807.8 338.71,532.42 509.9,829.62 519.41,829.62 678.85,536.47 864.03,807.8 739.83,194.38 729.2,194.38 517.73,581.23 293.54,194.38 283.33,194.38 "/> <circle fill="white" cx="839.36" cy="242.47" r="50"/> </g> </svg>, 'svg-a', this.$scope) [代码] 需要注意的是在 omip 中传递的最后一个参数不是 [代码]this[代码],而是 [代码]this.$scope[代码]。 在 mps 中,更加彻底,你可以单独创建 svg 文件,通过 import 导入。 [代码]//注意这里不能写 test.svg,因为 mps 会把 test.svg 编译成 test.js import testSVG from '../../svg/test' import { renderSVG } from '../../cax/cax' Page({ tapHandler: function(){ this.pause = !this.pause }, onLoad: function () { renderSVG(testSVG, 'svg-a', this) } }) [代码] 比如 test.svg : [代码]<svg width="300" height="300"> <rect bindtap="tapHandler" x="0" y="0" height="110" width="110" style="stroke:#ff0000; fill: #0000ff" /> </svg> [代码] 会被 mps 编译成: [代码]const h = (type, props, ...children) => ({ type, props, children }); export default h( "svg", { width: "300", height: "300" }, h("rect", { bindtap: "tapHandler", x: "0", y: "0", height: "110", width: "110", style: "stroke:#ff0000; fill: #0000ff" }) ); [代码] 所以总结一下: 你可以在 mps 中直接使用 import 的 SVG 文件的方式使用 SVG 你可以直接在 omip 中使用 JSX 的使用 SVG 你可以直接在原生小程序当中使用 htm 的方式使用 SVG 这就完了?远没有,看 cax 在小程序中的这个例子: [图片] 详细代码: [代码]renderSVG(html` <svg width="300" height="200"> <path d="M 256,213 C 245,181 206,187 234,262 147,181 169,71.2 233,18 220,56 235,81 283,88 285,78.7 286,69.3 288,60 289,61.3 290,62.7 291,64 291,64 297,63 300,63 303,63 309,64 309,64 310,62.7 311,61.3 312,60 314,69.3 315,78.7 317,88 365,82 380,56 367,18 431,71 453,181 366,262 394,187 356,181 344,213 328,185 309,184 300,284 291,184 272,185 256,213 Z" style="stroke:#ff0000; fill: black"> <animate dur="32s" repeatCount="indefinite" attributeName="d" values="......太长,这里省略 paths........" /> </path> </svg>`, 'svg-c', this) [代码] 再试试著名的 SVG 老虎: [图片] path 太长,就不贴代码了,可以点击这里查看 pasiton 标签 [代码]import { html, renderSVG } from '../../cax/cax' Page({ onLoad: function () { const svg = renderSVG(html` <svg width="200" height="200"> <pasition duration="200" bindtap=${this.changePath} width="100" height="100" from="M28.228,23.986L47.092,5.122c1.172-1.171,1.172-3.071,0-4.242c-1.172-1.172-3.07-1.172-4.242,0L23.986,19.744L5.121,0.88 c-1.172-1.172-3.07-1.172-4.242,0c-1.172,1.171-1.172,3.071,0,4.242l18.865,18.864L0.879,42.85c-1.172,1.171-1.172,3.071,0,4.242 C1.465,47.677,2.233,47.97,3,47.97s1.535-0.293,2.121-0.879l18.865-18.864L42.85,47.091c0.586,0.586,1.354,0.879,2.121,0.879 s1.535-0.293,2.121-0.879c1.172-1.171,1.172-3.071,0-4.242L28.228,23.986z" to="M49.1 23.5H2.1C0.9 23.5 0 24.5 0 25.6s0.9 2.1 2.1 2.1h47c1.1 0 2.1-0.9 2.1-2.1C51.2 24.5 50.3 23.5 49.1 23.5zM49.1 7.8H2.1C0.9 7.8 0 8.8 0 9.9c0 1.1 0.9 2.1 2.1 2.1h47c1.1 0 2.1-0.9 2.1-2.1C51.2 8.8 50.3 7.8 49.1 7.8zM49.1 39.2H2.1C0.9 39.2 0 40.1 0 41.3s0.9 2.1 2.1 2.1h47c1.1 0 2.1-0.9 2.1-2.1S50.3 39.2 49.1 39.2z" from-stroke="red" to-stroke="green" from-fill="blue" to-fill="red" stroke-width="2" /> </svg>`, 'svg-c', this) this.pasitionElement = svg.children[0] }, changePath: function () { this.pasitionElement.toggle() } }) [代码] pasiton 提供了两个 path 和 颜色 相互切换的能力,最常见的场景比如 menu 按钮和 close 按钮点击后 path 的变形。 举个例子,看颜色和 path 同时变化: [图片] 线性运动 这里举一个在 mps 中使用 SVG 的案例: [代码]import { renderSVG, To } from '../../cax/cax' Page({ tapHandler: function(){ this.pause = !this.pause }, onLoad: function () { const svg = renderSVG(html` <svg width="300" height="300"> <rect bindtap="tapHandler" x="0" y="0" height="110" width="110" style="stroke:#ff0000; fill: #0000ff" /> </svg>` , 'svg-a', this) const rect = svg.children[0] rect.originX = rect.width/2 rect.originY = rect.height/2 rect.x = svg.stage.width/2 rect.y = svg.stage.height/2 this.pause = false this.interval = setInterval(()=>{ if(!this.pause){ rect.rotation++ svg.stage.update() } },15) }) [代码] 效果如下: [图片] 组合运动 [代码]import { renderSVG, To } from '../../cax/cax' Page({ onLoad: function () { const svg = renderSVG(html` <svg width="300" height="300"> <rect bindtap="tapHandler" x="0" y="0" height="110" width="110" style="stroke:#ff0000; fill: #0000ff" /> </svg>` ,'svg-a', this) const rect = svg.children[0] rect.originX = rect.width/2 rect.originY = rect.height rect.x = svg.stage.width/2 rect.y = svg.stage.height/2 var sineInOut = To.easing.sinusoidalInOut To.get(rect) .to().scaleY(0.8, 450, sineInOut).skewX(20, 900, sineInOut) .wait(900) .cycle().start() To.get(rect) .wait(450) .to().scaleY(1, 450, sineInOut) .wait(900) .cycle().start() To.get(rect) .wait(900) .to().scaleY(0.8, 450, sineInOut).skewX(-20, 900, sineInOut) .cycle() .start() To.get(rect) .wait(1350) .to().scaleY(1, 450, sineInOut) .cycle() .start() setInterval(() => { rect.stage.update() }, 16) } }) [代码] 效果如下: [图片] 其他 vscode 安装 lit-html 插件使 htm 的 html[代码]内容[代码] 高亮 还希望小程序 SVG 提供什么功能可以开 issues告诉我们,评估后通过,我们去实现! Cax Github 参考文档
01-04 - wx.getWifiList接口需获取用户位置信息授权后使用
各位开发者: 大家好。 当前我们发现在android平台下,部分小程序会通过`wx.getWifiList`接口,嗅探周边Wi-Fi热点来推断用户所在的位置信息。为了更好地保护用户隐私,现策略调整为:android平台下,所有小程序在调用`wx.getWifiList`接口前,需获取用户位置信息授权(scope.userLocation)。详见《小程序开发文档》 温馨提示,若想要获取用户位置信息授权,开发者需要在代码内填写获取用户地理位置的用途说明,否则将无法顺利获取授权。详见《获取用户位置信息时需填写用途说明》 2019年5月17日起新提交发布的版本将会受到此调整的影响。 需要各位开发者注意,2019年5月17日起新提交发布的版本若未获取用户位置权限,则在android平台上将无法正常调用wx.getWifiList接口。该调整策略在微信android客户端 7.0.4 版本生效。
2019-04-28 - 目前为止最全的微信小程序项目实例
wx-gesture-lock 微信小程序的手势密码 WXCustomSwitch 微信小程序自定义 Switch 组件模板 WeixinAppBdNovel 微信小程序demo:百度小说搜索 shitoujiandaobu 小程序:石头剪刀布(附代码说明) audiodemo 微信小程序开发之视频播放器 Video 弹幕 弹幕颜色自定义 star 微信小程序开发之五星评分 switchCity 微信小程序开发之城市选择器 城市切换 huadong_del 微信小程序滑动删除效果 jianhang_menu 微信小程序开发之圆形菜单 仿建行圆形菜单 xiaoxiaoxiao_lazyload 实现微信小程序图片懒加载特效 kangaiduowei 微信小程序:康爱多微商城:学习界面设计 tianmao_dazhuanpan 小程序实现大转盘 仿天猫抽奖 跑马灯效果(有图有源码) weapp-meirong 微信小程序学习用demo推荐:美容商城;列表,预约 baisi 微信小程序仿百思不得姐 weapp-one 仿 「ONE · 一个」 的微信小程序 netmusic-app 仿网易云音乐APP的微信小程序 a_takeaway 微信小程序的外卖demo sideslip 微信小程序『侧边栏滑动』特效 wx_plo 微信小程序之仿微信漂流瓶 kwonWhere 微信小程序-知亦行 audiodemo 微信小程序开发之视频播放 弹幕 弹幕颜色自定义 wxChart 微信小程序图标插件 guoku 微信小程序-果库 snake 微信小程序-贪吃蛇小程序 douban_movie 微信小程序-仿豆瓣电影 RecordDemo 麦克风动画 shishanggou 实现了包括常用组件,ajax获取数据,模板使用,路由等的使用,下拉刷新数据;
2019-02-12 - 小程序自定义事件
事件的作用: 事件可用于不同页面间的数据交互,例如A页面监听了名为“test”的事件,当事件发生时改变页面标题。 B页面,比如点击某个按钮触发并广播了“test”事件。此时A页面的标题将改变。 实现: -- 在app.js 中定义事件 eventArr: [], // 事件数组 ,用于存储事件 addEventListener: function (eventName, cb) { // 注册自定义事件 var len = this.eventArr.length if (len < 1) { this.eventArr.push({ eventName: eventName, cbArray: [{ callback: cb }] }) } else { for (var i = 0; i < len; i++) { if (this.eventArr[i].eventName == eventName) { this.eventArr[i].cbArray.push({ callback: cb }) return } } this.eventArr.push({ eventName: eventName, cbArray: [{ callback: cb }] }) } }, sendEvent: function (eventName, paramObj) { // 触发事件 var len = this.eventArr.length for (var i = 0; i < len; i++) { if (this.eventArr[i].eventName == eventName) { var pa = paramObj || {} for (var j = 0; j < this.eventArr[i].cbArray.length; j++) { this.eventArr[i].cbArray[j].callback(pa) } break } } }, removeEvent: function (eventName) { // 移除事件 var len = this.eventArr.length for (var i = 0; i < len; i++) { if (this.eventArr[i].eventName == eventName) { this.eventArr.splice(i, 1) break } } } -- 在其他任意页面监听事件(建议在onLoad中监听) app.addEventListener('test',function(res){ // 收到事件后的处理逻辑,res为sendEvent的第二个参数 }.bind(this)) -- 触发事件 app.sendEvent('test',{title:'xiapu'})
2019-02-13 - node+express+MongoDB实现小商城服务端
### 说明 1、本人也是第一次使用node做一个完整的项目如果有觉得不合理的地方可以在下方留言或者Issues作者会尽快修复 2、本项目适合初学者或者准备自学node的伙伴,本人也是零基础开始写的node 3、如果对你有帮助的话麻烦给作者一个"star"给与支持
2018-09-27 - node+express+MongoDB实现小商城服务端
## GitHub地址 前端地址:https://github.com/FZliweiliang/wechat-app-mall 服务端地址:https://github.com/FZliweiliang/wechat-app-mall-server ## 运行环境 ``` CentOS 7.3 node 8.11.0 npm 5.6.0 MongoDB 3.2.7 ``` ## 主要功能 购物车 绑定手机 用户登录 添加商品 推荐商品 商品列表 优惠券 地址管理 上传图片 ... 接口列表: ### 管理 | Name | Method | Default | Description | | ----------- |:--------------| ---------|--------------| | /v1/admin/delUser | get | auto | 删除用户 | | /v1/admin/delItem | get | auto | 删除商品 | | /v1/admin/addItem | post | auto | 添加商品 | | /v1/admin/addClass | post | auto | 添加分类 | | /v1/admin/delClass | get | auto | 删除分类 | | /v1/admin/addClass | post | auto | 添加分类 | | /v1/admin/addCoupon | post | auto | 添加优惠券 | | /v1/admin/couponList | get | auto | 所有优惠券 | | /v1/admin/uploadBanner | post | auto | 上传banner | ### 首页 | Name | Method | Default | Description | | ----------- |:--------------| ---------|--------------| | /v1/home/bannerList | get | auto | 获取banner | | /v1/home/getHotList | get | auto | 获取推荐列表 | | /v1/home/getList | get | auto | 获取列表 | | /v1/home/getItem | get | auto | 获取详情 | ### 订单 | Name | Method | Default | Description | | ----------- |:--------------| ---------|--------------| | /v1/order/set | post | auto | 创建订单 | | /v1/order/get | post | auto | 获取订单详情 | | /v1/order/list | get | auto | 订单列表 | | /v1/order/update | post | auto | 更新订单 | ### 微信 | Name | Method | Default | Description | | ----------- |:--------------| ---------|--------------| | /v1/wx/getUser | get | auto | 获取微信用户信息 | ### 用户 | Name | Method | Default | Description | | ----------- |:--------------| ---------|--------------| | /v1/user/bindMobile | post | auto | 绑定手机号 | | /v1/user/addCity | post | auto | 添加地址 | | /v1/user/editCity | post | auto | 更新地址 | | /v1/user/defaultCity | post | auto | 设置默认地址 | | /v1/user/cityList | get | auto | 地址列表 | | /v1/user/getCoupon | post | auto | 领取优惠券 | | /v1/user/couponList | get | auto | 获取拥有的优惠 | ### 通用 | Name | Method | Default | Description | | ----------- |:--------------| ---------|--------------| | /v1/public/getClassList | get | auto | 获取分类列表 | ### 购物车 | Name | Method | Default | Description | | ----------- |:--------------| ---------|--------------| | /v1/order/addCart | post | auto | 加入购物车 | | /v1/order/cartList | get | auto | 购物车列表 | | /v1/order/delIetm | post | auto | 删除商品 | | /v1/order/editCart | post | auto | 编辑购物车 | ### 启动方法 ``` node app.js ``` ### 说明 1、本人也是第一次使用node做一个完整的项目如果有觉得不合理的地方可以在下方留言或者Issues作者会尽快修复 2、本项目适合初学者或者准备自学node的伙伴,本人也是零基础开始写的node 3、如果对你有帮助的话麻烦给作者一个"star"给与支持
2018-09-27 - 禁止swiper滑动
社区已经有人解答这个问题了。感谢@赵子龙 这里写个经验分享记录一下。 [图片]
2018-11-02 - 展示效果页如何修改组件中的参数?
wechatide://minicode/W2hvznmw65Yj 代码地址 [图片] [图片] [图片] 其他地方没改,请参照官方代码,想知道 在index.js 如何实现需求? 收到了组件给我的传参,我想改变组件中的idx=1,变成idx=0; 这里应该怎么做?
2018-05-08