- 微信小程序直播资料整理
可以通过此脑图大概了解小程序直播插件发展过程:http://naotu.baidu.com/file/597625fbd8659aa87e54143df1ed7f39?token=5bad276062c05585 [图片] 小程序直播组件是微信给开发者提供的实时视频直播工具,可以帮助开发者快速通过小程序向用户提供优质的直播内容,在小程序内流畅完成购买交易闭环,提升转化率; 小程序直播组件包括观众端、主播端及后台管理端,其中观众端提供拉流、实时互动、订阅提醒、商品购买等能力,主播端提供开播、推流、音视频效果优化等能力,后台管理端则负责直播房间、商品货架以及营销活动配置等。 【开通条件】 https://mp.weixin.qq.com/s/oqNdNEnRblEzwR_61d3vHA 满足以下条件的电商平台、自营商家,即有机会被邀请到小程序直播公测中来: (同时满足以下1、2、3条件,加上4、5、6条件的其中之一即可。) 1. 满足小程序18个开放类目(包括:电商平台、商家自营-百货、食品、初级食用农产品、酒/盐、图书报刊/音像/影视/游戏/动漫、汽车/其他交通工具的配件、服装/鞋/箱包、玩具/母婴用品(不含食品)、家电/数码/手机、美妆/洗护、珠宝/饰品/眼镜/钟表、运动/户外/乐器、鲜花/园艺/工艺品、家居/家饰/家纺、汽车内饰/外饰、办公/文具、机械/电子器件) 2. 主体下小程序近半年没有严重违规 3. 小程序近90天存在支付行为 4. 主体下公众号累计粉丝数大于100 5. 主体下小程序连续7日日活跃用户数大于100 6. 主体在微信生态内近一年广告投放实际消耗金额大于1w 【第三方平台(小程序服务商)】 https://developers.weixin.qq.com/community/develop/doc/000a06014745f00d95f9e03d951401?from=groupmessage&isappinstalled=0 服务商接入指引 具体接入指引请参考《【小程序直播】服务商接入指引》,以下为服务商接入步骤。 1. 权限申请 1) 在问卷《服务商“小程序直播”接入申请》填写相关信息并等待权限开通,发送申请后7个工作日内,可登陆微信开放平台查看第三方平台权限集并勾选 “小程序直播” 能力; 2) 开通后,即可登陆 “微信开放平台” (open.weixin.qq.com)勾选 “小程序直播” 第三方权限集并全网发布; 2.功能开发 小程序直播需要实现【直播组件】与【后台API】两个部分,其中组件部分需要在小程序中进行配置开发。 具体开发文档,请参考《小程序直播组件接入指引》。 【看点直播与小程序直播区别】 看点直播是不是腾讯官方?有什么区别? 小程序直播是腾讯WXG(也就是微信团队)公测推出的能力,为商家提供的经营工具,可在商家自有的小程序中实现直播互动与商品销售闭环。优点是可以直接内嵌到商家小程序,和公众号打通;直播吸引的流量都沉淀在商家自有小程序,不用跳转其他渠道,有利于形成私域流量,转化率高。 腾讯看点直播是腾讯PCG(平台与内容事业群,做QQ、腾讯视频的事业群)推出的直播产品,有App、小程序端、小程序端是基于微信小程序的开发能力开发的,商家必须通服务商才能接入,无法直接在商家自有的小程序内闭环交易。(需要直播服务商提交资料开通,服务费用599半年。) 【2020-05-22更新】 近期已上线新功能:评论管理,支持对单个用户进行禁言,与敏感词设置。 未全面开放新功能:直播间可以直接发放微信代金券,目前内测中,敬请期待! [图片] 【2020-06-02更新】 小程序后台直播功能接口支持进一步提升,可以通过接口添加直播间与商品管理,在没有涉及抽奖情况下及推送商品功能情况下,已经可以完整脱离小程序后台完成直播相关设置,对于一些服务商来说是一个不错的消息,按这个进度,下一步官方应该优先支持推送商品及抽奖活动设置配置接口的开放。 创建直播间文档:https://developers.weixin.qq.com/miniprogram/dev/framework/liveplayer/live-player-plugin.html 拉到三/9 商品接口文档:https://developers.weixin.qq.com/miniprogram/dev/framework/liveplayer/commodity-api.html [图片] 【2020-06-09更新】 直播间优惠券功能已经全面开放,很多玩法将会产生。 直播间领取的券可直接插入微信卡包(代表着可以提醒一次)。 如何配置:http://note.youdao.com/noteshare?id=afbff99580c4540cc011e3ed7ab5fbcf&sub=CDE480AAEC07437CB58902E0FF42C329 [图片][图片]
2020-06-09 - 小程序websocket心跳库——websocket-heartbeat-miniprogram
前言在16年的时候因为项目接触到websocket,而后对心跳重连做了一次总结,写了篇博客,而后18年对之前github上的demo代码进行了再次开发和开源,最终封装成库。如下: 博客:www.cnblogs.com/1wen/p/5808…github: github.com/zimv/websoc…npm: www.npmjs.com/package/web… 在2020年也就是今年初,同事建议说可以考虑兼容一下小程序,心想也挺好的。便有了今天的 websocket-heartbeat-miniprogram,这次基于以前的代码新建了一个项目,只做小程序的版本,因为涉及到各种小程序以及相关框架的兼容,觉得还是单独出一个包,更专注一点。 介绍websocket-heartbeat-miniprogram基于小程序的websocket相关API进行封装,主要目的是保障客户端websocket与服务端连接状态。该程序有心跳检测及自动重连机制,当网络断开或者后端服务问题造成客户端websocket断开,程序会自动尝试重新连接直到再次连接成功。兼容市面上大部分小程序微信,百度,支付宝等,只要都是统一的小程序weboscket-API规范。也支持小程序框架比如Taro等。无论如何,业务是需要一层心跳机制的,否则一些情况下会丢失连接导致功能无法使用。 用法 安装npm install --save websocket-heartbeat-miniprogram 复制代码 引入使用import WebsocketHeartbeat from 'websocket-heartbeat-miniprogram'; WebsocketHeartbeat({ miniprogram: wx, connectSocketParams: { url: 'ws://xxx' } }) .then(task => { task.onOpen = () => {//钩子函数 console.log('open'); }; task.onClose = () => {//钩子函数 console.log('close'); }; task.onError = e => {//钩子函数 console.log('onError:', e); }; task.onMessage = data => {//钩子函数 console.log('onMessage', data); }; task.onReconnect = () => {//钩子函数 console.log('reconnect...'); }; task.socketTask.onOpen(data => {//原生实例注册函数,重连后丢失 console.log('socketTask open'); }); task.socketTask.onMessage(data => {//原生实例注册函数,重连后丢失 console.log('socketTask data'); }); }) 本程序内部总是使用小程序connectSocket方法进行socket连接,如果socket断开,本程序内部会再次执行小程序的connectSocket方法,以此来重新建立连接,重连都会建立新的小程序socket实例。 WebsocketHeartbeat方法返回一个promise,返回的task对象是本程序的一个实例,提供了onOpen,onClose,onError,onMessage,onReconnect等钩子函数。也暴露了小程序本身的实例(socketTask),task.socketTask就是小程序connectSocket返回的实例,而task.socketTask是小程序的原生实例,它们通过onXXX方法传递函数进行监听注册,在socket重连以后,内部重新通过connectSocket新建实例,将会返回新的小程序原生实例,因此之前通过socketTask.onXXX注册的这些函数将会丢失。而本程序内部提供的钩子函数重连上以后依然有效。大部分情况下推荐就使用本程序的钩子函数。 支付宝小程序差异支付宝小程序只允许同时存在一个socket连接,原生的API也和其他小程序有一点小差异,本程序已经做了兼容,但是还是要注意支付宝只允许建立一个socket,如果建立多个socket,前面的socket都会被系统关闭,一定要通过本程序实例的task.close关闭旧的socket,否则程序会一直重连,导致所有socket相互冲突无法使用。 约定 1.只能通过前端主动关闭socket连接 如果需要断开socket,应该执行task.close()方法。如果后端想要关闭socket,应该下发一个消息,前端判断此消息,前端再调用task.close()方法关闭。因为无论是后端调用close还是因为其他原因造成的socket关闭,前端的socket都会触发onClose事件,程序无法判断是什么原因导致的关闭。因此本程序会默认尝试重连。 import WebsocketHeartbeat from 'websocket-heartbeat-miniprogram'; WebsocketHeartbeat({ miniprogram: wx, connectSocketParams: { url: 'ws://xxxx' } }) .then(task => { task.onMessage = data => { if(data.data == 'close') task.close();//关闭socket并且,不再重连 }; }) 2.后端对前端心跳的反馈 前端发送心跳消息,后端收到后,需要立刻返回响应消息,后端响应的消息可以是任何值,因为本程序并不处理和判断响应的心跳消息,而只是在收到任何消息后,重置心跳,因为收到任何消息就说明连接是正常的。因此本程序收到任何后端返回的消息都会重置心跳倒计时,以此来减少不必要的请求,减少服务器压力。 API详情参考: https://github.com/zimv/websocket-heartbeat-miniprogram 结语程序已经经过单元测试,也在百度,支付宝,微信等小程序之中实际测试和基于Taro测试。程序长期维护,发现兼容问题或者程序问题,希望得到issue反馈!
2020-02-22 - 小程序日历组件推荐
小程序日历组件推荐 这几天在做民宿小程序,遇到一个需求就是 用户选择日期,来下单,由于民宿每天的价格都是变化的,所以要在日历上显示价格,找了很久,终于找到了 vant https://youzan.github.io/vant-weapp/#/calendar 1 [图片] 2 [图片] 3 具体使用方法如下所示 [图片] 4 具体小程序界面截图如下所示: 5 [图片] 6 7 现在说起来都是风轻云淡,但是找的过程又盲目,有着急,开发中,也遇到各种问题,好在,回过头去,vant calendar就是我要找的日历组件 8
2020-06-07 - 直播----小程序开发心得分享
首先很开心,我司小程序获得第一波直播权限,我已经开发加好了直播,请确认你的小程序有直播资质,如果你有在开发中碰到什么问题,欢迎留言 一、引入直播插件 打开 app.json 文件 如果你代码有区分 分包 请记得将以下代码 放到 root 根文件夹 如果没有请忽略 以下代码 放到 "pages": ["pages/index/index"], 的同级地方 plugins": { "live-player-plugin": { "version": "1.0.2", "provider":"wx2b03c6e691cd7370" } }, 其中 live-player-plugin 是插件名字 version 是版本号码 二、引入直播开播 订阅组件(如果你不想引入,可以跳过) 在你要引入的页面 json 中添加组件 "usingComponents": { "subscribe": "plugin-private://wx2b03c6e691cd7370/components/subscribe/subscribe" } 注意不用改动 页面引入 room-id 属性一定要添加 就是后台会返回给你的 live_status 是用来判断状态 因为有时候我们都添加上订阅按钮 点了后会消失 是因为这个状态已经是过去的直播了 无法订阅 ps:这个插件目前有个 bug 就是 不管我有么有订阅这场 都是未订阅状态 但是点击去直播间的订阅按钮却是状态对的 并且我切换下 小程序 前后台(onShow onHide 切换)状态又是对的 三、页面跳转 你可以在图片上添加函数 也可以直接 navigator 跳转 goDetail(e) { var room = e.currentTarget.dataset.room; wx.reLaunch({ url: '/plugin-private://wx2b03c6e691cd7370/pages/live-player-plugin?room_id=' + room, }) } 或者 直接 navigator 跳转 四、页面分享 以下是我的页面分享 假设你的是卡片展示 或者图片展示 /** * 用户点击右上角分享 */ onShareAppMessage: function (res) { var idx = res.target.dataset.idx; const listInfo = this.data.listInfo[idx]; return { title: listInfo.name, imageUrl: listInfo.anchor_img, path: '/plugin-private://wx2b03c6e691cd7370/pages/live-player-plugin?room_id=' + listInfo.roomid } }, 五、订阅插件样式更改 /* 订阅 */ .subscribe--live-player-subscribe__btn{ width: 200rpx !important; height: 21px !important; line-height: 21px !important; font-weight: 200; font-size: 20rpx !important; text-align: center; background: #fff!important; color: #2d79ab!important; border-radius: 4px; pointer-events: auto; margin: 0 auto; } 写在最后-------------------------注意,开发工具目前是无法进入直播页面的,但是真机可以,你们可以上传到体验版然后通过微信后台开个直播,扫码体验就能进入直播间。 以上就是我的分享,谢谢大家观看~~,如果你觉得有用,点个赞吧
2020-04-03 - 熟练使用微信开发工具的代码块功能提升编码效率,降低误码率
1. 写在前面 自从上次介绍了宇宙第一强集成IDE的微信开发者工具安装插件等隐藏功能后,很多开发者社区哥们老铁感兴趣,一些哥们还私我问我是否支持代码块功能。答案是:支持!而且很完美的支持(此处必须有感恩,感恩微信团队每天的辛苦开发,作为同开发过小编辑器的人知道其中的苦与乐,同时呼吁各位猿少些喷喷喷的负能量,多些宣传和赞美的正能量!)。代码块是小编非常非常常用的一个功能,基本从04年开始建站和开发过程用过的所有IDE中都必备的功能。熟练使用微信开发工具的代码块功能提升编码效率,降低高频代码段的误写率。 2. 什么是代码块 可能有些刚接触开发的哥们不了解什么是「代码块」,这里我仅仅说说我个人对「代码块」功能的理解:代码块,英文名字:Code snippets,代码块的作用就是把比较长的一段代码在编码时只需要输入简写后的几个字母,比如把高频的代码console.log();简写成「clg」,再比如把小程序的页面.js里面的onLoad(),onShow等常用代码简写成「page_init」几个字母,最早提出这个概念和想法的人我也不知道是谁,总之得感谢他。如果说现在很多的编程语言有「语法糖」的说法,那么我个人觉得「代码块」可以称为「代码糖/编码糖」!熟练使用编码糖一定能让你尝到编码中的甜味。他的优点非常明显:极速,0误差输入高频代码段。个人觉得无论你现在处在编码的哪个级别都应该熟练使用Code snippets来提升工作效率。 3. 如何使用 3.1 打开开发者工具的编辑器扩展目录 [图片] 3.2 创建相关文件夹 返回上一级目录到User目下(里面有Workspaces文件夹),创建/进入snippets,此目录mac下完整路径应为:"~/Library/Application Support/微信开发者工具/【当前开发者工具特征码】/Default/Editor/User/snippets" [图片] 3.3 新建/编辑代码块json文件(如上图) [图片] 格式如上面,1,2,3是我比较常用的代码糖,生效后输入图1里面的clg回车就是console.log()(可以用这个来检测你代码糖功能是否生效);并且光标自动定位到()里,如下图: [图片][图片] 3.4 附带自用all.code-snippets 下面附上我常用的粗陋的代码糖块文件all.code-snippets(可以直接复制使用,你可以自行自己添加删除。里面有自己写的java框架常用的代码块,php常用和html常用以及nginx比较常用的,个人习惯不一样建议全部干掉重来,只需按里面的格式来写就可以了,格式如下: 字段名 意义 备注 prefix 简写后的字符串 必填 body 原字符串,可以用转义符 必填 description 备注 可控 [代码]{ // Example: // "Print to console": { // "scope": "javascript,typescript", // "prefix": "log", // "body": [ // "console.log('$0');", // "$2" // ], // "description": "Log output to console" // } //java begin "valueOf": { "prefix": "val", "body": "valueOf($0)", }, "parseInt": { "prefix": "par", "body": "Integer.parseInt($0);", }, "parseLong": { "prefix": "parl", "body": "Long.parseLong($0);", }, "equ": { "prefix": "equ", "body": "equals(\"$0\")", }, "isnull": { "prefix": "isnull", "body": "Tools.myIsNull($0)", }, "setattr": { "prefix": "setattr", "body": "request.setAttribute(\"$0\",$2)", }, "getattr": { "prefix": "getattr", "body": "request.getAttribute(\"$0\")", }, "getparam": { "prefix": "getparam", "body": "request.getParameter(\"$0\")", }, "getpost": { "prefix": "getpost", "body": "TtMap postUrl = Tools.getUrlParam();\r\nTtMap post = Tools.getpostmap(request, true);// 过滤参数,过滤mysql的注入,url参数注入\r\n" }, "tcf": { "prefix": "tcf", "body": "try{\r\n}catch(Exception e){\r\n\tTools.logError(e.getMessage());\r\n}finally{\r\n\t$0.closeConn();\r\n}", }, "777": { "prefix": "777", "body": "Runtime.getRuntime().exec(\"chmod 777 -R \" + strFileFullPath);" }, "go-1": { "prefix": "go-1", "body": "javascript:history.go(-1);" }, "dbctrl": { "prefix": "!dbctrl", "body": "DbCtrl dbCtrl = new DbCtrl(\"$0\");\r\ntry{\r\n\tTtList list = dbCtrl.lists(\"\", \"\");\r\n\tTtMap info = dbCtrl.info($2);\r\n}catch(Exception e){\r\n\tTools.logError(e.getMessage());\r\n\tif (Config.DEBUGMODE) {\r\n\t\te.printStackTrace();\r\n\t}\r\n}finally{\r\n\tdbCtrl.closeConn();\r\n}", "description": "TT-DbCtrl" }, "dbtools": { "prefix": "dbtools", "body": "DbTools dbTools = new DbTools();\r\ntry{\r\n\tTtList list = dbTools.reclist(\"$0\");\r\n\tTtMap info = dbTools.recinfo(\"$2\");\r\n}catch(Exception e){\r\n\tTools.logError(e.getMessage());\r\n}finally{\r\n\tdbTools.closeConn();\r\n}" }, "!recinfo": { "prefix": "rrecinfo", "body": "Tools.recinfo(\"$0\")", "description": "TT-DbTools-recinfo" }, "!reclist": { "prefix": "rreclist", "body": "Tools.reclist(\"$0\")", "description": "TT-DbTools-reclist" }, "ss": { "prefix": "ss", "body": "String[] sS = new String[]{}; ", "description": "new String[]" }, "mss": { "prefix": "mss", "body": "TtMap info = new HashMap<>();", "description": "new Map<String,String>" }, "lss": { "prefix": "lss", "body": "TtList lmss = new ArrayList<>();", "description": "new TtList " }, "<%": { "prefix": "!s", "body": "<%\r\n\t$0\r\n%>", "description": "TT-JSP<%自动完成" }, "<%=": { "prefix": "!ss", "body": "<%=$0%>", "description": "TT-JSP<%=自动完成" }, "jsp_include": { "prefix": "!sss", "body": "<jsp:include page=\"<%=$0%>\">\r\n\t<jsp:param name=\"$3\" value=\"$2\"/>\r\n</jsp:include>" }, "jsp_include2": { "prefix": "<jsp", "body": "<jsp:include page=\"<%=$0%>\">\r\n\t<jsp:param name=\"$3\" value=\"$2\"/>\r\n</jsp:include>" }, "!jsp_requery": { "prefix": "!req", "body": "request.getParameter(\"$0\")", }, "!jsp_requery_getAttribute": { "prefix": "!req2", "body": "request.getAttribute(\"$0\")", }, "!": { "prefix": "!ssss", "body": "<%@page import=\"com.tt.tool\"%>\r\n<%@ page contentType=\"text/html;charset=UTF-8\" language=\"java\"%>\r\n<%@ taglib prefix=\"c\" uri=\"http://java.sun.com/jsp/jstl/core\"%>\r\n<%@ taglib prefix=\"fmt\" uri=\"http://java.sun.com/jsp/jstl/fmt\"%>\r\n<%@ taglib uri=\"http://java.sun.com/jsp/jstl/functions\" prefix=\"fn\"%>\r\n<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\r\n <title>$0</title>\r\n</head>\r\n<body>\r\n\t$2\r\n</body>\r\n</html>", "description": "jsp-header" }, "div": { "prefix": "<div", "body": "<div id=\"$0\" name=\"$0\">\r\n\t\r\n</div>", }, "p": { "prefix": "<p", "body": "<p id=\"\" name=\"\"></p>", }, "a": { "prefix": "<a", "body": "<a href=\"$0\" id=\"\" name=\"\">$2</a>", }, "head": { "prefix": "<head", "body": "<head>\r\n\t$0\r\n</head>", }, "img": { "prefix": "<img", "body": "<img id=\"\" name=\"\" src=\"$0\">" }, "ul": { "prefix": "<ul", "body": "<ul id=\"\" name=\"\">\r\n\t\r\n</ul>" }, "li": { "prefix": "<li", "body": "<li id=\"\" name=\"\">\r\n\t\r\n</li>" }, "select": { "prefix": "<select", "body": "<select id=\"\" name=\"\">\r\n\t\r\n</select>" }, "option": { "prefix": "<option>", "body": "<option value=\"\">$0</option>" }, "input": { "prefix": "<input", "body": "<input type=\"$0\" id=\"$2\" name=\"$2\" value=\"$3\">" }, "form": { "prefix": "<form", "body": "<form id=\"info_form\" action=\"$${posturl}\" class=\"form-horizontal\" method=\"post\" enctype=\"multipart/form-data\">\r\n\t$2\r\n</form>" }, "!i": { "prefix": "!i", "body": "<%@ page contentType=\"text/html;charset=UTF-8\" language=\"java\"%>\r\n<%@ page import=\"com.tt.tool.Tools\" %>\r\n<%@ page import=\"com.tt.data.TtMap\" %>\r\n<%@ page import=\"com.tt.data.TtList\" %>\r\n<%@ page import=\"com.tt.tool.JspTools\" %>\r\n<%@ page import=\"java.util.*\" %>\r\n<%@ taglib prefix=\"c\" uri=\"http://java.sun.com/jsp/jstl/core\"%>\r\n<%@ taglib prefix=\"fmt\" uri=\"http://java.sun.com/jsp/jstl/fmt\"%>\r\n<%@ taglib uri=\"http://java.sun.com/jsp/jstl/functions\" prefix=\"fn\"%>\r\n<%@ taglib prefix=\"Tools\" uri=\"/tld/manager\" %>\r\n", }, "loginfo": { "prefix": "loginfo", "body": "Tools.logInfo($0)", "description": "loginfo" }, "logerror": { "prefix": "logerror", "body": "Tools.logError($0)", "description": "loginfo" }, //javascript "!go-1": { "prefix": "!go-1", "body": "javascript:history.go(-1);", }, "!tag": { "prefix": "!tag", "body": "<%@ taglib prefix=\"c\" uri=\"http://java.sun.com/jsp/jstl/core\"%>\r\n<%@ taglib prefix=\"fmt\" uri=\"http://java.sun.com/jsp/jstl/fmt\"%>\r\n<%@ taglib uri=\"http://java.sun.com/jsp/jstl/functions\" prefix=\"fn\"%>\r\n<%@ taglib prefix=\"Tools\" uri=\"/tld/manager\" %>", }, "$$": { "prefix": "$$", "body": "$(function(){$0\r\n});", "description": "TT-jquery自动运行" }, "$(": { "prefix": "$f", "body": [ "$(function(){", "});" ], "description": "TT-jquery自动运行" }, "timer": { "prefix": "timer", "body": "inv = setInterval(\"$0showtimes();\",1000);", "description": "TT-JS每隔几秒自动运行", }, "!posturl": { "prefix": "!posturl", "body": "<%=Tools.urlKill(\"id$0\")%>", }, "!ifdebug": { "prefix": "ifd", "body": [ "if (Config.DEBUGMODE) {", "\te.printStackTrace();", "}" ], }, "reload":{ "prefix": "reload", "body": "location.reload(true);" }, //PHP "<?php": { "prefix": "php", "body": "<?php $0 ?>", "description": "Global-PHP插入标签" }, "nav":{ "prefix": "nav", "body": "<navigator url=\"car_yy/car_yy_ppuser/car_yy_ppuser\">", "description": "老子的微信小程序的跳转", }, "bind":{ "prefix": "bind", "body": "bindtap=\"$1\"", "description": "老子的bindtap" }, "wx_ra":{ "prefix": "wepy_ra", "body":"let result = await util.wxRequest(httpSet);", "description": "微信小程序阻塞等待请求" }, "wx_r":{ "prefix": "wepy_r", "body":["util.wxRequest(httpSet).then(function(result){\r\n\tif(result.result==\"success\"){$1\r\n\t}\r\n});"], "description": "微信小程序阻塞等待请求" }, "httpset":{ "prefix": "wepy_hs", "body": "let params= {};\r\nlet httpSet={\r\n\turl:'$1',\r\n\tparams:params,\r\n\tmethod:'GET',\r\n\tisShowLoading: false,\r\n}", "description": "httpSet" }, "wepy_global":{ "prefix": "wepy_global", "body": "wepy.$$instance.globalData.$1", }, "wepy_castfail":{ "prefix": "wepy_castfail", "body": "this.$$broadcast('alertHeaderWarning', '$1');" }, "wepy_castOK":{ "prefix": "wepy_castok", "body": "this.$$broadcast('alertHeader', '$1');" }, "wepy_castfail_height":{ "prefix": "wepy_castfailh", "body": "this.$$broadcast('alertHeaderWarningHeight', '$1',60);" }, "wepy_castOK_height":{ "prefix": "wepy_castokh", "body": "this.$$broadcast('alertHeaderHeight', '$1',60);" }, "clg": { "prefix": "clg", "body": "console.log($0);" }, "wepy_tt":{ "prefix": "wepy_tt", "body": "let that = this;" }, "wepy_currtarget":{ "prefix": "wepy_currt", "body": " e.currentTarget.dataset.$1", }, "wepy_gourl":{ "prefix":"wepy_gourl", "body":"@tap=\"goUrl\" data-url=\"$1\" data-memberflag=\"$2\"", }, "wepy_goback":{ "prefix": "wepy_goback", "body":"wepy.navigateBack();" }, "wepy_urlencode":{ "prefix": "wepy_urlencode", "body": "encodeURIComponent($1);" }, "wepy_urldecode":{ "prefix": "wepy_urldecode", "body": "decodeURIComponent($1);" }, "wepy_noimg":{ "prefix": "wepy_noimg", "body": "/images/imgload.png", }, "wepy_errmsg":{ "prefix": "wepy_errmsg", "body": "(result && result.errorMsg) ? result.errorMsg :\"删除失败!\"", }, "wepy_sets":{ "prefix": "wepy_sets", "body": "wepy.setStorageSync($1,$2);" }, "wepy_gets":{ "prefix": "wepy_gets", "body": "wepy.getStorageSync($1);" } } [代码] 4. 相关链接 持续更新:收藏整理官方隐藏的小程序功能/参数/方法/API 动手打造更强更好用的微信开发者工具-编辑器扩展篇 点击wxml里面的绑定事件/变量名/样式名直接跳转到对应文件代码 小程序编码时变量名中文转英文变量名工具,各种驼峰取名 微信开发者工具编辑器支持「书签」功能,快速跳转到指定文件指定行和列 愉快的编写和调试Java:体验新版开发者工具的编辑器扩展功能 5. 其他未公布的隐藏功能 当你觉得有用的时候,就点赞和收藏或者分享,觉得没用的话就投诉,不管点赞还是投诉后的码农写代码永无BUG ,CP设计的产品人见人爱,BOSS每年收入翻番! ↓↓↓↓↓↓__________________________________________________________________________投诉的话点…↓↓↓
2020-05-17 - 动手打造更强更好用的微信开发者工具-编辑器扩展篇
1. 写在前面 1.1 微信开发者工具现状 具备一些基本的通用IDE功能,但是第三方的支持扩展需要加强。 1.2 开发者工具自带的编辑器扩展功能 可能很多老铁没用过官方的微信开发者工具的编辑器扩展(我一般称为编辑器插件)。官方把这块功能也隐藏得很深,也没有相关文档介绍,但是预留了相关的入口。合理利用第三方编辑器插件,可以极大的提升开发效率。下面先来看看官方预留的编辑器插件入口: [图片] (图一) 2. 几个不错插件安装效果 2.1 标签高亮插件-vincaslt.highlight-matching-tag [图片] 功能:可以把当前行对应的标签开头和结尾高亮起来,让开发者一目了然 2.2 小程序开发助手插件-overtrue.miniapp-helper [图片] 功能:必须要说的这个是纯国产的插件,里面的代码片段功能很全,具体介绍:小程序开发助手 - Visual Studio Marketplace https://marketplace.visualstudio.com/items?itemName=overtrue.miniapp-helper 2.3 minapp插件-qiu8310.minapp-vscode [图片] 功能:这个是今天的明星插件,里面的跳转功能很强,可以在wxml里CMD+点击对应变量/方法和CSS样式名称直接跳转到对应的js/wxss文件对应的地方。具体的下面是官方介绍: 标签名与属性自动补全 根据组件已有的属性,自动筛选出对应支持的属性集合 属性值自动补全 点击模板文件中的函数或属性跳转到 js/ts 定义的地方(纯 wxml 或 pug 文件才支持,vue 文件不完全支持) 样式名自动补全(纯 wxml 或 pug 文件才支持,vue 文件不完全支持) 在 vue 模板文件中也能自动补全,同时支持 pug 语言 支持 link(纯 wxml 或 pug 文件才支持,vue 文件不支持) 自定义组件自动补全(纯 wxml 文件才支持,vue 或 pug 文件不支持) 模板文件中 js 变量高亮(纯 wxml 或 pug 文件才支持,vue 文件不支持) 内置 snippets 支持 emmet 写法 wxml 格式化 3. DIY添加适合自己的插件 3.1 添加插件功能简介 仔细研究过微信开发者工具的人可能知道或者了解,其实微信开发者工具编辑器跟微软的开源编辑器vsCode「颇有渊源」。再深入研究发现,vsCode的插件完全可以无缝移植到微信开发者工具编辑器里来,所以今天的内容就是移植vsCode的插件到微信开发者工具。咱们先看看微信开发者工具自带的「管理编辑器扩展」功能(图1标注为2的地方) [图片](图二) 3.2 插件添加具体步骤 3.2.1 安装插件,获取插件文件 安装vsCode并安装你需要移植的插件,必须要说的是vsCode的插件非常多,好的插件也很多。相关安装,搜索插件教程建议大家百度相关教程。或者直接下载vsCode亲自体验,插件安装过程还是非常简单的。 3.2.2 复制插件文件夹 找到vsCode相关插件的安装文件夹: 操作系统 安装路径 windows %USERPROFILE%.vscode\extensions macOS ~/.vscode/extensions Linux ~/.vscode/extensions 复制对应插件文件夹到微信开发者工具的「打开编辑器扩展目录」(图一标注为1的地方) 3.2.3 添加插件配置文件 新版开发者工具直接进入图形设置,扩展设置里勾选对应插件即可。如下图: [图片] 旧版操作方法:进入微信开发者工具的「管理编辑器扩展」功能页面,在尾端加入对应添加的插件名称。以以上3个介绍的插件为例,在原来的尾端加入: “vincaslt.highlight-matching-tag”, “overtrue.miniapp-helper”, “qiu8310.minapp-vscode” 3.2.4 见证奇迹 重启微信开发者工具,见证插件带来的编码便利吧! 4 需要注意的 vsCode的插件很多,小程序相关的也越来越多了,但是插件质量参差不齐,所以安装时建议选择「标星」star比较多的插件。
2020-05-02 - 仅需6步7分钟,用原生 js 接入腾讯云即时通信 IM
### 概述 本文用6个步骤,讲解了如何用原生 js 在微信小程序接入腾讯云即时通信 IM,耗时大约7分钟。值得一看,不耽误事。 ### 背景 危机,有危就有机。疫情给全世界带来了很大的危害,也给很多场景和应用带来了前所未有的机会,如在线会议、在线教学、直播带货、全媒体客服等获得了前所未有的使用和增长。实现这些场景推荐使用腾讯云 TRTC,感兴趣的老板可以详细了解下,在此不多赘述。那如何实现会议、教学场景的聊天、文件传输、禁言功能,直播场景的弹幕、送礼、过滤涉黄涉政不雅词功能,全媒体客服的文本、语音、图片咨询功能呢?推荐使用腾讯云即时通信 IM,简单接入、稳定必达、覆盖全球。 “万事开头难”,接入一个 SDK 相当于开头,快速接入成功就开了个好头,心情愉悦干活有劲,后续可以调用相关 API 实现复杂具体的功能。下面就给大家介绍如何快速、心情愉悦地“开头”。 ### 步骤 ##### 1、打开微信开发者工具,新建小程序项目 [图片] ##### 2、命令行打开刚创建的项目文件目录,`npm init -y` 快速生成 package.json ##### 3、下载腾讯云即时通信 IMSDK:`npm install tim-wx-sdk@latest --production` [图片] ##### 4、构建 npm [图片] 构建成功后能在项目目录看到 miniprogram_npm 和 tim-wx-sdk [图片] ##### 5、详情-》本地设置-》使用 npm 模块 [图片] ##### 6、引入 TIM 模块 import TIM from 'tim-wx-sdk' //app.js App({ onLaunch: function () { // 创建 SDK 实例,TIM.create() 方法对于同一个 SDKAppID 只会返回同一份实例 let options = { SDKAppID: 0 // 接入时需要将0替换为您的即时通信应用的 SDKAppID }; let tim = TIM.create(options); // SDK 实例通常用 tim 表示 // 设置 SDK 日志输出级别,详细分级请参见 setLogLevel 接口的说明 tim.setLogLevel(0); // 普通级别,日志量较多,接入时建议使用 }, globalData: { userInfo: null } }) 控制台如果能看到 TIM.VERSION: 2.6.1 的日志,表示接入成功。 [图片] ### 相关文档 更新日志SDK 接口文档AVChatRoom 使用指南Web Demo小程序[图片] iOS(密码 123)[图片]Android [图片]
2020-04-13 - 如何实现一个自定义数据版省市区二级、三级联动
社区可能有其他的方案了,但是再分享下吧,给有需要的童鞋。 效果图: [图片] 额,这个视频转GIF因为社区上传不了大图,所以剪了一部分,具体的效果还是直接工具打开代码片段预览吧~ 第一步:你的页面JSON引入该组件: [代码]{ "usingComponents": { "city-picker": "/components/cityPicker/index" } } [代码] 第二步:你的页面WXML引入该组件 [代码]<city-picker visible="{{visible}}" column="2" bind:close="handleClick" bind:confirm="handleConfirm" /> [代码] 第三步:你的页面JS调用 [代码]// 显示/隐藏picker选择器 handleClick() { this.setData( visible: !this.data.visible }) }, // 用户选择城市后 点击确定的返回值 handleConfirm(e) { const { detail: { provinceName = '', provinceId = '', cityName, cityId='', areaName = '', areaId = '' } = {} } = e this.setData({ cityId, cityName, areaId, areaName, provinceId, provinceName }) } [代码] 组件属性 属性 默认值 描述 visible false 是否显示picker选择器 column 3 显示几列,可选值:1,2,3 values [0, 0, 0] 必填,默认回填的省市区下标,可选择具体省市区后查看AppData的regionValue字段 close function 点击关闭picker弹窗 confirm function 点击选择器的确定返回值 confirm: 属性 默认值 描述 provinceName 北京市 省份名称 provinceId 110000 省份ID cityName 市辖区 城市名称 cityId 110100 城市ID areaName 东城区 区域名称 areaId 110000 区域Id 至于怎么获取你想默认城市的下标,可以滑动操作下选中省市区后,点击确定后查看appData里的regionValue的值。 以上就是一个自定义数据版本的省市区二级、三级联动啦,老规矩,结尾放代码片段。 https://developers.weixin.qq.com/s/F9k9cTmT7LAz
2022-07-20 - 小程序页面(Page)扩展,为所有页面添加公共的生命周期、事件处理等函数
背景 在小程序的原生开发中,页面中经常会用到一些公共方法,例如在页面onLoad中验证权限、所有页面都需要onShareAppMessage设置分享等 假设我们在编码时每个页面都写一遍,显然不是一个高级程序员会干的事情,太Low了。如果我们定义一个公共文件,导出这些公共方法,每个页面都引入,然后再生命周期或者事件处理函数中调用,虽然看起来很方便,但不够优雅,达不到我们最终的目的(偷懒)。 下面给大家介绍一种相对比较优雅的实现方式,扩展Page来实现以上的操作。 Page(页面) 需要传入的是一个 [代码]object[代码] 类型的参数,那么我们重载一个 [代码]Page[代码] 函数,将这个 [代码]object[代码] 参数拦截改掉就可以了,下面直接上代码。 实现 1、在根目录新建一个 [代码]page-extend.js[代码] 文件,公共的逻辑都写在这里面 [代码]/** * * Page扩展函数 * * @param {*} Page 原生Page */ const pageExtend = Page => { return object => { // 导出原生Page传入的object参数中的生命周期函数 // 由于命名冲突,所以将onLoad生命周期函数命名成了onLoaded const { onLoaded } = object // 公共的onLoad生命周期函数 object.onLoad = function (options) { // 在onLoad中执行的代码 ... // 执行onLoaded生命周期函数 if (typeof onLoaded === 'function') { onLoaded.call(this, options) } } // 公共的onShareAppMessage事件处理函数 object.onShareAppMessage = () => { return { title: '分享标题', imageUrl: '分享封面' } } return Page(object) } } // 获取原生Page const originalPage = Page // 定义一个新的Page,将原生Page传入Page扩展函数 Page = pageExtend(originalPage) [代码] 2、在 [代码]app.js[代码] 中引入 [代码]page-extend.js[代码] 文件 [代码]require('./page-extend') App({ // 其他代码 ... }) [代码] 代码片段 https://developers.weixin.qq.com/s/Cyx8iGmV7Ldp 本文内容及评论未经允许,禁止任何形式的转载与复制(代码可在程序中使用)
2019-12-24