- 2019-02-26
- 小程序云函数的高级玩法-路由
一般情况下,一个云函数完成单一的逻辑功能,就是一个类的方法一样,如图: [图片] 但是受限免费用户最多只能使用20个云函数,想要在单一云函数中实现多个复杂的功能就需要通过参数来区别,可读性差,不利于管理。通过路由,尝试将请求归类,一个云函数处理某一类的请求,比如有专门负责处理用户的,或者专门处理支付的云函数。如图: [图片] 为了方便大家试用,腾讯云 Tencent Cloud Base 团队开发了 tcb-router,云函数路由管理库方便大家使用。 基于 koa 风格的小程序·云开发云函数轻量级类路由库,主要用于优化服务端函数处理逻辑 使用 npm install --save tcb-router 云函数端 // 云函数的 index.js const TcbRouter = require(’./router’); exports.main = (event, context) => { const app = new TcbRouter({ event }); [代码]// app.use 表示该中间件会适用于所有的路由 app.use(async (ctx, next) => { ctx.data = {}; await next(); // 执行下一中间件 }); // 路由为数组表示,该中间件适用于 user 和 timer 两个路由 app.router(['user', 'timer'], async (ctx, next) => { ctx.data.company = 'Tencent'; await next(); // 执行下一中间件 }); // 路由为字符串,该中间件只适用于 user 路由 app.router('user', async (ctx, next) => { ctx.data.name = 'heyli'; await next(); // 执行下一中间件 }, async (ctx, next) => { ctx.data.sex = 'male'; await next(); // 执行下一中间件 }, async (ctx) => { ctx.data.city = 'Foshan'; // ctx.body 返回数据到小程序端 ctx.body = { code: 0, data: ctx.data}; }); // 路由为字符串,该中间件只适用于 timer 路由 app.router('timer', async (ctx, next) => { ctx.data.name = 'flytam'; await next(); // 执行下一中间件 }, async (ctx, next) => { ctx.data.sex = await new Promise(resolve => { // 等待500ms,再执行下一中间件 setTimeout(() => { resolve('male'); }, 500); }); await next(); // 执行下一中间件 }, async (ctx)=> { ctx.data.city = 'Taishan'; // ctx.body 返回数据到小程序端 ctx.body = { code: 0, data: ctx.data }; }); return app.serve(); [代码] } tips: 小程序云函数的 node 环境默认支持 async/await 语法,推荐涉及到的异步操作时像 demo 中那样使用 小程序端 // 调用名为 router 的云函数,路由名为 user wx.cloud.callFunction({ // 要调用的云函数名称 name: “router”, // 传递给云函数的参数 data: { $url: “user”, // 要调用的路由的路径,传入准确路径或者通配符* other: “xxx” } }); 完整的实例,请参考我的另一篇博客: 分享使用tcb-router路由开发的云函数短信平台SDK
2019-04-20 - 微信小程序实现时间轴和地区列表的功能
老规矩先看效果图 [图片] 先来看左图的地区列表是如何实现的。 我们在解析数据之前,要先看下数据结构 [代码][{ "_id": "XL28U3kPDdDCJ9m0", "item": { "diqu": "北京", "list": [{ "id": "XL27oeSiwXKAQuFR", "name": "清华大学", "img": "https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=2693386884,1727296839\u0026fm=58\u0026bpow=1200\u0026bpoh=1200" }, { "id": "XL27oeSiwXKAQuF1", "name": "北京大学", "img": "https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=2152123166,2178049351\u0026fm=58\u0026bpow=1080\u0026bpoh=1080" }, { "id": "XL27oeSiwXKAQuF2", "name": "人民大学", "img": "https://ss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=2642337058,1598432384\u0026fm=58\u0026w=121\u0026h=140\u0026img.PNG" }] } }, { "_id": "XL28U3kPDdDCJ9m1", "item": { "diqu": "杭州", "list": [{ "id": "XL27oeSiwXKAQuF3", "name": "杭州师范大学", "img": "https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=2219745018,1861674512\u0026fm=58\u0026bpow=475\u0026bpoh=475" }, { "id": "XL27oeSiwXKAQuF4", "name": "浙江大学", "img": "https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=3694367183,2414886214\u0026fm=58\u0026bpow=995\u0026bpoh=995" }] } }] [代码] 这里有两条数据,一个是北京地区的,一个是杭州地区的,正好对应我们图上的地区。然后每条json数据里面包含一个学校list,比如北京地区有清华大学,北京大学,人民大学。而每个大学对象里又包含学校id,学校名,学校校徽。 有了上面的源数据,接下来我们就看具体的实现 首先是wxml文件,其实很简单,就是一个大的列表用来显示地区,大列表里面又有一个小的列表用来显示学校。 [代码]<!--index.wxml--> <!-- 列表 --> <block wx:for="{{dataList}}" wx:key="item"> <view class='item-root'> <text class='title'>{{item.item.diqu}}</text> <block wx:for="{{item.item.list}}" wx:key="item"> <view class='img-root' bindtap='goDetail' data-item='{{item}}'> <image class='img' src='{{item.img}}'></image> <text class='xuexiao'>{{item.name}}</text> </view> </block> </view> </block> [代码] 然后是wxss文件 [代码]/* pages/myorder/myorder.wxss */ page { background: #fff; } .item-root { display: flex; flex-direction: column; } .title { width: 100%; background: gainsboro; } .img-root { display: flex; margin-left: 15px; margin-top: 5px; border-bottom: solid 1px gainsboro; } .img { width: 30px; height: 30px; } .xuexiao { margin: 5px 10px; flex: 1; } [代码] 至于如何把源数据json解析并显示到列表中,可以参考我之前写的解析本地json到列表。 《列表功能实现和本地json数据解析》: https://www.kancloud.cn/java-qiushi/xiaochengxu/767304 [图片] 视频讲解: https://edu.csdn.net/course/play/9531/202161 [图片] 到这里我们的地区列表就轻松的实现了,再来看下时间轴列表的实现 小程序时间轴列表实现 [图片] 还是先看数据源,我们拿清华大学为例 [代码]{ "_id": "XL27oeSiwXKAQuFR", "name": "清华大学", "desc": "清华大学始建与1900年,位于北京", "img": "https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=2693386884,1727296839\u0026fm=58\u0026bpow=1200\u0026bpoh=1200", "wangzhi": "http://www.tsinghua.edu.cn", "diqu": "北京市海淀区", "newsList": [{ "time": "2019年4月1日", "content": "招聘职位:英语老师,数学老师,物理老师", "title": "逸夫楼3楼大厅北京新东方专场招聘会" }, { "time": "2019年3月25日", "title": "北京京东专场招聘", "content": "招聘岗位:管培生,总裁助理,总经理" }] } [代码] 可以看到我们是顶部的学校信息,和底部的newsList组成,newsList就是我们时间轴的具体数据源。下面我们就来看看实现代码。 wxml文件如下,注释里写的很清楚了 [代码]<view class='top-root'> <view class='img-root'> <image class='img' src='{{deatil.img}}'></image> </view> <view class='top-desc-root'> <text class='xiangqing'>{{deatil.name}}</text> <text class='xiangqing'>网址:{{deatil.wangzhi}}</text> <text class='xiangqing'>地区:{{deatil.diqu}}</text> </view> </view> <!-- 时间轴 --> <view class="listview-container"> <block wx:for="{{newsList}}" wx:key="item"> <view class="playlog-item" bindtap="itemTapped"> <view class="dotline"> <!-- 竖线 --> <view class="line"></view> <!-- 圆点 --> <view class="dot"></view> <!-- 时间戳 --> </view> <view class="content"> <text class="course">{{item.time}}</text> <text class="course">{{item.title}}</text> <text class="chapter">{{item.content}}</text> </view> </view> <ad unit-id="adunit-5abb45645905fc90" wx:if="{{index % 5 == 4}}"></ad> </block> </view> [代码] wxss样式文件如下 [代码]page { background: #fff; } .top-root { display: flex; flex-wrap: nowrap; flex-direction: row; } .img-root { height: 40px; width: 40px; margin: 5px; } .img { width: 100%; height: 100%; } .top-desc-root { flex: 1; display: flex; flex-direction: column; } .xiangqing { font-size: 28rpx; color: #000; } /*时间轴*/ /*外部容器*/ .listview-container { margin: 10rpx 10rpx; } /*行样式*/ .playlog-item { display: flex; } /*时间轴*/ .playlog-item .dotline { width: 35px; position: relative; } /*竖线*/ .playlog-item .dotline .line { width: 1px; height: 100%; background: #ccc; position: absolute; top: 0; left: 15px; } /*圆点*/ .playlog-item .dotline .dot { width: 11px; height: 11px; background: #30ac63; position: absolute; top: 10px; left: 10px; border-radius: 50%; } /*时间戳*/ .playlog-item .dotline .time { width: 100%; position: absolute; margin-top: 30px; z-index: 99; font-size: 12px; color: #777; text-align: center; } /*右侧主体内容*/ .playlog-item .content { width: 100%; display: flex; flex-direction: column; border-bottom: 1px solid #ddd; margin: 3px 0; } /*章节部分*/ .playlog-item .content .chapter { font-size: 30rpx; line-height: 68rpx; color: #444; white-space: normal; padding-right: 10px; } /*课程部分*/ .playlog-item .content .course { font-size: 28rpx; line-height: 56rpx; color: #999; } [代码] 到这里时间的样式就已经实现了,我们接下来要做的就是把数据源json数据解析到页面上。方式有如下三种 1,把json放本地 2,把json导入到云开发数据 3,把json放到我们自己的服务器后台 下面我简单已放在云开发数据库并请求解析为例 先看下我云开发后台数据库 [图片] 然后写个云函数去获取云开发数据库里的json数据源,就是上图红色框里的数据 [图片] 可以看到我们成功的请求到了云数据库里的数据到本地。并成功解析并渲染到页面上了。是不是很简单。 当然,实现这些你还需要有一定的云开发知识。 同样为大家提供了云开发视频讲解:https://edu.csdn.net/course/detail/9604 有任何关于编程的问题都可以加我微信2501902696(备注编程开发) 编程小石头,码农一枚,非著名全栈开发人员。分享自己的一些经验,学习心得,希望后来人少走弯路,少填坑。 [图片]
2019-04-24 - 路由的封装
小程序提供了路由功能来实现页面跳转,但是在使用的过程中我们还是发现有些不方便的地方,通过封装,我们可以实现诸如路由管理、简化api等功能。 页面的跳转存在哪些问题呢? 与接口的调用一样面临url的管理问题; 传递参数的方式不太友好,只能拼装url; 参数类型单一,只支持string。 alias 第一个问题很好解决,我们做一个集中管理,比如新建一个[代码]router/routes.js[代码]文件来实现alias: [代码]// routes.js module.exports = { // 主页 home: '/pages/index/index', // 个人中心 uc: '/pages/user_center/index', }; [代码] 然后使用的时候变成这样: [代码]const routes = require('../../router/routes.js'); Page({ onReady() { wx.navigateTo({ url: routes.uc, }); }, }); [代码] query 第二个问题,我们先来看个例子,假如我们跳转[代码]pages/user_center/index[代码]页面的同时还要传[代码]userId[代码]过去,正常情况下是这么来操作的: [代码]const routes = require('../../router/routes.js'); Page({ onReady() { const userId = '123456'; wx.navigateTo({ url: `${routes.uc}?userId=${userId}`, }); }, }); [代码] 这样确实不好看,我能不能把参数部分单独拿出来,不用拼接到url上呢? 可以,我们试着实现一个[代码]navigateTo[代码]函数: [代码]const routes = require('../../router/routes.js'); function navigateTo({ url, query }) { const queryStr = Object.keys(query).map(k => `${k}=${query[k]}`).join('&'); wx.navigateTo({ url: `${url}?${queryStr}`, }); } Page({ onReady() { const userId = '123456'; navigateTo({ url: routes.uc, query: { userId, }, }); }, }); [代码] 嗯,这样貌似舒服一点。 参数保真 第三个问题的情况是,当我们传递的参数argument不是[代码]string[代码],而是[代码]number[代码]或者[代码]boolean[代码]时,也只能在下个页面得到一个[代码]string[代码]值: [代码]// pages/index/index.js Page({ onReady() { navigateTo({ url: routes.uc, query: { isActive: true, }, }); }, }); // pages/user_center/index.js Page({ onLoad(options) { console.log(options.isActive); // => "true" console.log(typeof options.isActive); // => "string" console.log(options.isActive === true); // => false }, }); [代码] 上面这种情况想必很多人都遇到过,而且感到很抓狂,本来就想传递一个boolean,结果不管传什么都会变成string。 有什么办法可以让数据变成字符串之后,还能还原成原来的类型? 好熟悉,这不就是json吗?我们把要传的数据转成json字符串([代码]JSON.stringify[代码]),然后在下个页面把它转回json数据([代码]JSON.parse[代码])不就好了嘛! 我们试着修改原来的[代码]navigateTo[代码]: [代码]const routes = require('../../router/routes.js'); function navigateTo({ url, data }) { const dataStr = JSON.stringify(data); wx.navigateTo({ url: `${url}?jsonStr=${dataStr}`, }); } Page({ onReady() { navigateTo({ url: routes.uc, data: { isActive: true, }, }); }, }); [代码] 这样我们在页面中接受json字符串并转换它: [代码]// pages/user_center/index.js Page({ onLoad(options) { const json = JSON.parse(options.jsonStr); console.log(json.isActive); // => true console.log(typeof json.isActive); // => "boolean" console.log(json.isActive === true); // => true }, }); [代码] 这里其实隐藏了一个问题,那就是url的转义,假如json字符串中包含了类似[代码]?[代码]、[代码]&[代码]之类的符号,可能导致我们参数解析出错,所以我们要把json字符串encode一下: [代码]function navigateTo({ url, data }) { const dataStr = encodeURIComponent(JSON.stringify(data)); wx.navigateTo({ url: `${url}?encodedData=${dataStr}`, }); } // pages/user_center/index.js Page({ onLoad(options) { const json = JSON.parse(decodeURIComponent(options.encodedData)); console.log(json.isActive); // => true console.log(typeof json.isActive); // => "boolean" console.log(json.isActive === true); // => true }, }); [代码] 这样使用起来不方便,我们封装一下,新建文件[代码]router/index.js[代码]: [代码]const routes = require('./routes.js'); function navigateTo({ url, data }) { const dataStr = encodeURIComponent(JSON.stringify(data)); wx.navigateTo({ url: `${url}?encodedData=${dataStr}`, }); } function extract(options) { return JSON.parse(decodeURIComponent(options.encodedData)); } module.exports = { routes, navigateTo, extract, }; [代码] 页面中我们这样来使用: [代码]const router = require('../../router/index.js'); // page home Page({ onLoad(options) { router.navigateTo({ url: router.routes.uc, data: { isActive: true, }, }); }, }); // page uc Page({ onLoad(options) { const json = router.extract(options); console.log(json.isActive); // => true console.log(typeof json.isActive); // => "boolean" console.log(json.isActive === true); // => true }, }); [代码] route name 这样貌似还不错,但是[代码]router.navigateTo[代码]不太好记,[代码]router.routes.uc[代码]有点冗长,我们考虑把[代码]navigateTo[代码]换成简单的[代码]push[代码],至于路由,我们可以使用[代码]name[代码]的方式来替换原来[代码]url[代码]参数: [代码]const routes = require('./routes.js'); function push({ name, data }) { const dataStr = encodeURIComponent(JSON.stringify(data)); const url = routes[name]; wx.navigateTo({ url: `${url}?encodedData=${dataStr}`, }); } function extract(options) { return JSON.parse(decodeURIComponent(options.encodedData)); } module.exports = { push, extract, }; [代码] 在页面中使用: [代码]const router = require('../../router/index.js'); Page({ onLoad(options) { router.push({ name: 'uc', data: { isActive: true, }, }); }, }); [代码] navigateTo or switchTab 页面跳转除了navigateTo之外还有switchTab,我们是不是可以把这个差异抹掉?答案是肯定的,如果我们在配置routes的时候就已经指定是普通页面还是tab页面,那么程序完全可以切换到对应的跳转方式。 我们修改一下[代码]router/routes.js[代码],假设home是一个tab页面: [代码]module.exports = { // 主页 home: { type: 'tab', path: '/pages/index/index', }, uc: { path: '/pages/a/index', }, }; [代码] 然后修改[代码]router/index.js[代码]中[代码]push[代码]的实现: [代码]function push({ name, data }) { const dataStr = encodeURIComponent(JSON.stringify(data)); const route = routes[name]; if (route.type === 'tab') { wx.switchTab({ url: `${route.path}`, // 注意tab页面是不支持传参的 }); return; } wx.navigateTo({ url: `${route.path}?encodedData=${dataStr}`, }); } [代码] 搞定,这样我们一个[代码]router.push[代码]就能自动切换两种跳转方式了,而且之后一旦页面类型有变动,我们也只需要修改[代码]route[代码]的定义就可以了。 直接寻址 alias用着很不错,但是有一点挺麻烦得就是每新建一个页面都要写一个alias,即使没有别名的需要,我们是不是可以处理一下,如果在alias没命中,那就直接把name转化成url?这也是阔以的。 [代码]function push({ name, data }) { const dataStr = encodeURIComponent(JSON.stringify(data)); const route = routes[name]; const url = route ? route.path : name; if (route.type === 'tab') { wx.switchTab({ url: `${url}`, // 注意tab页面是不支持传参的 }); return; } wx.navigateTo({ url: `${url}?encodedData=${dataStr}`, }); } [代码] 在页面中使用: [代码]Page({ onLoad(options) { router.push({ name: 'pages/user_center/a/index', data: { isActive: true, }, }); }, }); [代码] 注意,为了方便维护,我们规定了每个页面都必须存放在一个特定的文件夹,一个文件夹的当前路径下只能存在一个index页面,比如[代码]pages/index[代码]下面会存放[代码]pages/index/index.js[代码]、[代码]pages/index/index.wxml[代码]、[代码]pages/index/index.wxss[代码]、[代码]pages/index/index.json[代码],这时候你就不能继续在这个文件夹根路径存放另外一个页面,而必须是新建一个文件夹来存放,比如[代码]pages/index/pageB/index.js[代码]、[代码]pages/index/pageB/index.wxml[代码]、[代码]pages/index/pageB/index.wxss[代码]、[代码]pages/index/pageB/index.json[代码]。 这样是能实现功能,但是这个name怎么看都跟alias风格差太多,我们试着定义一套转化规则,让直接寻址的name与alias风格统一一些,[代码]pages[代码]和[代码]index[代码]其实我们可以省略掉,[代码]/[代码]我们可以用[代码].[代码]来替换,那么原来的name就变成了[代码]user_center.a[代码]: [代码]Page({ onLoad(options) { router.push({ name: 'user_center.a', data: { isActive: true, }, }); }, }); [代码] 我们再来改进[代码]router/index.js[代码]中[代码]push[代码]的实现: [代码]function push({ name, data }) { const dataStr = encodeURIComponent(JSON.stringify(data)); const route = routes[name]; const url = route ? route.path : `pages/${name.replace(/\./g, '/')}/index`; if (route.type === 'tab') { wx.switchTab({ url: `${url}`, // 注意tab页面是不支持传参的 }); return; } wx.navigateTo({ url: `${url}?encodedData=${dataStr}`, }); } [代码] 这样一来,由于支持直接寻址,跳转home和uc还可以写成这样: [代码]router.push({ name: 'index', // => /pages/index/index }); router.push({ name: 'user_center', // => /pages/user_center/index }); [代码] 这样一来,除了一些tab页面以及特定的路由需要写alias之外,我们也不需要新增一个页面就写一条alias这么麻烦了。 其他 除了上面介绍的navigateTo和switchTab外,其实还有[代码]wx.redirectTo[代码]、[代码]wx.navigateBack[代码]以及[代码]wx.reLaunch[代码]等,我们也可以做一层封装,过程雷同,所以我们就不再一个个介绍,这里贴一下最终简化后的api以及原生api的映射关系: [代码]router.push => wx.navigateTo router.replace => wx.redirectTo router.pop => wx.navigateBack router.relaunch => wx.reLaunch [代码] 最终实现已经在发布在github上,感兴趣的朋友可以移步了解:mp-router。
2019-04-26 - 2000万公众号运营者笑了,从此关联小程序再无授权!
似乎很少人发现,在刚刚过去的小假期之前,一个新能力在微信开发者社区突然被官宣了。 公众号关联小程序将无需小程序管理员确认,且小程序可被无限数量的公众号关联。 这是继小程序可无限制内嵌公众号后,公众号又一次「改革开放」,让小程序真正成为公众号的左膀右臂。正如微软小程序高级产品经理张鹏对我们说:“小程序应该要帮公众号的”,这次真的帮大了! 1 公众号关联小程序 不是公众号文章内嵌小程序 标题是不是像绕口令?之所以要重点强调,是因为很多人将这两者混为一谈。 比如,今天就有用户称:这个功能我已经用了好几个月,为什么现在才官宣呢? [图片] 乍一听吓一跳,微信竟然官宣个几个月前上线的功能?经过进一步了解,晓程序观察(yinghoo-tech)发现,原来这位用户是将公众号文章内嵌小程序跟公众号关联小程序,这两个不同的功能混淆了,闹了个大乌龙,真是啼笑皆非。 这也难怪,毕竟这两功能的关系过于密切。 实际上,前一项能力早就在今年2月份就已释放,当时我们判断,小程序与公号的连通性大大加强,因为在公号文章以及自定义菜单栏都可以自由插入小程序,不需要再关联。 [图片] 既然文章内嵌小程序无需关联小程序,乍一看,好像关联不关联都没那么重要了,为什么微信还要将关联授权给取消呢? 这是因为,公众号如果没有与小程序关联,在一些玩法中依然有很多痛点,就像是横亘在二者之间的一根“刺”。 以自定义菜单为例,如果小程序不关联公众号,运营者将无法在自定义菜单栏,设置小程序特定路径,只可以转跳到主页。 比如,某公号在菜单栏底部设置抽奖,用户进入公号点击底部栏进行抽奖时,跳转的将不是抽奖页面,而是抽奖小程序的主页,用户还需要继续查询才能找到该公号的抽奖活动。 以前为了解决这个问题,很多公号运营者不得不找到小程序开发者,索要页面路径,对于一些即时性很强的活动,就会大大影响活动进度。如果想用的小程序是个人类目,运营者很难联系上开发者,工作甚至就此卡住。 现在,微信终于将这颗刺给拔掉了! 此后公号运营者如需关联小程序,只需在后台「小程序管理」 - 「关联小程序」中输入小程序名称/APPID/账号原始ID,即可关联小程序。减少等待小程序管理员确认授权的时间,极大提高工作效率。 不过想要授权,有2个前提: 1、遵守公众号只能关联3个不同主体小程序,和10个同主体的小程序规则; 2、该小程序必须已设置无需关联确认。 [图片] 否则,你的公号将无法关联小程序。 2 小程序无限关联公号 是把“双刃剑”? 众所周知,微信公号是个待开采的流量池,而小程序就是负责开采的机器。两者相结合,公众号呈现内容,引流吸粉,再到小程序转化成交,已经成为创业者轻车熟路的方式。 而小程序关联公众号的大门,并非一开始就彻底敞开,而是遵循用户需求,一步一步地开放。 起初,小程序只能关联50个公众号;之后,该数字拓展到了500个。随着小程序的普及,不少开奖、打卡类工具类小程序备受公号运营者欢迎,此时,用张鹏的话来说,“500个依旧不够,小程序都要开启择优授权公号了”。 于是微信为了解决这一问题,放出一个大招,公众号文章可无限制内嵌小程序了!从那一刻开始,公号运营者如需在文章里内嵌小程序时,只需搜索小程序全称或AppID,就能将小程序内嵌其中。 但这种方式依旧有“限制”,最大的限制莫过于其大大增加了开发者之间的沟通成本。直到现在,微信团队彻底解放小程序关联公众号的“门禁”,小程序终于可以在公众号里随心所欲地穿梭。 不过,一片叫好的同时,不同的声音也不绝于耳。 “别人关联我的小程序,还不用经过我的同意,真的好吗?”某工具类小程序开发者对我们表示。 虽说小程序被更多人知道,被更多公众号关联使用,是一种荣幸。但同时,有开发者发现,不少三俗公号会在小程序里上传一些敏感信息,如果现在他们可以随意关联小程序,可以进行更多操作,这对于开发者而言,显然弊大于利。 据了解,提出“抗议”的开发者已经不少。他们认为,既然登录需要授权、调取信息需要授权,为什么现在关联小程序却不用确认授权了。他们拿出了公众号文章作为举例,“如果转发原创公号文章时,无需不授权也能转发,何谈尊重原创”。 所以我们看到,微信团队在发布这项功能的同时,也给了这类开发者“后路”。如果开发者希望小程序在被关联时保留管理员确认环节,可前往“小程序管理后台-设置-基本设置-关联公众号设置”修改设置项。 当然,辩论的圆桌上有正方就有反方,张鹏就是坚决拥护“无需授权是件好事”的代表:“从本质上说,小程序是一个发布出来的网页,公众号关联我认为确实不需要确认。至于三俗的内容应该由微信的内容审核机制来判断,而不是小程序运营者”。 正反两方辩论得难解难分,站在小程序运营者角度来看,你会怎么看?
2019-04-10 - 2019-04-03
- 新富文本组件
mp-html小程序富文本组件 news欢迎加入 QQ 交流群:699734691示例小程序添加获取组件包功能[图片] 功能介绍 支持在多个平台使用 支持丰富的标签(包括 table、video、svg 等) 支持丰富的事件效果(自动预览图片、链接处理等) 支持锚点跳转、长按复制等丰富功能 支持大部分 html 实体 丰富的插件(关键词搜索、内容编辑等) 效率高、容错性强且轻量化使用方法1. npm 方式 在项目根目录下执行 npm install mp-html 开发者工具中勾选 使用 npm 模块 并点击 工具 - 构建 npm 在需要使用页面的 json 文件中添加 { "usingComponents": { "mp-html": "mp-html" } } 在需要使用页面的 wxml 文件中添加 <mp-html content="{{html}}" /> 在需要使用页面的 js 文件中添加 Page({ onLoad() { this.setData({ html: 'Hello World!' }) } }) 2. 源码方式 将源码中的代码包(dist/mp-weixin)拷贝到 components 目录下,更名为 mp-html 在需要使用页面的 json 文件中添加 { "usingComponents": { "mp-html": "/components/mp-html/index" } } 后续步骤同上 获取github 链接:https://github.com/jin-yufeng/mp-html npm 链接:https://www.npmjs.com/package/mp-html 文档链接:https://jin-yufeng.gitee.io/mp-html
2022-03-04 - 富文本组件体验小程序
简介 上周发布的 新富文本显示组件 收获了许多关注,为方便大家了解和体验,[代码]demo[代码] 小程序上线啦 [图片] 大家可以在这里查看介绍和示例或者进行自定义的测试,发现任何问题都欢迎反馈哦 立即体验 [图片] GitHub链接 Github链接
2020-12-27