更新-移动端BUG管理小程序功能更新

目前,移动端BUG管理小程序已经上线并且保持持续更新,欢迎大家使用!扫描小程序码就可以随时随地进行BUG管理了哦!1.注册/登录如果您是第一次使用MadPecker,可以直接在小程序里完成注册。小程序登录时用的邮箱地址和密码和PC端的一致,而且登录一次之后,下次进入小程序直接进入项目界面,免去了重复登录的烦恼。2.处理BUGMadPecker小程序和PC端数据完全互通,在小程序上可以完成指派、完成、通过、不通过、关闭、再打开等操作。最早做MadPecker的初心,就是为了提高我们自身团队的工作效率。随着MadPecker进一步的成长,我们有了越来越多的产品线以及越来越多的支持者,我们也同样希望这款产品能够多少对您有一点小小的帮助。当然,如果您对我们的平台有哪些意见或者建议的话,欢迎您在我们的公众号后台留言,小啄我看到了之后会及时回复大家。Peace!

July 1, 2019 · 1 min · jiezi

如何用小程序实现类原生APP下一条无限刷体验

1.背景如今信息流业务是各大互联网公司争先抢占的一个大面包,为了提高用户的后续消费,产品想出了各种各样的方法,例如在微视中,用户可以无限上拉出下一条视频;在知乎中,也可以无限上拉出下一条回答。这样的操作方式用户体验更好,后续消费也更多。最近几年的时间,微信小程序已经从一颗小小的萌芽成长为参天大树,形成了较大规模的生态,小程序也拥有了一个很大的流量入口。 2.demo体验那如何才能在小程序中实现类原生APP效果的下一条无限刷体验? 这篇文章详细记录了下一条无限刷效果的实现原理,以及细节和体验优化,并将相关代码抽象成一个微信小程序代码片段,有需要的同学可查看demo源码。 线上效果请用微信扫码体验: 小程序demo体验请点击:https://developers.weixin.qq.com/s/vIfPUomP7f9a 3.实现原理出于性能和兼容性考虑,我们尽量采用小程序官方提供的原生组件来实现下一条无限刷效果。我们发现,可以将无限上拉下一篇的文章看作一个竖向滚动的轮播图,又由于每一篇文章的内容长度高于一屏幕高度,所以需要实现文章内部可滚动,以及文章之间可以上拉和下拉切换的功能。 在多次尝试后,我们最终采用了在<swiper>组件内部嵌套一个<scroll-view>组件的方式实现,利用<swiper>组件来实现文章之间上拉和下拉切换的功能,利用<scroll-view>来实现一篇文章内部可上下滚动的功能。 所以页面的dom结构如下所示: <swiper class='scroll-swiper' circular="{{false}}" vertical="{{true}}" bindchange="bindChange" skip-hidden-item-layout="{{true}}" duration="{{500}}" easing-function="easeInCubic"> <block wx:for="{{articleData}}"> <swiper-item> <scroll-view scroll-top="0" scroll-with-animation="{{false}}" scroll-y > content </scroll-view> </swiper-item> </block></swiper>4.性能优化我们知道view部分是运行在webview上的,所以前端领域的大多数优化方式都有用。例如减少代码包体积,使用分包,渲染性能优化等。下面主要讲一下渲染性能优化。 4.1 dom优化由于页面需要无限上拉刷新,所以要在<swiper>组件中不断的增加<swiper-item>,这样必然会导致页面的dom节点成倍数的增加,最后非常卡顿。 为了优化页面的dom节点,我们利用<swiper>的current和<swiper-item>的index来做优化,控制是否渲染dom节点。首先,仅当index <= current + 1时渲染<swiper-item>,也就是页面中最多预先加载出下一条,而不是将接口返回的所有后续数据都渲染出来;其次,对于用户已经消费过的之前的<swiper-item>,不能直接销毁dom节点,否则会导致<swiper>的current值出现错乱,但是我们可以控制是否渲染<swiper-item>内部的子节点,我们设置了仅当current <= index + 1 && index -1 <= current时才会渲染<swiper-item>中的内容,也就是仅渲染当先文章,及上一篇和下一篇的文章内容,其他文章的dom节点都被销毁了。 这样,无论用户上拉刷新了多少次,页面中最多只会渲染3篇文章的内容,避免了因为上拉次数太多导致的页面卡顿。 4.2 分页时setData的优化setData工作原理小程序的视图层目前使用WebView作为渲染载体,而逻辑层是由独立的 JavascriptCore 作为运行环境。在架构上,WebView 和 JavascriptCore 都是独立的模块,并不具备数据直接共享的通道。当前,视图层和逻辑层的数据传输,实际上通过两边提供的 evaluateJavascript 所实现。即用户传输的数据,需要将其转换为字符串形式传递,同时把转换后的数据内容拼接成一份 JS 脚本,再通过执行 JS 脚本的形式传递到两边独立环境。 而 evaluateJavascript 的执行会受很多方面的影响,数据到达视图层并不是实时的。 每次 setData 的调用都是一次进程间通信过程,通信开销与 setData 的数据量正相关。setData 会引发视图层页面内容的更新,这一耗时操作一定时间中会阻塞用户交互。setData 是小程序开发中使用最频繁的接口,也是最容易引发性能问题的接口。避免不当使用setDatadata 应仅包括与页面渲染相关的数据,其他数据可绑定在this上。使用 data 在方法间共享数据,会增加 setData 传输的数据量,。使用 setData 传输大量数据,通讯耗时与数据正相关,页面更新延迟可能造成页面更新开销增加。仅传输页面中发生变化的数据,使用 setData 的特殊 key 实现局部更新。避免不必要的 setData,避免短时间内频繁调用 setData,对连续的setData调用进行合并。不然会导致操作卡顿,交互延迟,阻塞通信,页面渲染延迟。避免在后台页面进行 setData,这样会抢占前台页面的渲染资源。可将页面切入后台后的setData调用延迟到页面重新展示时执行。优化示例无限上拉刷新的数据会采用分页接口的形式,分多次请求回来。在使用分页接口拉取到下一刷的数据后,我们需要调用setData将数据写进data的articleData中,这个articleData是一个数组,里面存放着所有的文章数据,数据量十分庞大,如果直接setData会增加通讯耗时和页面更新开销,导致操作卡顿,交互延迟。 ...

June 27, 2019 · 1 min · jiezi

笔记实现小程序和H5页面之间互相跳转

一、背景需求背景是这样的,在小程序里面,点击查看用户签订的协议,跳转到协议详情页,刚好协议详情页在另一个H5项目的已经有,所以就想直接跳转过去,避免再开发小程序版本的协议详情页 二、小程序跳转H5页面小程序里面运行H5页面,需要嵌在<web-view></web-view>web-view里面,注意:一个项目只能有一个<web-view></wb-view>。Demo:在小程序里面打开百度网页在小程序项目里面src/pages/新建一个webview的文件夹,含有wxml/wxss/json/js wxml:<web-view src="{{ src }}"></web-view>js:在onLoad里面获取到url这个参数,然后赋值给data,这样在wxml里面就能取到src的值。Page({ data: { url: '', }, onLoad: function (param) { this.setData({ url: decodeURIComponent(param.url), }) }});json/wxss是空文件就可以了。 在小程序的页面跳转到H5页面的写法 wx.navigateTo({ url: '../webview/index?url=https://www.baidu.com/'});这样就成功实现从小程序跳转到H5页面。 三、H5页面返回小程序从H5页面返回小程序页面,需要使用微信SDK提供的跳转方法。 window.wx.miniProgram.navigateTo({ url: `/page/account/index`, });使用微信的SDK方法,需要先发送签名验证wx.config。 四、小程序和H5互跳遇到的坑【问题描述】wx.miniProgram.navigateTo中url无法跳转问题【问题解决】:app.json中配置的tabBar与wx.navigateTo中的url引用相同页面导致 首先pages/account/index这个路径在app.json已经存在,也就是当前从H5页面window.wx.miniProgram.navigateTo(url)的url已经和app.json的一样。此时是不能通过这个方式跳转,而是要改成 window.wx.miniProgram.reLaunch(url) 总结:如果url在app.json已定义,则使用reLaunch跳转,如果没有,则使用miniProgram.navigateTo(url)【问题描述】在小程序里面跳转到H5协议详情页的时候,进入了系统错误页(项目里定义好的错误页),当我现在微信公众号打开该协议详情页,此时再从小程序进入,不会出现。【问题解决】这里我判断是跟登录态有关系,因为我先访问一下公众号,此时浏览器里有了登录态,所以在小程序里面访问协议详情页不会进入系统错误页。 定位问题过程:H5页面是vue页面,先从路由文件/routes/index.js开始debugger,果然就在登录的js里面找到问题,查看登录的js里面有一个先会登出的过程,然后再login(这里是因为不同券商的原因,需要logout清除上一个券商的数据,哈哈,流水账,不然越记越长,不展开咯)在登录logout的过程,此时该cgi抛出异常,刚好被全局捕获,所以进入了系统错误页。 后面的解决方法,是在登出的时候try catch捕获异常,不要把异常被全局捕获。 try {await request('logout.cgi')} catch(e) {console.log('error')}记下问题2,是想跟自己说,bugger经常有,遇到了就一个个地看debugger,看错误来源哪里。谨记在心。

June 25, 2019 · 1 min · jiezi

小程序记录

1、swiper 里可以嵌套videovideo上可以加浮层 利用<view> posization:fixed但: iOS端会有bug,因为iOS的原生video组件层级太高,会出现浮层“消失的状况”小程序的解决方案是提供了<cover-view> <cover-image>但是,如果在video上添加了过多的<cover-view> <cover-image> 会导致ios端视频播放的卡顿以及swiper滑动的卡顿以上可以模拟实现一个上下滑动轮播视频的demo 2、在xml中使用for循环,需要有一个卫衣的key来作为标识wx:for="{{videoData}}" wx:key="{{videoData}}但如果希望不同页面点进来初始化的内容是不一样的就不能在page-data中先声明 可以在onLoad 或者 onShow中声明 3、"navigationStyle":"custom”, 可以声明头部的navigation 导航为透明,只保留右上角的关闭小程序按钮但是这个属性在 webview中无效后续也许小程序会放开,暂时关注着

June 25, 2019 · 1 min · jiezi

小程序云开发遇到的一些问题集合

最近在开始尝试做小程序的云开发。学习云开发主要有以下几个原因: 云开发使用的语言就是js,服务端就是nodejs自己开发小程序的服务端,要自己买服务器,买域名,域名备案,还要配置https,不熟悉怎么配置的人估计会踩很多坑,会花很多的时间。下面记录一下我在云开发过程中遇到的一些问题。 1.小程序端可以直接调用操作数据库的api小程序有云函数和数据库相关的操作,我自己也有做后端,正常的逻辑应该是在后端操作数据库,所以我一开始理解是,小程序端调用云函数,云函数操作数据库,但是仔细看了官方的文档之后,发现可以直接在小程序端调用操作数据库的api。 2.发送模板消息不能定时发送我想做一个每日定时推送消息的一个功能,刚好云函数也直接定时触发,所以每次用户点击的时候就把formId存下来,在云函数里读取formId,再发送模板消息,但是一直不生效,云函数是能定时触发了,但是每次结果都失败了,找了很久,最后才知道,发送模板消息不能在云函数里调用,只能在小程序的发起。希望后面微信能支持云函数定时发送模板消息吧 3.数据库有控制台(需要下载开发版2019.06.20及之后的版本)开发版nightly版本下载链接 4.集合的主键:_id必须是字符串因为一些原因,我需要在某个集合的每条记录里加一个自增的值,所以我把_id设置成了number类型的,然后试了导入数据和云函数新增数据两种方法,试了好久,一直新增不成功,我以为是什么其他的原因,报错的原因也不是很准确,找了很久,通过数据库操作控制台,新增了一个add模板,把需要的新增的数据新增,执行语句之后,这回的报错才是准确的,这回才了解到_id必须是字符串。

June 25, 2019 · 1 min · jiezi

推荐10个堪称神器的小程序

1:1BooK1BooK 是一个精品书籍小程序,一个非常实用并且值得尝试的书籍小程序。 它免费提供了丰富的书籍,你还可以利用小程序的搜索功能搜索你要查找书籍的书名或者书籍作者,从而轻松找到你需要的书籍。 点击任意书籍界面,它提供了内容简介和作者简介,点击右下角的下载链接按钮,就可以轻松复制书籍的下载链接到剪贴板。 2:历史价格查询历史价格查询是一个非常实用的小程序,它可以帮助我们查找任意商品的历史价格和历史价格走势。 我们应该知道很多商家在活动日会采取降价的方法,但是有的商家可能会将商品的价格先升后降,其实商品本身根本没有降价。 这个时候,我们就有必要查询了解我们需要购买商品的历史价格了,我们只需要复制商品链接到这个小程序,它就可以帮助我们查询商品的历史价格走势并且按照图表的方式展现出来,它还会展示历史优惠活动。 3:AI 识别专家AI 识别专家是一个功能强大的 AI 识别小程序。 它支持花草识别,拍照识车,动物识别,菜品识别,面对面翻译,拍照识字:拍照识别身份证、名片、行驶证/驾驶证、银行卡、营业执照。 总之,你不认识的东西,都可以利用这个小程序智能识别。 4:ReadhubReadhub 是一个高质量互联网新闻资讯小程序,它让你每天只需要花几分钟就可以了解互联网行业发生的事情,整个小程序体验非常出色。 它的主要特点就是十分简洁,不管是小程序界面,还是新闻阅读界面;它提供的互联网新闻的质量很高,而且通过一个新闻资讯你还可以看到类似互联网新闻报道;如果你只想专注于高质量互联网新闻,这个小程序会给你很好的阅读和使用体验。 5:微软AI识图微软AI识图是一个非常实用的效率办公小程序。 它支持的功能非常全面:拍照翻译,将单图或者多图转换为 PDF,PPT 和长图,拍图识字,表格还原功能:将图片的表格进行还原,人像功能:识别头像制作成 PPT;你不仅可以直接拍照,也可以对手机上面的任意图片进行上面的操作;并且所有功能免费,识别率也是非常不错。 它的拍图识字功能还可以对识别的字体编辑翻译,导出 Word 等等操作。 6:点学英语点学英语是一个让你在阅读世界名著的同时学习英语的小程序。 首先,它提供的书籍包括世界名著,名人传记,经典小说,而且你也可以利用小程序的搜索功能轻松搜索你想看的书籍。 点击任意书籍,你可以选择全英文阅读,也可以选择显示中文翻译,点击任意英文单词,小程序就可以翻译这个单词的意思并且发音,你还可以将不认识的单词添加到生词本。 利用这个小程序,你不仅可以提高你的英语单词水平,还可以提高你的英语阅读水平。 7:百科知识词典百科知识词典是一个功能强大并且内容丰富的百科知识小程序,是一个你可以学到很多知识的小程序。 它提供的知识词典包括:汉语字典,汉语词典,成语词典,英语词典,汉英词典,诗词词典,菜谱大全,名言警句,迷语词典,歇后语词典,古汉语词典,英汉速查词典,汉英速查词典,英汉简明词典,本草纲目,名人名著。 它还支持强大的手册功能,例如:小学、初中古诗词手册,中国文学常识手册,文言文通假字手册,名言警句手册,英语不规则动词,金融知识。 它还支持强大的图表功能,例如:牛顿运动定律,欧氏几何公理,英语的句子种类,英语的十六种时态,经济学原理,金融市场的分类,证券市场的种类。 它还支持答题功能;总之,这是一款非常好的学习小程序。 8:一席一席是一个高质量演讲小程序,它提供了丰富并且高质量的演讲。 首先,这个小程序提供的演讲质量很高,一席邀请的演讲者都是各个领域颇有成就的人,不同于TED的英文演讲,一席里面的演讲都是让你容易听懂的高质量中文演讲。 它提供的演讲种类也是十分丰富:社会,运动,生活,人生,音乐,环境,设计,历史,艺术,创业,电影,博物,记录,建筑,文化,科技;你可以利用小程序的演讲分类功能和搜索功能轻松找到高质量的演讲。 9:购物决策助手购物决策助手是一个帮助你做出正确的购物选择的小程序。 它主要提供的决策方法是利用几道选择题,帮助你做出正确的购物选择;当你需要购买商品,但是不知道购买哪个牌子,不知道购买哪个型号,打开这个小程序,做几个简单的购物需求选择题,选择题的内容就是你对商品的需求。 当你答题完毕,小程序就会给你推荐多个具体的商品,并且给出这些商品详细的推荐理由和价格。 当你不知道购买具体商品或者对自己的购买需求都不清晰的时候,使用这个小程序参考一下也是一个不错的选择。 10:用药助手用药助手是丁香园出品的一个详细介绍各种疾病需要用的药物的小程序。 首先,这个小程序主要的功能就是详细介绍各种疾病需要使用的药物,它还对各种疾病进行了详细分类,让你可以迅速找到你需要查找的疾病用药;它对各种疾病所需用到的药物也进行了详细介绍:药物成份,适应症,规格,用法用量,不良反应,用药禁忌,注意事项,生产企业等等信息。 它还提供医学计算功能,例如:肾小球滤过率,肌酐清除率,血小板剂量计算,血浆渗透压计算,高血糖的钠校正计算等等。

June 22, 2019 · 1 min · jiezi

小程序生成海报代码分享

今天下午花了一下午时间把之前项目添加了对海报生成的支持 需要的同学可以移步下面链接 https://gitee.com/jgl1210/gen... 本代码实现功能1、海报上添加图片2、海报上添加文字3、海报下载4、海报保存到本地

June 20, 2019 · 1 min · jiezi

微信开放能力笔记

用户点击该按钮时,会返回获取到的用户信息,回调的detail数据与wx.getUserInfo返回的一致,open-type="getUserInfo"时有效 转发获取更多转发信息 通常开发者希望转发出去的小程序被二次打开的时候能够获取到一些信息,例如群的标识。现在通过调用 wx.showShareMenu 并且设置 withShareTicket 为 true ,当用户将小程序转发到任一群聊之后,此转发卡片在群聊中被其他用户打开时,可以在 App.onLaunch 或 App.onShow 获取到一个 shareTicket。通过调用 wx.getShareInfo 接口传入此 shareTicket 可以获取到转发信息。 页面内发起转发基础库 1.2.0 开始支持,低版本需做兼容处理。 通过给 button 组件设置属性 open-type="share",可以在用户点击按钮后触发 Page.onShareAppMessage 事件,如果当前页面没有定义此事件,则点击后无效果。相关组件:button 使用指引转发按钮,旨在帮助用户更流畅地与好友分享内容和服务。转发,应是用户自发的行为,且在需要时触手可及。开发者在使用时若遵从以下指引,会得到更佳的用户体验。 含义清晰:明确、一目了然的图形按钮,将为用户减少理解的时间。在我们的资源下载中心,你可以找到这样的按钮素材并直接使用。或者你可以根据自己业务的设计风格,灵活设计含义清晰的按钮的样式。当然,你也可以直接使用带文案的按钮,“转发给好友”,它也足够明确。方便点击:按钮点击热区不宜过小,亦不宜过大。同时,转发按钮与其他按钮一样,热区也不宜过密,以免用户误操作。按需出现:并非所有页面都适合放置转发按钮,涉及用户隐私的非公开内容,或可能打断用户完成当前操作体验的场景,该功能并不推荐使用。同时,由于转发过程中,我们将截取用户屏幕图像作为配图,因此,需要注意帮助用户屏蔽个人信息。尊重意愿:理所当然,并非所有的用户,都喜欢与朋友分享你的小程序。因此,它不应该成为一个诱导或强制行为,如转发后才能解锁某项功能等。请注意,这类做法不仅不被推荐,还可能违反我们的《运营规范》,我们强烈建议你在使用前阅读这部分内容。以上,我们陈列了最重要的几点,如果你有时间,可以完整浏览《设计指南》,相信会有更多的收获。 Tips不自定义转发图片的情况下,默认会取当前页面,从顶部开始,高度为 80% 屏幕宽度的图像作为转发图片。转发的调试支持请查看 普通转发的调试支持 和 带 shareTicket 的转发只有转发到群聊中打开才可以获取到 shareTickets 返回值,单聊没有 shareTicketsshareTicket 仅在当前小程序生命周期内有效由于策略变动,小程序群相关能力进行调整,开发者可先使用 wx.getShareInfo 接口中的群 ID 进行功能开发。

June 20, 2019 · 1 min · jiezi

微信开放能力微信小程序获取用户信息

微信开放能力 微信小程序获取用户信息 用户点击该按钮时,会返回获取到的用户信息,回调的detail数据与wx.getUserInfo返回的一致,open-type="getUserInfo"时有效 https://developers.weixin.qq.... 请输入代码 <view class="button-wrapper"> <button type="primary" open-type="getUserInfo" lang="zh_CN" bindgetuserinfo="onGotUserInfo">生成请柬</button> </view> onGotUserInfo: function(e) { console.log(e.detail.errMsg) console.log(e.detail.userInfo) console.log(e.detail.rawData) wx.navigateTo({ url: '/pages/haibao/index', success: res => { console.log(res); }, fail: err => { console.log(err); } }) },

June 20, 2019 · 1 min · jiezi

小程序navigateBack传参

小程序中使用navigateBack可以回到上级页面,却无法像navigateTo一样传参,如果想要实现传参,可以通过getCurrentPages这个方法: 假设选择了城市:

June 20, 2019 · 1 min · jiezi

微信小程序开发注意指南和优化实践

前言转眼间已经参与过我厂好几个小程序的开发了,下面本妹子将开发中的那些注意点和各位小伙伴们分享下,妥妥的干货一枚。 一、WXML不要换行写,有空格不行微信开发者工具不会对代码进行trim操作,如果代码中换行,页面也直接换行。 wx:if vs hidden一般来说,wx:if 有更高的切换消耗而 hidden 有更高的初始渲染消耗。因此,如果需要频繁切换的情景下,用 hidden 更好,如果在运行时条件不大可能改变则 wx:if 较好。 图片处理1.大图片也会造成页面切换的卡顿有一部分小程序会在页面中引用大图片,在页面后退切换中会出现掉帧卡顿的情况。2.图片占容量代码包限制是2MB,图片占用空间较大,建议都上传到CDN上,代码里直接引用链接。3.大图片小点击位小程序主要在手机端运行,手机屏幕大小有限,所以尽量点击位大点。4.图片截取存在图片没有按原图宽高比例显示,可以设置image组件的mode属性,来保持原图宽高比。5.CSSSprites所有零星图片都包含到一张大图中,减少请求数 WXS 模块每个 wxs 模块均有一个内置的 module 对象。直接在wxml中引入,可以将写需要转化数据的写进去,防止给setData加负担 使用了过大的 WXML 节点数目一个太大的WXML节点树会增加内存的使用,样式重排时间也会更长,建议一个页面使用少于1000个WXML的节点,节点树深度少于30层,子节点数不大于60个 二、WXSSCss伪类看不到在微信开发者工具中,Styles不会显示Css伪类,喜欢写::before或:first-child的小伙伴们请注意了,你的伪类在控制台是看不到的,所以本妹子不建议在小程序里用Css伪类,以防找不到问题点不好修复bug。 小程序button自带给after伪类添加了边框,通过开发者工具是看不到after,我们需要自行去掉边框。 button::after { border: none;}hover伪类则可以用小程序自带的属性hover-class代替。 部分CSS3属性不能用如transform:rotate(180deg),不能用。 自定义颜色限制不是所以颜色配置都能随心所欲,比如导航栏标题颜色,仅支持 black / white;下拉 loading 的样式,仅支持 dark / light。所以出视觉图关注下。 滚动区域没有开启惯性滚动当加了overflow: scroll时,IOS下需要额外设置: -webkit-overflow-scrolling: touch,来开启惯性滚动。 三、JSJavaScript 支持情况如果需要支持到IOS8话,建议下面js方法都不使用。 分享事件不支持异步如果你想自定义分享图片,则在生命周期onShareAppMessage中编写如下所示: Page({ onShareAppMessage: function (res) { return { title: '自定义转发标题', imageUrl: 'https://blog.frontendx.cn/images/logo.png' } }})但是onShareAppMessage不能支持异步,如果你想从接口里获取分享图片URL,必须在onLoad提前读取并放入Data中 小程序有并发限制wx.request、wx.uploadFile、wx.downloadFile 的最大并发限制是 10 个。 所有为了保险起见,需要写个请求队列,如果并发量大于10,则等待请求。 采用公共方法和组件编写公共方法和组件,可以避免重复造轮子。1.公共埋点方法2.各种处理js的方法(转https,throttle,formatTime等)3.公共组件(iphonex兼容组件,倒计时组件等) ...

June 19, 2019 · 1 min · jiezi

在小程序中实现-Mixins-方案

原文来自我的博客:https://jrainlau.github.io/#/... 在原生开发小程序的过程中,发现有多个页面都使用了几乎完全一样的逻辑。由于小程序官方并没有提供 Mixins 这种代码复用机制,所以只能采用非常不优雅的复制粘贴的方式去“复用”代码。随着功能越来越复杂,靠复制粘贴来维护代码显然不科学,于是便寻思着如何在小程序里面实现 Mixins。 什么是 MixinsMixins 直译过来是“混入”的意思,顾名思义就是把可复用的代码混入当前的代码里面。熟悉 VueJS 的同学应该清楚,它提供了更强大了代码复用能力,解耦了重复的模块,让系统维护更加方便优雅。 先看看在 VueJS 中是怎么使用 Mixins 的。 // define a mixin objectvar myMixin = { created: function () { this.hello() }, methods: { hello: function () { console.log('hello from mixin!') } }}// define a component that uses this mixinvar Component = Vue.extend({ mixins: [myMixin]})var component = new Component() // => "hello from mixin!"在上述的代码中,首先定义了一个名为 myMixin 的对象,里面定义了一些生命周期函数和方法。接着在一个新建的组件里面直接通过 mixins: [myMixin] 的方式注入,此时新建的组件便获得了来自 myMixin 的方法了。 ...

June 19, 2019 · 2 min · jiezi

通过json用canvas生成分享海报支持微信小程序和web

需求在项目里写过几个canvas生成分享海报页面后,觉得这是个重复且冗余的工作.于是就想有没有能通过类似json直接生成海报的库. 然后就在github找到到两个项目: wxa-plugin-canvas,不太喜欢配置文件的写法.就没多去了解mp_canvas_drawer,使用方式就比较符合直觉,不过可惜功能有点少.然后就想着能不能自己再造个轮子.于是就有了这个项目 json2canvas,你可以简单的理解为是mp_canvas_drawer的增强版吧. json2canvas canvas绘制海报,写个json就够了.项目的canvas绘制是基于cax实现的.所以天然的带来一个好处,json2canvas同时支持小程序和web功能支持缩放. 如果设计稿是750,而画布只有375时.你不需要任何换算,只需要将scale设置为0.5即可.支持图片圆角支持圆型,矩形,矩形圆角(背景色支持线性渐变)长文本自动换行(感谢 coolzjy@v2ex 提供的正则 https://regexr.com/4f12l ,优化了换行的计算方式(不会粗暴的折断单词))支持分组(cax里很好用的一个功能)同时支持小程序和web示例demo-web 界面左边的json,可以进行编辑,直接看效果哟~小程序demogit clone https://github.com/willnewii/json2canvas.git微信开发者工具导入项目 example/weapp/小程序安装npm i json2canvas微信开发者工具->工具->构建npm在需要使用的界面引入Component { "usingComponents": { "json2canvas":"/miniprogram_npm/json2canvas/index" }}举个例子想要生成一个这样的海报,需要怎么做?(红框是图片元素,蓝框是文字元素,其余的是一张背景图。) 简单,一个json搞定.具体支持的元素和参数,请查看项目readme { "width": 750, "height": 1334, "scale": 0.5, "children": [ { "type": "image", "url": "http://res.mayday5.me/wxapp/wxavatar/tmp/bg_concerts_1.jpg", "width": 750, "height": 1334 }, { "type": "image", "url": "http://res.mayday5.me/wxapp/wxavatar/tmp/wxapp_code.jpg", "width": 100, "x": 48, "y": 44, "isCircular": true, }, { "type": "circle", "r": 50, "lineWidth": 5, "strokeStyle": "#CCCCCC", "x": 48, "y": 44, }, { "type": "text", "text": "歌词本", "font": "30px Arial", "color": "#FFFFFF", "x": 168, "y": 75, "shadow": { "color": "#000", "offsetX": 2, "offsetY": 2, "blur": 2 } }, { "type": "image", "url": "http://res.mayday5.me/wxapp/wxavatar/tmp/medal_concerts_1.png", "width": 300, "x": "center", "y": 361 }, { "type": "text", "text": "一生活一场 五月天", "font": "38px Arial", "color": "#FFFFFF", "x": "center", "y": 838, "shadow": { "color": "#000", "offsetX": 2, "offsetY": 2, "blur": 2 } }, { "type": "text", "text": "北京6场,郑州2场,登船,上班,听到你想听的歌了吗?", "font": "24px Arial", "color": "#FFFFFF", "x": "center", "y": 888, "shadow": { "color": "#000", "offsetX": 2, "offsetY": 2, "blur": 2 } }, { "type": "rect", "width": 750, "height": 193, "fillStyle": "#FFFFFF", "x": 0, "y": "bottom" }, { "type": "image", "url": "http://res.mayday5.me/wxapp/wxavatar/tmp/wxapp_code.jpg", "width": 117, "height": 117, "x": 47, "y": 1180 }, { "type": "text", "text": "长按识别小程序二维码", "font": "26px Arial", "color": "#858687", "x": 192, "y": 1202 }, { "type": "text", "text": "加入五月天 永远不会太迟", "font": "18px Arial", "color": "#A4A5A6", "x": 192, "y": 1249 }] }问题反馈有什么问题可以直接提issue ...

June 18, 2019 · 2 min · jiezi

一种让小程序支持JSX语法的新思路

React社区一直在探寻使用React语法开发小程序的方式,其中比较著名的项目有Taro,nanachi。而使用React语法开发小程序的难点主要就是在JSX语法上,JSX本质上是JS,相比于小程序静态模版来说太灵活。本文所说的新思路就是在处理JSX语法上的新思路,这是一种更加动态的处理思路,相比于现有方案,基本上不会限制任何JSX的写法,让你以真正的React方式处理小程序,希望这个新思路可以给任何有志于用React开发小程序的人带来启发。 现有思路的局限在介绍新的思路之前,我们先来看下Taro(最新版1.3),nanachi是怎么在小程序端处理JSX语法的。简单来说,主要是通过在编译阶段把JSX转化为等效的小程序wxml来把React代码运行在小程序端的。 举个例子,比如React逻辑表达式: xx && <Text>Hello</Text>将会被转化为等效的小程序wx:if指令: <Text wx:if="{{xx}}">Hello</Text>这种方式把对JSX的处理,主要放在了编译阶段,他依赖于编译阶段的信息收集,以上面为例,它必须识别出逻辑表达式,然后做对应的wx:if转换处理。 那编译阶段有什么问题和局限呢?我们以下面的例子说明: class App extends React.Component { render () { const a = <Text>Hello</Text> const b = a return ( <View> {b} </View> ) }}首先我们声明 const a = <Text>Hello</Text>,然后把a赋值给了b,我们看下最新版本Taro 1.3的转换,如下图: 这个例子不是特别复杂,却报错了。 要想理解上面的代码为什么报错,我们首先要理解编译阶段。本质上来说在编译阶段,代码其实就是‘字符串’,而编译阶段处理方案,就需要从这个‘字符串’中分析出必要的信息(通过AST,正则等方式)然后做对应的等效转换处理。 而对于上面的例子,需要做什么等效处理呢?需要我们在编译阶段分析出b是JSX片段:b = a = <Text>Hello</Text>,然后把<View>{b}</View>中的{b}等效替换为<Text>Hello</Text>。然而在编译阶段要想确定b的值是很困难的,有人说可以往前追溯来确定b的值,也不是不可以,但是考虑一下 由于b = a,那么就先要确定a的值,这个a的值怎么确定呢?需要在b可以访问到的作用域链中确定a,然而a可能又是由其他变量赋值而来,循环往复,期间一旦出现不是简单赋值的情况,比如函数调用,三元判断等运行时信息,追溯就宣告失败,要是a本身就是挂在全局对象上的变量,追溯就更加无从谈起。 所以在编译阶段 是无法简单确定b的值的。 我们再仔细看下上图的报错信息:a is not defined。 为什么说a未定义呢?这是涉及到另外一个问题,我们知道<Text>Hello</Text>,其实等效于React.createElement(Text, null, 'Hello'),而React.createElement方法的返回值就是一个普通JS对象,形如 // ReactElement对象{ tag: Text, props: null, children: 'Hello' ...}所以上面那一段代码在JS环境真正运行的时候,大概等效如下: ...

June 15, 2019 · 2 min · jiezi

Taro-13-震撼发布全面支持-JSX-语法和-Hooks

在 Taro 1.2 发布之后,Taro 在业界收获了巨大的赞誉和关注:GitHub 上 Star 数量超过 19000 粒,NPM 下载量也稳居同类开发框架之首,同时 Taro 团队也和腾讯、百度、华为等数十家业界巨头的研发团队展开了深入和有效的合作。 Taro 1.3 是我们酝酿最久的版本:经历了横跨 6 个月的开发时间,近 2000 次的代码提交,近百位开发者的共同参与。我们终于在今天骄傲地发布了 Taro 1.3。 Taro 1.3 的特性包括但不限于: 支持快应用和 QQ 小程序的开发全面支持 JSX 语法和 React Hooks大幅提高 H5 性能和可用性Taro Doctor支持快应用和 QQ 小程序的开发快应用的开发模式非常特别,它的 API、组件系统、组件库和其他小程序端差异非常大,并且快应用只是一个标准,各家安卓厂商对运行时的实现也各不相同。而这块「硬骨头」终于也被 Taro 啃下了。 QQ 小程序作为新兴的小程序类容器,大家普遍对它知之甚少,但 Taro 也率先实现了对 QQ 小程序的支持。 支持快应用和 QQ 小程序意味着 Taro 真正对业界主流小程序实现了「全覆盖」,不管你的业务要支持哪一个小程序端,只要维护一套代码,Taro 就能生成对应小程序平台的代码。同时 Taro 也成为了业界首个同时支持微信小程序、百度智能小程序、字节跳动小程序、支付宝小程序、快应用、QQ 小程序共 6 端小程序的开发框架。 全面支持 JSX 语法和 React Hooks作为使用 React 和 JSX 语法的开发框架,Taro 早期的版本在编译器和编辑器检查工具都对语法做了高强度的限制。而在 Taro 1.3 中,开发者可以充分发挥自己的创造力和想象力,可以任意地写 if-else,可以任意地写匿名函数,可以把 JSX 放在类函数中,也可以放在普通函数中,等等。只要编译器和和 ESLint 不报错,就可以这么写。 ...

June 14, 2019 · 2 min · jiezi

基于Proxy的小程序状态管理

微信小程序的市场在进一步的扩大,而背后的技术社区仍在摸索着最好的实践方案。我在帮助Nike,沃尔玛以及一些创业公司开发小程序后,依旧认为使用小程序原生框架是一个更高效,稳定的选择,而使用原生框架唯独缺少一个好的状态管理库,如果不引入状态管理则会让我们在模块化,项目结构以及单元测试上都有些捉襟见肘。 目前相对比较稳健的做法是针对redux或者mobx做一个adaptor应用到小程序中,但这样需要自己想办法打包引入外部库,还要想怎么去写这个adaptor,总显得有些麻烦。于是我迸发出一个想法去写一个专用于小程序的状态管理库,它使用起来足够简单并且可以通过小程序自己的npm机制安装。 目前我已经用这个开源库开发了两个电商小程序,在提高我开发效率的同时亦保证了程序的性能,所以接下来我想谈谈这背后的理念以启发更多开发者尝试新的解决方案。 基于Proxy的状态管理实现Proxy在小程序中已经得到了足够好的支持,目前并没有发现在任何iPhone或者Android上不能使用Proxy的情况。而基于Proxy的状态管理其实也就是订阅监听的模式,一方面监听数据的变化,另一方面将这些变化传达给订阅的小程序页面。 举一个比较常见的例子,当一个用户从自己的主页进入用户编辑页面,然后更改了自己的用户名点击保存后,用户主页和用户编辑页上的用户名这时候都应该被更新。这背后的程序逻辑则是:更新这个行为将触发Proxy去通知状态管理库,然后状态管理库负责检查此时还在页面栈中的所有页面,更新订阅了用户名这个数据的页面,如下图: Part1: 监听数据变化监听数据变化其实就是监听各个Store的属性变化,实现上就是在各个Store前面加了一层Proxy,用更直观的图片来表示就是这样: 当一个Store被观察以后,它的属性就都变成了Proxy实例,当这个属性值是Object或者Array的时候,它内部的值也会被包装成Proxy实例,这样无论多深层的数据变动都能被监听到。而在Proxy的后面,Store的属性其实是被另一套数据(紫色部分)所维护,这套数据不负责监听,它就是纯数据,针对属性的任何变动最后都会应用到这套数据上来,它的作用是维护和返回最新的数据。 实现细节: https://github.com/wwayne/min... Part2: 页面数据绑定因为小程序每个页面的js都是向Page中传递一个对象,这就让我们有机会包装这个对象,从而实现: 进入页面后,将页面保存在页面栈中将来自状态管理库的数据映射到这个页面的data上来页面退出时,将页面从页面栈中移除实现细节: https://github.com/wwayne/min... Part3: 页面订阅更新当数据被监听到变化后,我们需要依次做两件事,先是找到所有存储在页面栈里的页面,然后根据各个页面订阅的数据来检查变化,如果有变化就通知这些页面,从而让它们去触发setData更新页面。 实现细节:https://github.com/wwayne/min... 使用状态管理的例子有了状态管理库,现在我们就来实现一开始举例的更新用户信息的操作,我们的文件路径如下: stores/ user.jspages/ userEdit/ index.js index.wxml1.首先我们创建一个Store保存用户的信息,并且监听它的变化: // stores/user.jsimport { observe } from 'minii'Class UserStore { constructor () { this.name = 'bob' } changeName (name) { this.name = name }}export default observe(new UserStore(), 'user')2.接着在我们的小程序页面订阅Store的信息 // pages/userEdit/index.jsimport { mapToData } from 'minii'import userStore from '../../stores/user'const connect = mapToData(state => (({ myName: state.user.name}))Page(connect({ updateNameToJames () { userStore. changeName('james') }}))3.完成,现在可以在页面中使用和更新数据了 ...

June 14, 2019 · 1 min · jiezi

智汇驾考小程序

智汇驾考小程序,适用于驾考科目一,科目四考题的练习,覆盖驾驶证和资格证的考试,包括小车,货车,客车,摩托车,教练员,客运,货运,危险品,出租车,网约车等车型。功能包括:练习,答题,错题集,图标速记。练习功能分为答题模式和背题模式,答题模式可以在答完题目显示正确答案和帮助提示,可以进行跳题作答,背题模式可以直接查看正确答案和帮助提示,实时查看答题卡,统计答题情况,记忆功能,能够继续上次答题,也可以清除答题记录,重新答题。答题功能主要包括倒计时功能,随机取题功能,可以进行跳题作答,交卷评分,倒计时自动提示交卷。记忆功能,保存可下次继续做题。错题集功能主要是针对练习和答题两大模块的作答错题进行分类收集,可像练习功能一样进行答题模式和背题模式的作答方式,可移除错题,具有针对性的答题。图标速记功能,可展示各种交通图标,分类显示,可进行滑动显示,增强记忆。本程序还搭配管理后台,管理用户,可以随时更换套题,增加题目,编辑题目,删除题目,以及使用模板批量的导入题目,查看反馈意见等,非常方便实用!

June 11, 2019 · 1 min · jiezi

小程序位置授权处理

这两天在做小程序调取地图的时候遇到一个问题,如果用户第一次拒绝了位置权限请求。那么就不会再次唤起授权弹出。需要我们引导用户去开启。 具体做法如下。在 aap.json中加入授权配置 "permission": { "scope.userLocation": { "desc": "你的位置信息将用于小程序位置接口的效果展示" } }在 page页面中使用,需要有几个注意的地方,初次使用的时候,去申请权限。这里我是放在onShow 方法里面。 onShow: function () { //初始获取定位权限 wx.authorize({ scope: 'scope.userLocation', success: (res) => { }, }) },然后在调用地图地位。或者获取用户权限的函数去判断是否有定位权限,如果没有那么引导用户开启权限。如下:我有一个Input去触发选择地图事件。 <input bindfocus="openMap" value='{{address}}' placeholder="点击选择详细地址"></input>事件处理 openMap:function(e){ var that = this wx.getSetting({ success(res){ //这里判断是否有地位权限 if (!res.authSetting['scope.userLocation']) { wx.showModal({ title: '提示', content: '请求获取位置权限', success:function(res){ if(res.confirm==false){ return false; } wx.openSetting({ success(res) { //如果再次拒绝则返回页面并提示 if (!res.authSetting['scope.userLocation']) { wx.showToast({ title: '此功能需获取位置信息,请重新设置', duration: 3000, icon: 'none' }) } else { //允许授权,调用地图 that.chooseMap() } } }) } }) } else { //如果有定位权限,调用地图 that.chooseMap() } } }) }, chooseMap(){ var that = this wx.chooseLocation({ success: function (res) { that.setData({ address: res.address, latitude: res.latitude, longitude: res.longitude }) }, fail: function (res) { console.log(res) } }) },原文地址 ...

June 11, 2019 · 1 min · jiezi

BeautyWejs-一套专注于微信小程序的开发范式

一个简单的介绍BeautyWe.js 是什么? 它是一套专注于微信小程序的企业级开发范式,它的愿景是: 让企业级的微信小程序项目中的代码,更加简单、漂亮。为什么要这样命名呢? Write beautiful code for wechat mini program by the beautiful we!「We」 既是我们的 We,也是微信的 We,Both beautiful! 那么它有什么卖点呢? 专注于微信小程序环境,写原汁原味的微信小程序代码。由于只专注于微信小程序,它的源码也很简单。插件化的编程方式,让复杂逻辑更容易封装。再加上一些配套设施: 一些官方插件。一套开箱即用,包含了工程化、项目规范以及微信小程序环境独特问题解决方案的框架。一个CLI工具,帮你快速创建应用,页面,组件等。它由以下几部分组成: 一个插件化的核心 - BeautyWe Core 对 App、Page 进行抽象和包装,保持传统微信小程序开发姿势,同时开放部分原生能力,让其具有「可插件化」的能力。一些官方插件 — BeautyWe Plugins 得益于 Core 的「可插件化」特性,封装复杂逻辑,实现可插拔。官方对于常见的需求提供了一些插件:如增强存储、发布/订阅、状态机、Logger、缓存策略等。一套开箱即用的项目框架 - BeautyWe Framework 描述了一种项目的组织形式,开箱即用,集成了 BeautyWe Core ,并且提供了如:全局窗口、开发规范、多环境开发、全局配置、NPM 等解决方案。一个CLI工具 - BeautyWe Cli 提供快速创建应用、页面、插件,以及项目构建功能的命令行工具。并且还支持自定义的创建模板。一个简单的例子下载 用 BeautyWe 包装你的应用 之后,你就能使用 BeautyWe Plugin 提供的能力了。 开放原生App/Page,支持插件化new BtApp({...}) 的执行结果是对原生的应用进行包装,其中包含了「插件化」的处理,然后返回一个新的实例,这个实例适配原生的 App() 方法。 下面来讲讲「插件化」到底做了什么事情。 首先,插件化开放了原生 App 的四种能力: ...

June 10, 2019 · 4 min · jiezi

使用taro开发小程序我遇到的坑-欢迎各位大侠补充

在开发小程序的技术选型上,我选择了taro + taro ui + typescript, 整理了一下我在开发小程序时候遇到的一些问题,后续持续更新,也欢迎大家补充taro 官网taro-ui 官网 一: 怎么加入第三方字体库? 在这里我使用的是阿里的iconfont 1)在iconfont官网新建自己的项目,并且将需要的字体加入到新建的项目中,查看该项目,可以看到如下页面: 2)点击下载到本地,解压后我们选择iconfont.css加入到自己的开发项目中 3)修改.css后缀为.scss(因为项目中用的是scss), 打开iconfont.scss文件,我们可以看到以下内容 @font-face {font-family: "iconfont"; src: url('iconfont.eot?t=1560144283341'); /* IE9 */ src: url('iconfont.eot?t=1560144283341#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAaQAAsAAAAADRwAAAZEAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDQAqMcIpAATYCJAMYCw4ABCAFhG0HfRsTC1FUbfJkPzV5ggizAQXawIIgxu1RDgAAgAQFIC0AxMP/r/1+n3vHmId4U2vQPWoiRBKLRCIkSBC9UTolE4r+/uv8ufb2CkCqKUhiXEg2+ZTFIrtONaCjO3bHek84VECy9jr/Otv/EdpYPZVTm1BtUEnSFnFtwRvwyLlN4A1i07lPvBuxBEbmvn6/Vk81NGzxdqUQ43vfFxVLLkmn3xCSuKSIV0Kjdhada8KcpYAzYqxx7MueT6A1LYPXYVPHAAQq1IEBtS6ZIkDgRpRiwR6a0IrYtxAP4KdJd942gHvz/vEP8iKQpMzqC51dNMpQ85XznfqsP6ybyOuwLpeA8CAyNoGCuCaTrvhMuGmCWmplX/tAq5EkqZYV3zu/04eOlUIRnyikbdjbilYI/fOiUgf1g/qouOQrp/Mn8VXBUsGdEKGAYAUiZAimwH+lsEqwYB6kdYx+hNq0ablaqU+lXlySVtuaTMwkjGFYliFd7miaUg1YHKeNMXTMgddyCZWf4/CiL+nMm0+xIKhIGoSlPUvpn10JWEn3EkbTQiq5Q9LO6bAcVKhdK6WgJHfa19Mj9vb6uruFri4eoj1N6Rbd9yAYCDtFNVQnsYISrD5GhtWQRlFSa+8PF3odOVKRUpSgTJJHI2qDzKm/hmR3ZVR3nTeDcF9YhTCkSQoA6zKzpt+qppT1LksTXrfF7Kl4hYSFHdNprI8VtE8zv+uMR5NTn8VDdelMRY0HM1XWnghWp5A4JdWA44+7o6BQLs0F1bADiKrsAA/jlNJCThLqxLAMKG+SyycoLBkKtEoHLx5P+whSfq5g4Y0omBB+larl5foy6S8f4UV+nk/wbYCkz1T+0T0h51MqE5lPG8xIFYXmfvbTIKxoJ5ML6RMvby0B8uICwTfvGP32OyXNoKTnbFRe7cZyalKZjVDqjbbPa1bVReO5tWlIv20Rlv9xOw0svy98jtt97vOi/JaD814YgWu/ZX/r8DHUf78EdbCJ0G060YRwnPWl1cvZHtu8UxNrsNZWR0i36IT7RF0V8F6OalQ5tszQND88fx4GoF9n+JEAktr8MFA+AIHuhYGB9BLnLeMFHPAHIAe9isBK4P4lnXPsWI4nOcqTPagPPiRlGXWrbsRlU1et3mR4iC5ZMnFgIkaiXydsuJllaomGxWDrVrjka0uG5MVgYOOkj7Lmrd6Xu2L2+ti/GX9vaoROhIiINaKn6r+M6cudfHgyQhw0bdrYvjVYa60jtn7Vww4SETClg5v4wr0/OP6UGOuN+59eNrL3O3a56tnIwvGFtdiwZ2Fk0AEnneiZyOqOyxn4eXzN9I3TDAmnDedJF+nvKf6vz+P7s9cWu4q9Sd5ipyaQsBbfzyu3XybSY/lm++knYchtOUtuzCI499I0a1q/N8FlUaWk5az72MN75DA7TAYxxKW1krbeHuai/4ym3l7wv03fsWuXqgwf9IBNTl7tfz4/f/sWzqcEQ7t1/upHMQNY+Y8QHOfT/7iaADX8PIAjSO5c6eDAu5dcAQVxdfO8D/D+/dupraovXtjAd84jba93XnZkT8B++H5AT871S0+8zjkvokbRbjfk8UtBNV5wjV2S4PkWsHpM/m/XhjR1n4t6VIARWingFpYBOqI/rwHozoc+SQBd+dynhCIa1w3natez/P4zaTqi4j6Q+ifP+kwPPsLMTgF81ukFyzk3yjG7FIVQY1X2qmNZ7pVHEJSScJDt3GbaqC9SsRNkS0JjYgVJbQqyxqK8UG9CqWcbKo0daG1oPrhnjM5HFH1Yt6MgDHsMyaAPyIZ9lBfqz1Ca9A8qw+EDrfOIOWbPcrDgeh0LJpaRuICYxD2kjTWDx9p9WLFcgr4uGJchrBssF+Vm5WyXNmMP1iV2MGaVPNMkiOjcjZrUxbDLxZGqcweWzCxqmmpZdjahdsySuBuCHdBhAlP7lCGiBUdGwnmQmU3BO2/fB1NYXAT6Qqe54xBMZ2BLR3JlyWHIm4M8rE7vpaFhliKPiQkE6lrqODekCRMwV1PEISq9lgMmMWWhFgWqMtnYE+EGZV0/xP0rL4JWfcwqUuQooowqakM3VOCiJfcRDvadKvCQRWoJ8SrEmrOCPHjOmP446yaqmC1SRrFEBQ6KFi2ZwEMNbhmWXSQA') format('woff2'), url('iconfont.woff?t=1560144283341') format('woff'), url('iconfont.ttf?t=1560144283341') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ url('iconfont.svg?t=1560144283341#iconfont') format('svg'); /* iOS 4.1- */}.iconfont { font-family: "iconfont" !important; font-size: 16px; font-style: normal; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;}.iconzhaobudaojieguo:before { content: "\e668";}为了项目结构的干净,我把icon单独抽成了一个文件夹 ...

June 10, 2019 · 2 min · jiezi

史上最全的微信小程序代码大全源码下载

 小程序QQ交流群:131894955   开发文档: http://wepydemo.mydoc.io 小程序CMS官网源码下载 源码链接: https://gitee.com/jeecg/jeewx... JAVA版微信管家平台(各种微信活动、公众号管理) 源码地址: https://gitee.com/jeecg/h5huo... 微信小程序实例源码大全下载 微信小应用示例代码(phodal/weapp-quick)源码链接:https://github.com/phodal/wea... 微信小应用地图定位demo(giscafer/wechat-weapp-mapdemo)源码链接:https://github.com/giscafer/w... 微信小应用- 掘金主页信息流(hilongjw/weapp-gold)源码链接:https://github.com/hilongjw/w... 微信小程序(应用号)示例:微信小程序豆瓣电影(zce/weapp-demo)源码链接:https://github.com/zce/weapp-... 微信小程序-豆瓣电影(hingsir/weapp-douban-film)源码链接:https://github.com/hingsir/we... 小程序 hello world 尝鲜(kunkun12/weapp)源码链接:https://github.com/kunkun12/w... 使用微信小程序开发2048游戏(sammffl/wechat-weapp-2048)源码链接:https://github.com/sammffl/we... 微信小程序-微票(wangmingjob/weapp-weipiao)源码链接:https://github.com/wangmingjo... 微信小程序购物车DEMO(SeptemberMaples/wechat-weapp-demo)源码链接:https://github.com/SeptemberM... 微信小程序V2EX(jectychen/wechat-v2ex)源码链接:https://github.com/jectychen/... 微信小程序-知乎日报(myronliu347/wechat-app-zhihudaily)源码链接:https://github.com/myronliu34... 微信小程序-公众号热门文章信息流(hijiangtao/weapp-newsapp)源码链接:https://github.com/hijiangtao... 微信小程序版Gank客户端  源码链接:https://github.com/lypeer/wec... 微信小程序集成Redux实现的Todo list  源码链接:https://github.com/charleyw/w... 微信小程序-番茄时钟  源码链接:https://github.com/kraaas/timer 微信小程序项目汇总  源码链接:http://javascript.ctolib.com/cat ... t-wechat-weapp.html 微信小程序版聊天室  源码链接: https://github.com/ericzyh/we... 微信小程序-HiApp  源码链接: https://github.com/BelinChung... 小程序Redux绑定库  源码链接: https://github.com/charleyw/w... 微信小程序版微信源码链接:  https://github.com/1838043547... 小程序开发从布局开始源码链接:  https://github.com/hardog/wec... 微信小程序-音乐播放器 源码链接: https://github.com/eyasliu/we... 微信小程序-简易计算器-适合入门源码链接: https://github.com/dunizb/wxa... 微信小程序-github 源码链接:  https://github.com/zhengxiaow... 微信小程序-小熊の日记 源码链接:  https://github.com/harveyqing... 微信小程序源码链接: https://github.com/SeaHub/Pig... 微信小程序(WeChatMeiZhi妹子图)源码链接:https://github.com/brucevanfd... 使用方法 1、克隆项目代码到本地(git应该都要会哈,现在源码几乎都会放github上,会git才方便,不会的可以自学一下哦,不会的也没关系,gitHub上也提供直接下载的链接)2、打开微信开发者工具;3、添加项目->选择本项目目录->编译执行;

June 8, 2019 · 1 min · jiezi

小程序开发框架

微信团队开发的wepy写的文档就挺好的较为易于阅读 https://tencent.github.io/wepy/https://tencent.github.io/wep...

June 6, 2019 · 1 min · jiezi

小程序授权操作

<!--pages/album/index.wxml--><view class='page-wrapper'> <view class='image'> <image class="img" src="/images/IMG_0031.jpg" mode="aspectFill"></image> </view> <view class='name'> 新郎:李翔宇;新娘:刘嘉琦 </view> <view class='info'> 谨定于2019年6月18日中午12点举办婚礼 </view> <view class='info'> 欢迎大家光临 </view> <view class="button-wrapper"> <button type="primary" open-type="getUserInfo" lang="zh_CN" bindgetuserinfo="onGotUserInfo">生成请柬</button> </view> </view>//index.js//获取应用实例const app = getApp()Page({ data: { motto: '欢迎您的到来', userInfo: {}, hasUserInfo: false, canIUse: wx.canIUse('button.open-type.getUserInfo') }, //事件处理函数 bindViewTap: function() { wx.navigateTo({ url: '../logs/logs' }) }, onGotUserInfo: function(e) { console.log(e.detail.errMsg) console.log(e.detail.userInfo) console.log(e.detail.rawData) wx.navigateTo({ url: '/pages/poster/index', success: res => { console.log(res); }, fail: err => { console.log(err); } }) }, onLoad: function () { if (app.globalData.userInfo) { this.setData({ userInfo: app.globalData.userInfo, hasUserInfo: true }) } else if (this.data.canIUse){ // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 // 所以此处加入 callback 以防止这种情况 app.userInfoReadyCallback = res => { this.setData({ userInfo: res.userInfo, hasUserInfo: true }) } } else { // 在没有 open-type=getUserInfo 版本的兼容处理 wx.getUserInfo({ success: res => { app.globalData.userInfo = res.userInfo this.setData({ userInfo: res.userInfo, hasUserInfo: true }) } }) } }, getUserInfo: function(e) { console.log(e) app.globalData.userInfo = e.detail.userInfo this.setData({ userInfo: e.detail.userInfo, hasUserInfo: true }) }})

June 5, 2019 · 1 min · jiezi

免费开源小程序公众号商城

免费开源小程序+公众号商城,代码易读,功能完善,基于thinkphp5开发,支持一键安装。源码地址: http://github.crmeb.net/u/blue体验地址:

June 4, 2019 · 1 min · jiezi

小程序开发工具调查

Photo by Adeolu Eletu on Unsplash调查时间为2019年05月上旬进行 目前开发小程序可选方案有以下几种方式: 基于小程序开发工具进行原生开发(简称:原生开发)基于构建环境进行开发,并转换为小程序原生代码(简称:构建式开发)原生开发由于设计问题需要管理大量文件导致开发过程不流畅(如创建一个组件需要新建三份文件编写代码);更多的问题是JS新特性不支持、css样式不支持Less/Sass,也不能灵活运用npm包管理(尽管新版本提供了支持);细说就是上面那些问题,对于日常开发的前端工程师来说却是需要重视的,这类问题得不到解决,开发及维护成本是高昂的!现代的前端工程师日常开发场景已经常常使用ES6/7的新特性(甚至有些习惯使用TypeScript),然后要让这些人回头使用老旧的方法写代码,只能说工作成本太高了。结论:不推荐用原生开发,除非你的程序足够简单。 原生开发的缺点构建式开发都能解决,而且还提供常用的语境,更能使前端工程师更快更高效地进行开发工作(基于MVVM框架开发的语境)。下面是一些收集来的开发环境: wepy一个最受欢迎的小程序框架。基于vue开发风格。mpvue是一个使用 Vue.js 开发小程序的前端框架。基于vue开发风格。taro是一套遵循React语法规范的多端统一开发框架。基于react开发风格mpvue可能文档不是那种容易阅读的类型,没看下去先弃置;微信团队开发的wepy写的文档就挺好的较为易于阅读,框架把原生开发的多文件结构改为了单文件并提供使用一些JS的新特性(基于Babel),不得不提的缺点是它无法循环渲染自定义组件(虽然在1.7.2-alpha4已经支持),还有一点,在wepy官方的仓库中找关于循环渲染自定义组件的issues时发现另一个问题:数据多的时候性能较差的情况(具体看wepy是否可以作为一个正式项目的工具使用? 项目规模起来后如何优化? (issues#1673));而刚好@kdong007在issues中提到taro解决了wepy的问题让我对taro提起了兴趣。虽然不懂reart也考虑尝试一波;taro是一套遵循React语法规范的多端统一开发框架,能一键生成可以在微信小程序/H5/ReactNative等端运行的代码,还支持TypeScript自家也有taro-uiUI库,文档易读容易定位问题,多个库的版本管理也不像wepy那样不统一。在v1.3.0-beta-0之后还支持React Hook方式编码,让我这个React新人也想尝尝鲜! 除了开发环境,UI库的支持选择也是很重要的,目前使用较为广泛的有以下这些: weui-wxss WeUI WXSS是腾讯官方UI组件库WeUI的小程序版,提供了跟微信界面风格一致的用户体验iview-weappiView是TalkingData发布的一款高质量的基于Vue.js组件库,而iView weapp则是它们的小程序版本vant-weapp Vant Weapp 是有赞移动端组件库 Vant 的小程序版本,两者基于相同的视觉规范,提供一致的 API 接口,助力开发者快速搭建小程序应用。minui 基于规范的小程序 UI 组件库,自定义标签组件,简洁、易用、工具化taro-ui 一套基于 Taro 框架开发的多端 UI 组件库weui-wxss,iview-weapp,vant-weapp和minui都是基于原生开发的UI组件库,想用于wepy环境下可以参考一波minui推荐的处理办法(min-cli文档 - 结合WePY)。主要是两点:UI组件库文件放在小程序项目目录下;在页面设置config.usingComponents={'van-button':'../components/vant/button/index'}来注册组件。如果你还抱有疑问,可以围观这个issues。至于taro-ui必须和taro组合使用,环境相对封闭但是功能无可挑剔,毕竟能生成至weapp/H5/RN。 结语:睇餸吃饭,兄弟!按自己需要来选择用什么方式开发小程序吧!祝各位好运!我就继续研究一下这个taro怎样搞,哈哈XD

June 3, 2019 · 1 min · jiezi

拆弹时刻小程序canvas生成海报二优化方案

海报生成速度缓慢问题的优化 微信头像在app.js中预先加载缓存多图片异步加载流程中断处理 二次授权失败的处理请求或者下载图片失败处理保存图片可被压缩海报生成速度缓慢问题的优化原因分析: 主要的时间消耗在于getImageInfo网络请求获取头像和下载图片获得临时地址的过程,可以看到海报中有3张图片(微信头像、主图、动态二维码(对应不同新闻的ID))需要下载,接下来主要就是对这3张图的优化 微信头像在app.js中预先加载缓存//app.js//可以在app.js中使用小程序默认的全局变量,将头像在加载的时候预先缓存App({ onLaunch: function () { // 获取用户信息 wx.getSetting({ success: res => { if (res.authSetting['scope.userInfo']) { // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框 wx.getUserInfo({ success: res => { this.globalData.userInfo = res.userInfo; //从返回值中获取微信头像地址 let WxHeader = res.userInfo.avatarUrl; wx.getImageInfo({ src: WxHeader,//下载微信头像获得临时地址 success: res => { //将头像缓存在全局变量里 this.globalData.avatarUrlTempPath = res.path; }, fail: res => { //失败回调 } }); } }) } } }) }, globalData: { userInfo: null, //如果用户没有授权,无法在加载小程序的时候获取头像,就使用默认头像 avatarUrlTempPath: "./images/defaultHeader.jpg" }})大致思路是: 加载App.js的时候==> getSetting(判断是否授权) ==> getUserInfo(获取头像) ==> getImageInfo(生成临时地址) 将需要的网络请求在加载小程序的时候就异步完成,提前将临时地址缓存在全局变量globalData中,这样当用户进入新闻页面,点击生成海报的时候就不需要在请求微信头像,缩短了不少时间。 注意: 如果用户一开始没有微信授权,生成海报时又必须要用户头像不能使用默认的话,那就只能老老实实走之前的流程了。 ...

May 31, 2019 · 2 min · jiezi

gulp构建小程序

目前来说,对于构建小程序的,类似taro这些框架,生态已经挺完善的了,没有什么必要再搞一套来折腾自己。但是,我司的小程序,是很早之前就开发的,我们负责人当时信不过这些开源的框架,于是自己用webpack搞了一套框架,但有一个比较严重的问题,有一些文件依赖重复打包了,导致小程序包体积比较大。 持续了一个多月,主包体积在2M左右徘徊,开发都很难做下去。我们负责人终于受不了了,给了我个任务,让我写一个构建小程序的工具,减少小程序包体积。 我们现在的框架对比一下原生小程序,其实差别不大,无非就是 ts => jssass=>wxsswxml=>wxmljson=>json由于我司小程序基础库是1.9.8的,不支持构建npm,所以node_modules的依赖包以及依赖路径需要自己处理,于是写了一个babel插件 babel-plugin-copy-npm。这么一想,其实不难,而且单文件编译,那不是gulp的强项吗!!! 最终效果: 而且由于增量更新,只修改改变的文件,所以编译的速度非常快。 项目地址:https://github.com/m-Ryan/ry-wx 最终流程大概如下:清除dist目录下的文件 => 编译文件到dist目录下=> 开发模式监听文件更改,生产环境压缩文件。 一、清除dist目录下的文件 (clean.js) const del = require('del');const fs = require('fs');const path = require('path');const cwd = process.cwd();module.exports = function clean() { if (!fs.existsSync(path.join(cwd, 'dist'))) { fs.mkdirSync('dist'); return Promise.resolve(null); } return del([ '*', '!npm' ], { force: true, cwd: path.join(cwd, 'dist') });};二、编译文件 1.编译typescript(compileJs.js)const gulp = require('gulp');const { babel } = require('gulp-load-plugins')();const path = require('path');const cwd = process.cwd();module.exports = function compileJs(filePath) { let file = 'src/**/*.ts'; let dist = 'dist'; if (typeof filePath === 'string') { file = path.join(cwd, filePath); dist = path.dirname(file.replace(/src/, 'dist')); } return gulp.src(file).pipe(babel()).pipe(gulp.dest(dist));};2.编译sass(compileSass.js)const gulp = require('gulp');const { sass, postcss, rename } = require('gulp-load-plugins')();const path = require('path');const cwd = process.cwd();const plugins = [ require('autoprefixer')({ browsers: [ 'ios >= 8', 'ChromeAndroid >= 53' ], remove: false, add: true }), require('postcss-pxtorpx')({ multiplier: 2, propList: [ '*' ] })];module.exports = function compileSass(filePath) { let file = 'src/**/*.scss'; let dist = 'dist'; if (typeof filePath === 'string') { file = path.join(cwd, filePath); dist = path.dirname(file.replace(/src/, 'dist')); } return gulp .src(file) .pipe(sass({ outputStyle: 'compressed' }).on('error', sass.logError)) .pipe(postcss(plugins)) .pipe( rename({ extname: '.wxss' }) ) .pipe(gulp.dest(dist));};编译json,wxml,由于需要压缩,所以需要分开处理(copyJson.js) ...

May 31, 2019 · 3 min · jiezi

小程序webview关闭后页面音频没有关闭

问题描述:在web-view的src中,引入了一个HTML5页面,这个页面有个自动播放的音频。在小程序中,点击右上角关闭小程序后,web-view页面中的音频依然会播放。 期待现象期待关闭小程序之后,音频也停止。 通过查找文档,发现没有直接提供方法,网上找了一圈之后,尝试的方案也都无法实现。 所以我这里想到的思路是,当用户关闭小程序时,应该销毁掉web-view。可惜,目前没有这个接口。 所以我就利用了模拟的方式来实现,当前小程序页面onHide时,就将web-view的页面src属性清空。 后来经过测试发现,在ios平台下,需要制定一个url,在android平台下只需要清空。另外为了防止造成缓存,给url后面添加了一个随机的参数。 以下是代码片段。 <template> <view> <web-view :src="webUrl"></web-view> </view></template><script> export default { data() { return { webUrl: 'https://demo.com/weixin/index.html' } }, onLoad() { }, onHide(){ // webview关闭后,刷新url。否则会造成音乐在后台继续播放的bug if (uni.getSystemInfoSync().platform == "ios") { this.webUrl = 'https://demo.com/weixin/index.html?redirect=true'; }else{ // android系统下只能给空值 this.webUrl = ';' } }, onBackPress(){ }, methods: { } }</script><style></style>

May 30, 2019 · 1 min · jiezi

独家揭秘阿里小程序的一云多端看这篇就够了

摘要: 阿里巴巴小程序一云多端的整体战略,以及阿里小程序后续为开发者提供的云服务(云应用、云开发等)、开发者工具链(IDE、插件、SDK等)、跨端框架能力说明。同时结合繁星计划后续提供给开发者的扶持和ISV的权益体系做一个整体的介绍。专家介绍 视频回放https://yq.aliyun.com/live/1097 阿里小程序的一云多端相信绝大部分同学知道阿里一云多端的项目,最早始于19年三月份在北京云栖大会上,阿里云的CEO在云栖大会上对外发布了一云多端的项目。 一云多端是什么?大家今天常见都是微信小程序,微信小程序实际上是一个变化的体系,在它上面开发一个小程序,只能在微信上跑。是不是可以有另外一种方式,能不能开发一个小程序,比如:我写了前端代码,既能在微信上跑,也能在支付宝、高德、头条、百度、哪里都能跑。 这样对研发同学的成本要低很多,这就是多端的概念。 相比较我们App的生态体系,微信其实类似于iOS,他自己自成了一个闭环。 阿里巴巴想做的事情就是我们希望类似于 Android 这样一个开放联盟,能形成整个除了阿里内部,包括阿里生态公司,包括外部的一些公司,都能共用整个小程序的一个框架,共用小程序的一个体系,这是当时对外宣称要做一云多端目的。 一云指的是什么呢?一云指的是:给大家举个例子,我们今天在做微信的小程序,我们都知道他的ID里其实是有自己的云服务的,那我们在做支付宝小程序的时候,大家也会感知到它其实也是一个闭环。 那我们从业务的视角来看,比如:我作为星巴克的开发者,我肯定希望我后端的服务都供用在我自己的服务里,让所有的端都能供链到我这里,这才是对业务来讲价值最大、最好的一个点。这就是阿里巴巴想强调的一云,通过我们这样整体的云,来支持我们这样所有的端。 这是一个大的背景,具体我们来看一下,微信小程序大概在2016年开始做,差不多历时了三年才有了今天我们看到的小程序这样一个繁荣的生态,真正让大家感知到这样一个风口差不多是在18年,大概是跳一跳那个小程序开始火起来以后,大家才感知到小程序原来可以这么玩,越来越多这样的玩家入驻了。 截止到2018年底,全网的小程序已经超过了200万,整个小程序的开发其实呈现出井喷的现状。 200万是什么概念呢?现场有多少同学知道,当前iOS系统中的 App Store,它里面有多少应用? 据我了解的一个数据 ,18年的时候,整个 App Store 里也才230万个 App 应用。大家看小程序这个行业,才经历了两三年基本已经到了我们这样一个量级,根据我们现在了解的一些调研报告的数据,2019年可能预计会到500万的量级,今年还会有一个很快速增长的过程。 整个微信小程序活跃用户的增长量其实是趋于平缓的,获客成本其实是逐渐逐渐的高起,整个发展的核心已经由传统意义上的拉新到现在更多的是运营。 微信小程序的活跃用户现在已经有7亿多,整个微信App,活跃用户也才10亿到11亿左右,它的天花板其实已经很低了,随时就可以触碰到,在这种背景下,我们作为一个开发者,作为一个企业,其实是希望能够有更多其他平台的拥抱 ,我们可以通过其他的渠道来获取到我们这样的流量。 阿里巴巴正在做的事情是:会全面的拥抱小程序,为小程序提供全面的技术、业务、生态的支持,能够帮助我们的企业在未来的云生态里面走的更远。 下面这张图,是我们刚才介绍的数据: 左边的数据是我们小程序的增长量,17年数据是100多万,到18年已经200多万了,按照我们现在预测的数据,到了2019年可能有四五百万,基本上是每年翻倍的节奏。 右边的数据是全网小程序用户数的规模,大概分布情况是:支付宝大概是四五亿,微信大概是七亿左右,百度大概是两三亿,加在一起应该有十几亿的数据。后续随着越来越多大平台的参与 ,小程序的用户规模也会越来越大的。 具体到阿里巴巴,我们有一些面向场景主流的端,比如:我们面向电商购物场景的淘宝,面向出行领域的高德,面向我们金融和本地生活的支付宝,面向这种企业服务这块的钉钉,这些端都会全面的拥抱小程序。 具体这些端后面会做什么,接下来几位讲师会和大家详细分享,我们在不同端里,小程序具体是什么样的玩法?会给我们的开发者提供什么样的业务能力?我在这里就不做太多的介绍了。 对于个人开发者,对于企业而言,当前阿里在做的一云多端对我们来讲有什么价值,对我们来讲有什么样的机会,我们可以看一下这张图。 我们传统意义上讲,大家其实都知道小程序,大家能感知到的就是微信,因为只有这样一个声音,后续我们期望能让大家知道小程序不只等于微信小程序, 阿里其实也会有相应的能力。除了阿里以外,大家已经知道的,像今日头条,像百度也都陆陆续续加入了小程序战场,后续小程序真的不等于就是微信小程序了,全网主流平台都会去做支持。 其次我们传统意义上,小程序在微信覆盖的用户群体,覆盖的场景以社交场景为主,后续随着更多的App和场景的加入,我们的小程序基本上可以覆盖全场景,不仅仅是当前的社交 ,我们有支付场景、有金融场景、有出行场景、有企业服务场景,有越来越多的场景。随着阿里小程序战略的演进,后续会把阿里小程序的开发框架、开发标准对外开放,除了阿里内部小程序能用以外,整个阿里系的一些App,比如:像微博等一些App都可以直接运行阿里的小程序。再往后会把开发框架开放给企业自己的App,可以真正的做到一个小程序在全网都能跑,能支持全网的用户覆盖。 基于这样的背景,现在这样流量红利,如果我们不仅仅看微信的话,流量红利其实又有一波已经进来了,不仅仅是微信平台,现在全网已经有十几个小程序的平台在加入到战场,整体的活跃用户现在已经能突破十亿以上,这种小程序的入口其实也很多。 从场景上来说:除了像微信社交场景以外,电商的LBS、搜索、内容,能覆盖的场景也是会越来越多的。 对企业而言,对个人开发者而言,价值在于:现在中国这个人口红利已经逐渐的消失了,如果自己做一个App,获客成本其实已经很高了,即使是微信小程序做了这么长时间,微信小程序的获客成本也是越来越高。 我们如何来降低获客成本,一个比较好的方式就是借助不同App平台,通过不同的小程序平台来获取我们的流量扶持,能够通过低成本的方式来获取我们的客户,这是一个我们价值点所在。 不同的这个App有不同的业务能力,比如:高德,大家更多的就是用它的LBS能力,我们可以获得位置,出行数据等等,可能这些能力你在微信里是获取不到的,每个不同的开发者,所面向的场景是不一样的,所要的业务能力也是会有比较大的差异的。如果可以借助平台的这个业务的赋能,让业务场景能够快速的扩展,这对大家来讲是一个比较好的机会。 从阿里本身的经济体而言,其实会给不同的开发者提供业务的赋能,比如:一些API的能力,地图的API、商家的API、风控的API、支付的API,我相信大部分的开发者可能更多的都是奔着更好用的业务能力来的。 对企业大的战略而言,也有几个比较好的点。一个点是前面说的,微信小程序的获客成本已经逐渐提高了,其他一些平台属于刚起步的阶段,流量其实相对来讲还属于比较充沛。如果能抓住这样的机会,能早一点进去,流量的获客成本相对比较低的,业务的扶持也能让自身的小程序,自身的业务有快速的发展。 通常情况下,大家都知道,鸡蛋不要放在一个篮子里,因为放在一个篮子里风险是比较高的,如果我们把所有的业务全部承载在微信的小程序里,万一微信的小程序开发的规则以及的业务变化,实际上对大家自身的业务影响是很大的,甚至是致命的影响。多元发展其实是所有开发者,所有企业都必须考虑这样的点,今天刚好也确实是有这样的机会。 多端小程序的价值多端小程序对大家到底有哪些核心的价值? 第一个是场景,在于我们传统意义上讲微信,更多的是我们有人际关系的关系链在微信上,其他的场景,比如:我是做汽配相关的,这时候我在微信上很难获取到适合的用户群体。 我不知道大家有没有看过一份数据:现在支付宝、微信、百度的小程序的留存率,从数据上看,支付宝的小程序留存率是最高的,为什么呢?原因在于支付宝是一个场景化的App,它主要面向的是一个支付的场景和本地生活化的场景,大家用这个App的时候其实就是它的目标用户群体,基于这个场景来开发App,其实就很容易获客,如果我们的业务其实做的还ok的话,这批用户的留存和后续的转化其实是很高的。 第二个是流量的价值,流量的价值在于由单一的微信生态流量逐渐转变为全网的流量,因为我们有越来越多的App加入到小程序的战场。除此之外,像阿里内部的高德、钉钉、淘宝是有大量的企业能力,大量的设备能力的数据在里面,通过这些能够帮助大家更好的获取流量。 第三个是业务,相比较其他的平台,阿里的一个很大的优势在于相对的业务能力板块是比较全的,金融支付能力、企业的服务能力、物流能力,一系列的能力都可以帮助大家来做赋能,让大家更好更快的开发自己的业务。 第四个是用户粘性,之前数据也举例了,大家通过单一渠道来获取以及通过社交渠道来获取的流量,相对来讲粘性是比较差的,因为它使用的场景是面向我们当前社交的,我们跟朋友的聊天,不大会关注其他的场景,可能也有一定的转化,但这个转化率一定是不高的。如果是奔着特定场景的,相对来讲这个粘性要高很多。 第五个是成本,一个产品它的生命周期如果从刚起步到成熟到后续的衰落,那么微信当前就处于偏成熟的阶段,这时候大家认知的很多,使用的人也很多,很多人去抢那一点流量,成本逐渐越来越高,如果有一个新的战场,一片新的领域,大家能早一点有机会进去,这个时候获客成本其实是很低的。 第六个是品牌的效应,我们可以让整个小程序的品牌,能够更好的扩展,能做到所有人都能够共知的状况。 前面介绍的是小程序的背景,对当前的机会所在,具体到阿里小程序,这张图就是阿里产品的能力大图,对应的小程序解决方案,从最底下看是我们阿里经济体的能力的输出,后续大家通过我们的阿里小程序云,可以获取到阿里内部的所有这些业务能力,支付宝的能力、钉钉、高德、淘宝所有的能力都会通过小程序云来对外进行透出。 小程序云本身它会提供哪些能力呢?小程序云里包含两个部分: 第一部分是云应用,云应用来帮助大家来做线上的资源编排和应用拓广,比如:作为一个开发者,我们可能有自己的后端服务,后端服务可能想自己去做部署,部署是有成本的,可能首先要去买ECS、买服务器、买数据库、买IDS、还得买流量、买官网IP,买好了一系列的原子的原产品,接下来要做的事情就是把环境给打好,具备一个网络环境,具备可访问的环境,有了可访问的环境,接下来还得想怎么去做部署,做更新,云应用核心所解决的就是以上事情。 第二部分是云开发,云开发简单地讲它是一个Serverless 的套件,云开发不仅仅是面向开发者,在开发者的领域会提供函数计算的能力、存储能力、数据库的能力,同时也会面向运营测,会提供你当前小程序端测的数据统计分析,提供对应的用户反馈的能力,接下来还有类似做运营提供图片设计的在线能力,这些能力都会通过 Serverless 的套件对外透出。 具体到业务会更多,阿里经济体大家想核心想使用的业务能力,比如:云视频、内容安全能力等都会通过当前的 Serverless 的套件对外透出。另一个是小程序云的整体价值,前面强调的一云多端的一云目的是什么,一云并不是希望大家都把数据统一的放在阿里云上,一云的核心对客户支撑的价值在于我们把所有的资源都聚拢在一起,而不是面向不同的场景,来提供不同的后端服务。这样是一种极大效率的降低。那另外一个是期望大家数据能统一,有了数据以后,我们才好有后续基于数据的运营,基于数据的业务分析和扩展,这是我们希望做到一云的效果,通过一朵云来支持整个小程序业务的发展,支持企业,支持我们个人开发者业务的发展。 ...

May 29, 2019 · 1 min · jiezi

小程序-多图列表-性能优化

小程序 多图列表 性能优化写这篇文章的缘由: 最近在公司的小程序项目中遇到了页面图片元素过多导致的性能问题. 从小程序提供的性能检测面板分析, 确定是图片元素占用了过多内存导致. 因为本人之前主要是做桌面端应用开发和原生app开发, 没有太顾及过移动端图片的内存占用问题. 这次既然遇到了, 也就趁这个机会学习一下其优化的技巧. 什么造成的性能问题简单的来说: DOM节点过多 && 图片节点过多 DOM节点过多会造成更多的内存占用. 按照目前的微信小程序限制, 内存占用500M以上会出现卡顿, 甚至闪退. 如果列表中节点没有图片标签, 内存占用现象还不会太明显, 只是DOM节点过多会造成页面渲染耗时增加. 但当列表节点中含有图片时, 内存占用会迅速攀升. 如何解决这两点呢?对于上面两点, 我们分别有对应的优化思路 1. DOM节点过多.对于无限加载的页面, 列表中每一个元素都有大量的子节点. 当列表数目增加时, 页面的总节点数会暴增. 以小红书的小程序为例: 上图中可以看到, 该页面为很多的卡片组成的列表页面. 假设一个卡片的DOM子节点数为 30, 那么当列表元素加载到1000时, 页面会有 30 * 1000 = 30,000 个DOM节点. 小程序显然是吃不消的 (注: 微信小程序推荐总节点数不超过: 1000) 那我们该如何处理来减少节点数呢? 思路很简单: 我们可以只对用户当前屏幕和上下两屏进行真实内容的加载, 对于其他用户暂时不可见的地方, 用空白的节点进行占位. 这样处理后, 实际有内容的卡片数目不超过5个, 页面的总节点数为: 5 * 30 + 995 = 1145. 相对于之前的节点数有了巨大的改进. 让我们来看看代码的实现写代码前, 让我们整理一下需要的数据结构. ...

May 28, 2019 · 2 min · jiezi

小程序代码构成

https://developers.weixin.qq.... 在上一章中,我们通过开发者工具快速创建了一个 QuickStart 项目。你可以留意到这个项目里边生成了不同类型的文件: .json 后缀的 JSON 配置文件.wxml 后缀的 WXML 模板文件.wxss 后缀的 WXSS 样式文件.js 后缀的 JS 脚本逻辑文件 接下来我们分别看看这4种文件的作用。 从事过网页编程的人知道,网页编程采用的是 HTML + CSS + JS 这样的组合,其中 HTML 是用来描述当前这个页面的结构,CSS用来描述页面的样子,JS 通常是用来处理这个页面和用户的交互。同样道理,在小程序中也有同样的角色,其中 WXML 充当的就是类似 HTML 的角色。打开 pages/index/index.wxml,你会看到以下的内容: 小程序启动之后,在 app.js 定义的 App 实例的 onLaunch 回调会被执行: App({ onLaunch() { // 小程序启动之后 触发}})整个小程序只有一个 App 实例,是全部页面共享的,更多的事件回调参考文档 注册程序 App 。接下来我们简单看看小程序的一个页面是怎么写的。 Page 是一个页面构造器,这个构造器就生成了一个页面。在生成页面的时候,小程序框架会把 data 数据和 index.wxml 一起渲染出最终的结构,于是就得到了你看到的小程序的样子。 在渲染完界面之后,页面实例就会收到一个 onLoad 的回调,你可以在这个回调处理你的逻辑。 有关于 Page 构造器更多详细的文档参考 注册页面 Page 。

May 24, 2019 · 1 min · jiezi

注册小程序appjs

注册小程序每个小程序都需要在 app.js 中调用 App 方法注册小程序示例,绑定生命周期回调函数、错误监听和页面不存在监听函数等。 详细的参数含义和使用请参考 App 参考文档 。 // app.jsApp({ onLaunch(options) { // Do something initial when launch. }, onShow(options) { // Do something when show. }, onHide() { // Do something when hide. }, onError(msg) { console.log(msg) }, globalData: 'I am global data'})整个小程序只有一个 App 实例,是全部页面共享的。开发者可以通过 getApp 方法获取到全局唯一的 App 示例,获取App上的数据或调用开发者注册在 App 上的函数。 // xxx.jsconst appInstance = getApp()console.log(appInstance.globalData) // I am global data

May 24, 2019 · 1 min · jiezi

小程序注册页面

注册页面对于小程序中的每个页面,都需要在页面对应的 js 文件中调用 Page 方法注册页面示例,指定页面的初始数据、生命周期回调、事件处理函数等。 详细的参数含义和使用请参考 Page 参考文档 。 // index.jsPage({ data: { text: 'This is page data.' }, onLoad(options) { // Do some initialize when page load. }, onReady() { // Do something when page ready. }, onShow() { // Do something when page show. }, onHide() { // Do something when page hide. }, onUnload() { // Do something when page close. }, onPullDownRefresh() { // Do something when pull down. }, onReachBottom() { // Do something when page reach bottom. }, onShareAppMessage() { // return custom share data when user share. }, onPageScroll() { // Do something when page scroll }, onResize() { // Do something when page resize }, onTabItemTap(item) { console.log(item.index) console.log(item.pagePath) console.log(item.text) }, // Event handler. viewTap() { this.setData({ text: 'Set some data for updating view.' }, function () { // this is setData callback }) }, customData: { hi: 'MINA' }})

May 24, 2019 · 1 min · jiezi

填坑手册小程序Canvas生成海报完整版

海报生成示例 最近智酷君在做[小程序]canvas生成海报的项目中遇到一些棘手的问题,在网上查阅了各种资料,也踩扁了各种坑,智酷君希望把这些“填坑”经验整理一下分享出来,避免后来的兄弟重复“掉坑”。 原型图 这是一个大致的原型图,下面来看下如何制作这个海报,以及整体的思路。 <center>海报生成流程</center> 下面分享下主要的代码内容和“填坑现场”:一、添加字体https://developers.weixin.qq.com/miniprogram/dev/api/canvas/font.html canvasContext.font = value //示例ctx.font = `normal bold 20px sans-serif`//设置字体大小,默认10ctx.setTextAlign('left');ctx.setTextBaseline("top");ctx.fillText("《智酷方程式》专注研究和分享前端技术", 50, 15, 250)//绘制文本符合 CSS font 语法的 DOMString 字符串,至少需要提供字体大小和字体族名。默认值为 10px sans-serif 文字过长在canvas下换行问题处理(最多两行,超过“...”代替)ctx.setTextAlign('left');ctx.setFillStyle('#000');//文字颜色:默认黑色ctx.font = `normal bold 18px sans-serif`//设置字体大小,默认10let canvasTitleArray = canvasTitle.split("");let firstTitle = ""; //第一行字let secondTitle = ""; //第二行字for (let i = 0; i < canvasTitleArray.length; i++) { let element = canvasTitleArray[i]; let firstWidth = ctx.measureText(firstTitle).width; //console.log(ctx.measureText(firstTitle).width); if (firstWidth > 260) { let secondWidth = ctx.measureText(secondTitle).width; //第二行字数超过,变为... if (secondWidth > 260) { secondTitle += "..."; break; } else { secondTitle += element; } } else { firstTitle += element; }}//第一行文字ctx.fillText(firstTitle, 20, 278, 280)//绘制文本//第二行问题if (secondTitle) { ctx.fillText(secondTitle, 20, 300, 280)//绘制文本}通过 ctx.measureText 这个方法可以判断文字的宽度,然后进行切割。(一行字允许宽度为280时,判断需要写小点,比如260) ...

May 23, 2019 · 2 min · jiezi

taro的坑子组件的默认属性和父组件中修改子组件样式问题以及应用复杂数据

坑一:子组件的默认属性 如果这样获取可选属性的默认值: const { startScore = 0, currentScore = 0, endScore = 0, showStartAndEnd = true } = this.props;而又没有实际传入属性的话页面中就会显示null。我们需要在子组件内这样定义默认属性: static defaultProps = { currentScore: 0, startScore: 0, showStartAndEnd: true, endScore: 0, };坑二:父组件中修改子组件样式 如果子组件在多个地方用,那么就需要在不同地方展示不同的子组件样式,所以就需要在父组件中修改样式。而taro不能像react那样直接修改,而是需要这样麻烦的步骤: 先在子组件中定义有哪些拓展的class: static externalClasses = ['my-class', 'radio-class', 'img-class', 'info-class', 'add-class', 'count-class', 'delete-class'];再将拓展的class应用到子组件样式可变的地方: <View className="Goods-radio radio-class" onClick={this.onSelectGoods}> <PRadio value={selected}/> </View>如图中的radio-class 之后在父组件中应用对应的将对应的class作为属性传输: <Goods stock={item.goods.stock} goodsId={item.goods.id} key={index} my-class={'shopping-good'} radio-class={'Goods-radio'} count-class={'Goods-count'} delete-class={'Goods-remove'} img-class={'Goods-img'} info-class={'Goods-info'} >如图中的radio-class。现在我们终于可以在父组件用Goods-radio作为className来修改子组件的样式了。 ...

May 23, 2019 · 1 min · jiezi

微信小程序wepy框架学习和使用心得

一、微信小程序wepy框架简介:微信小程序WePY框架是腾讯官方推出来的框架,类似的框架还有美团的mpvue,京东的Taro等; 目前公司开发小程序主要用到的是微信原生方法和官方的wepy框架; wepy框架在开发过程中参考了 Vue 等现有框架的一些语法风格和功能特性,对原生小程序的开发模式进行了再次封装,更贴近于 MVVM 架构模式, 并支持ES6/7的一些新特性。相对更容易上手,提高开发效率; 二、WePY项目的创建与目录结构WePY的安装或更新都通过npm进行,全局安装或更新WePY命令行工具npm install wepy-cli -g在开发目录中生成Demo开发项目wepy new myproject切换至项目目录cd myproject 安装依赖npm install开启实时编译wepy build --watchWePY项目的目录结构如下 ├── dist 小程序运行代码目录(该目录由WePY的build指令自动编译生成,请不要直接修改该目录下的文件) ├── node_modules ├── src 代码编写的目录(该目录为使用WePY后的开发目录) | ├── components WePY组件目录(组件不属于完整页面,仅供完整页面或其他组件引用) | | ├── com_a.wpy 可复用的WePY组件a | | └── com_b.wpy 可复用的WePY组件b | ├── pages WePY页面目录(属于完整页面) | | ├── index.wpy index页面(经build后,会在dist目录下的pages目录生成index.js、index.json、index.wxml和index.wxss文件) | | └── other.wpy other页面(经build后,会在dist目录下的pages目录生成other.js、other.json、other.wxml和other.wxss文件) | └── app.wpy 小程序配置项(全局数据、样式、声明钩子等;经build后,会在dist目录下生成app.js、app.json和app.wxss文件) └ ── package.json 项目的package配置搭建好项目后,IDE需配置代码高亮,文件后缀为.wpy,可共用Vue的高亮规则,但需要手动设置,具体配置大家可参考wepy官方文档三、wepy使用心得总结:wepy代码风格类似Vue,如computed,data,methods等用法差不多,熟悉vue开发的同学看看文档可以轻松上手,不过还是有很多地方写法容易混淆,我工作中遇到的总结几个,如列表循环,条件渲染,父子组件值传递等,下面举例说明: 1). wepy和vue列表循环对比: // wepy 列表循环,外面可套一层repeat标签,注意和vue写法的区别 <repeat for="{{list}}" key="index> <view>{{item}}</view> </repeat> // vue 列表循环,外面可套一层template标签 <template v-for="(item,index) in list" :key="index"> // 不推荐key直接用索引index <div>{{item}}<div> </template> 2). wepy和vue条件渲染中,wepy需要加{{}},vue不需要,里面都可以写表达式进行判断: <view wx:if="{{show}}"></view> <div v-if="show"></div> 3). 父子组件值传递两者都在子组件中用props接收, props中可以定义能接收的数据类型,如果不符合会报错, wepy可以通过使用.sync修饰符来达到父组件数据绑定至子组件的效果,也可以通过设置子组件props的 twoWay:true来达到子组件数据绑定至父组件的效果。那如果既使用.sync修饰符,同时子组件props中 添加的twoWay: true时,就可以实现数据的双向绑定了; // parent.wpy <child :title="parentTitle" :syncTitle.sync="parentTitle" :twoWayTitle="parentTitle"></child> data = { parentTitle: 'p-title' }; // child.wpy props = { // 静态传值 title: String, // 父向子单向动态传值 syncTitle: { type: String, default: 'null' }, twoWayTitle: { type: String, default: 'nothing', twoWay: true } }; onLoad () { console.log(this.title); // p-title console.log(this.syncTitle); // p-title console.log(this.twoWayTitle); // p-title this.title = 'c-title'; console.log(this.$parent.parentTitle); // p-title. this.twoWayTitle = 'two-way-title'; this.$apply(); console.log(this.$parent.parentTitle); // two-way-title. --- twoWay为true时,子组件props中的属性值改变时,会同时改变父组件对应的值 this.$parent.parentTitle = 'p-title-changed'; this.$parent.$apply(); console.log(this.title); // 'c-title'; console.log(this.syncTitle); // 'p-title-changed' --- 有.sync修饰符的props属性值,当在父组件中改变时,会同时改变子组件对应的值。2.wepy支持自定义组件开发,实现组件复用,减少代码冗余,提高开发效率; ...

May 23, 2019 · 2 min · jiezi

小程序系列如何使用分包加载

在小程序开发的过程中,小程序的体积会随着版本的迭代变的越来越大,这时候我们就希望能够将小程序分成多个包从服务器下载,这样既可以加快首屏的渲染也便于后续按需加载的实现。小程序在微信客户端 6.6.0,基础库 1.7.3 及以上版本开始支持 分包功能。在构建小程序分包项目时,构建会输出一个或多个分包。每个使用分包小程序必定含有一个主包。所谓的主包,即放置默认启动页面/TabBar 页面,以及一些所有分包都需用到公共资源/JS 脚本;而分包则是根据开发者的配置进行划分。在小程序启动时,默认会下载主包并启动主包内页面,当用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示。 配置方法 配置例子{ "pages": ["pages/index", "pages/shopcart"], "subpackages": [ { "root": "packageA", "pages": ["pages/mine", "pages/order"] }, { "root": "packageB", "name": "pack2", "pages": ["pages/detail", "pages/pay"] } ]}├── app.js├── app.json├── app.wxss├── packageA│ └── pages│ ├── mine│ └── order├── packageB│ └── pages│ ├── pay│ └── detail├── pages│ ├── index│ └── shopcart└── utils 打包原则声明 subpackages 后,将按 subpackages 配置路径进行打包,subpackages 配置路径外的目录将被打包到 app(主包) 中app(主包)也可以有自己的 pages(即最外层的 pages 字段)subpackage 的根目录不能是另外一个 subpackage 内的子目录tabBar 页面必须在 app(主包)内 引用原则packageA 无法 require packageB JS 文件,但可以 require app、自己 package 内的 JS 文件packageA 无法 import packageB 的 template,但可以 require app、自己 package 内的 templatepackageA 无法使用 packageB 的资源,但可以使用 app、自己 package 内的资源

May 22, 2019 · 1 min · jiezi

小程序richtext组件如何改变内部img图片样式

一、起因小程序中有一个页面,很奇葩,是通过后端传过来的整段HTML字符串展示内容的,那么我们暂时叫这个页面为content,传过来之后,他里面的图片样式是不固定的,有的大,有的小,有的有style有的没有,那我怎么能让他统一展示成一样的样式呢? 二、办法思前想后,我觉得还是正则比较靠谱,把content里面所有的img标签筛选出来,把里面有style的、有width的、有height的、全部删除掉,最后在统一加上我们想要的样式,最终代码如下: <RichText nodes={content} /> 下面是HTML字符串处理过程 let html = content .replace(/<p([\s\w"=\/\.:;]+)((?:(style="[^"]+")))/ig, '<p') .replace(/<p>/ig, '<p style="font-size: 15Px; line-height: 25Px;">') .replace(/<img([\s\w"-=\/\.:;]+)((?:(height="[^"]+")))/ig, '<img$1') .replace(/<img([\s\w"-=\/\.:;]+)((?:(width="[^"]+")))/ig, '<img$1') .replace(/<img([\s\w"-=\/\.:;]+)((?:(style="[^"]+")))/ig, '<img$1') .replace(/<img([\s\w"-=\/\.:;]+)((?:(alt="[^"]+")))/ig, '<img$1') .replace(/<img([\s\w"-=\/\.:;]+)/ig, '<img$1 style="width: 100%; border-radius: 8Px;"');最终实现了我们想要的样式统一的效果啦~ 三、总结我有想过直接在less里面取到img,然后改变它的样式,这种办法在h5中是可行的,但是在小程序中不起作用!因为在小程序中会是一整个rich-text标签,里面的内容样式无法修改。所以采用这种办法啦~~能够解决问题。

May 21, 2019 · 1 min · jiezi

详解-mpvue-小程序框架-及和原生的差异

简介1.美团工程师推出的基于Vue.js封装的用于开发小程序的框架2.融合了原生小程序和Vue.js的特点3.可完全组件化开发 特点1.组件化开发2.完成的Vue.js开发体验(前提是熟悉Vue)3.可使用Vuex管理状态4.Webpack构建项目5.最终H5转换工具将项目编译成小程序识别的文件 初始化项目1.npm install vue-cli -g 下载vue脚手架2.vue init mpvue/mpvue-quickstart my-project 初始化项目3.cd my-project 进入项目根目录4.npm install 根据package.json安装项目依赖包5.npm start || npm run dev 启动初始化项目 注册小程序1.src/app.json 全局配置文件2.src/App.vue 等同于原生小程序中的app.js, 可再次写小程序应用实例的声明周期 函数 || 全局样式(style中编写)3.main.js应用入口文件, 声明组件类型,挂载组件 入口文件介绍import Vue from 'vue'import App from './App.vue'// Vue.config.productionTip = false 默认为false,用于启动项目的时候提示信息,设置为false关闭提示Vue.config.productionTip = true// 这个值是为了与后面要讲的小程序页面组件所区分开来,因为小程序页面组件和这个App.vue组件的写法和引入方式是一致的,为了区分两者,需要设置mpType值App.mpType = 'app'// 生成Vue实例const app = new Vue(App)// 挂载组件app.$mount() 编写页面 pages/index页面需要文件介绍 index.vue 等同于原生中的wxml + wxss + jsmain.js 当前组件页面的入口文件,用于生成当前组件实例,并挂载组件main.json 当前页面的局部配置文件(注意:index.vue组件最终会被转化为main.wxml以及main.wxss文件, 所以当前的json文件需命名main)src源文件 自动打包后的dist文件 index/main.jsimport Vue from 'vue'import Index from './index.vue'const index = new Vue(Index)index.$mount() ...

May 21, 2019 · 2 min · jiezi

实现小程序tab栏下划线动画效果

最终效果 实现wxml <view class='abox'> <view wx:for="{{title}}" class='{{currentIndex==index?"tabTrue":""}}' bindtap='changeTab' data-aa='{{index}}'> {{item}} </view> <view class='b' style="left:{{left}}px"></view></view>wxss .abox{ display: flex; flex-direction: row; width: 100%; justify-content: space-around; position: relative; padding-bottom: 20rpx;}.tabTrue{ color: red;}.b{ background: red; height: 4rpx; width:64rpx; position: absolute; bottom: 0; transition: all .3s linear;}js Page({ data: { title: ["首页","掘金","思否","知乎"], currentIndex:"0", left:"" }, changeTab:function(e){ //console.log(e) this.setData({ currentIndex: e.currentTarget.dataset.aa }) this.changeline(e) }, changeline:function(){ const query = wx.createSelectorQuery() var _this = this query.select('.tabTrue').boundingClientRect() query.exec(function (res) { _this.setData({ left: res[0].left }) //console.log(res[0].left) }) }, onLoad: function () { this.changeline(1) }})上面代码可以实现效果,这里面最重要的就是通过 changeTab方法获取有tabtrue这个class的标签,获取到标签的left值。 ...

May 18, 2019 · 1 min · jiezi

小程序系列项目配置

全部配置项小程序根目录下的 app.json 文件用来对微信小程序进行全局配置。文件内容为一个 JSON 对象,总共有15个属性可以配置,如下: 常用配置项常用的配置项包括页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等。 { "pages": ["pages/index/index", "pages/logs/index"], "window": { "navigationBarTitleText": "Demo" }, "tabBar": { "list": [ { "pagePath": "pages/index/index", "text": "首页" }, { "pagePath": "pages/logs/logs", "text": "日志" } ] }, "networkTimeout": { "request": 10000, "downloadFile": 10000 }, "debug": true, "navigateToMiniProgramAppIdList": ["wxe5f52902cf4de896"]}

May 18, 2019 · 1 min · jiezi

小程序scrollview安卓机隐藏横向滚动条的实现

一、实践踩坑项目使用mpvue开发 1.使用flex布局 // html大概长这样 <div class="worth-wraper"> <scroll-view scroll-x="true" scroll-left="0"> <div class="worth-list"> <div class="worth-item-img"> <img src="/static/images/index/brand1.png" alt=""> </div> <div class="worth-item-img"> <img src="/static/images/index/brand2.png" alt=""> </div> <div class="worth-item-img"> <img src="/static/images/index/brand3.png" alt=""> </div> <div class="worth-item-img"> <img src="/static/images/index/brand4.png" alt=""> </div> </div> </scroll-view></div>// css相应就大概长这样 .worth-wraper{ margin-top: 60rpx;height: 560rpx;box-sizing: border-box;display: flex;width: 750rpx;overflow: hidden;font-size: 28rpx;color: #7a7269;line-height: 42rpx;.worth-list{ display: flex; margin-left: 30rpx; .worth-item-img{ flex: 1; margin-right: 20rpx; width: 290rpx; height: 560rpx; } img{ width: 290rpx; height: 560rpx; } .worth-item{ padding: 0 35rpx 0 40rpx; flex: 1; box-sizing: border-box; background: url("../../../static/images/index/worth-bg1.png") no-repeat; background-size: 100% 100%; width: 290rpx; height: 560rpx; margin-right: 20rpx; }}} ...

May 15, 2019 · 1 min · jiezi

ShareBook1后台框架与小程序用户登录接口实战

本博客 猫叔的博客,转载请申明出处阅读本文约 “5分钟”适读人群:Java后端、Java初级、小程序前端前后端项目的地址ShareBookServerShareBookClient小程序前端 先看一下本节的学习目录,我们项目的小程序会在首次登录的时候自动获取用户的OpenId,并作为系统的注册信息,这里只是获取其OpenId或者SessionId,还没有获取用户信息(比如头像、Id、性别等)。 而在获取前,大家可能还要了解一下小程序的用户注册流程,这里我就不具体说了。 我们会在app.js(这个是所有小程序首次都会执行的js,我们会对小程序的缓存区Storage进行校验,并确定是否存在有效token),做校验,如果没有就进行首次注册。 注册流程是从小程序(简称vx,以下vx替代)获取用户的code,给到服务器,服务器会用code还有自己的appId等信息一起去微信服务器请求用户数据,注意每一个vx所对应的用户openid都是不一样的。 config.js是存放整个vx的统一基层API地址。 就如上图写的,前端在第一节的内容较为简单,大家可以在GitHub看到源码。 针对适读人群的合理学习时间是:45分钟,并了解vx官网部分简易API。 Java服务端 本节的服务端是重点,除了搭建整个SpringBoot基本开发框架以外(好像不用很久)还要准备一些基本的公关类和工具类,这个大家学习起来可能有点费劲,不过干货很多。 首先是技术栈,SpringBoot+MySQL+MyBatis,这个我就不具体说怎么搭建了,详情看源码,或者我的官网也有搭建教程。 在pom文件中,我引入了Swagger,这会方便我们与前端对接API的信息,你仅需要在启动类加上一个@EnableSwagger2的注解即可。 访问:http://localhost:8080/sharebook/swagger-ui.html(注意我的application-dev.yml中给项目起了名字叫sharebook,如果你是其他名字,请修改) 需要介绍的是,大家可以看看resources文件夹我采用application.yml、application-dev.yml,这样可以方便我们快速切换开发、生产、测试等多种环境的项目配置,希望大家可以养成习惯。 在项目的实体类上,我采用Lombok快速生成get/set方法,你仅需要加一个@Data的注解,这里你需要注意还要加无参和全参的构造函数,例如我一开始没有全参的构造,在读取生成User实体类的时候,MyBatis会报java.lang.NoSuchMethodException。 同时实体类需要序列号,我这里就采用默认的Serializable,对实体类序列化是因为它可能需要进行网络通信或者数据持久化。对于加了Serializable的实体类,最好有一个对应的UID。 因为我是用IDEA(推荐使用),所有如果要生成UID,可以在配置勾选以上的选项,然后点击实体类按“Alt+Enter”,然后选择生成UID即可。 common & util对于AppMessage,大家可能会吐槽,因为其实可以优化,不过我从ssm迁移过来就偷懒了,大家可以fork后自己改为SpringBoot的yml配置形式,它其实就是一些静态配置。 HttpService写的不好,大家可以修改优化,是一个普通的Http请求工具类。 主要是ResponseCode和ServerCache,对API接口返回层做了统一处理,vx前端程序员可以更好的调试工作,推荐大家模仿优化。 TokenCache使用了Google的guava做了本地缓存,缓存vx登录的token,一定要设定有效时间。 其实util包和common包一开始拆分的不好,所以大家可以优化。 MD5Util就是一个MD5的加解密处理。 业务处理就如上面vx环节说的,我们API获取到code后会进行校验处理。 我在接口实现使用了很古老的方式,代码是很久以前的了,见谅,介绍流程为主。大家可以去修改优化。 我对从微信服务器获取到的结果进行校验和数据获取,得到的openid先到数据库校验,用户是否存在,存在就生成Token,不存在就注册后生成Token。流程很简单。 补充以下,vx的API路径我推荐:http://localhost:8080/sharebook/api/v1/ 这里采用v1命名。是因为后续升级后v2,这样有时可以保证老版本API可以继续使用或者停用。 针对适读人群的合理学习时间是:115分钟,推荐自己模仿敲一遍。 实战调试vx首次登录调用成功。 vx缓存区Storage存储token数据 后端服务器日志打印正常。 SQL数据录入正常,这里sessionId为null是正常的,项目业务没有要求存储sessionId,注意对于在统一公众号下的不同小程序的openid是不同的,但是sessionId是一致的(不知道近期vx官方是否更改规则)。 目录链接没有实战经验?从零敲一个企业级共享项目前后端!公众号:Java猫说学习交流群:728698035 现架构设计(码农)兼创业技术顾问,不羁平庸,热爱开源,杂谈程序人生与不定期干货。

May 15, 2019 · 1 min · jiezi

小程序绑定用户方案-优化

在做过一系列小程序之后,对小程序的登陆鉴权的流程也有一定的理解,类似于 B 端小程序自不必说,要用户信息手机号地址可以一把梭,做一个引导页面进行判断然后要求用户给与绑定,用户自然不会多说什么,毕竟这是企业级别应用。但是当涉及到 C 端小程序时候。想让用户进行绑定,就势必要给与用户便利。这里我列出一些我觉得较为不错的小程序应用方案以供参考。 预先绑定类该类小程序在使用之前就需要绑定用户信息。常见于线下门店类功能性小程序。线下操作时有大量的优惠活动来支持小程序的流量。 功能介绍例如 便利蜂。之前在上海经常使用,价格和优惠都非常不错,这类小程序属于线下功能类小程序,内部有抽奖,付款等一系列功能。该小程序第一次打开就先用户直接要求用户绑定信息和地址,考虑到线下门店都会有一定的店员辅助。所以该小程序的绑定操作实际上用户都是可以接受的。图片如下所示。 技术要点技术1: 使用自定义导航栏让头部可以配置全局配置 "window": { "navigationStyle": "custom"}如果微信 app 的版本在 7.0.0之上,我们就可以使用页面级别的配置了。 { "usingComponents": {}, "navigationStyle": "custom"}该配置默认时default,当使用custom时候可以自定义导航,可以在头部配置 loading。 第二种这个需要 app 版本,所以如果是想简化,反而在全局下定义,再使用微信官方的组件 avigation-bar 即可。 技术2:使用小程序骨架屏骨架屏方案在后端不能很快给与前端数据时候采用这种方案,亦或者前端可以使用 Service Worker 把上次缓存数据返回到前端,等到从后端获取数据之后刷新页面也是一种方案,但是因为这是第一次打开小程序,所以采用骨架屏是一个很好的方法。 采用 小程序骨架屏 组件,如果不需要骨架屏动画效果,可以试试直接加载图片作为骨架屏。 惰性绑定类该类小程序在展示时无需绑定用户信息,但是当用户进行操作时在询问绑定。常用于线上商城等一系列无需专人引导的用户项目。 功能介绍基本上线上大部分 c 端小程序都采用此做法,功能上倒是没什么可以介绍的,但是实践上却有不同做法。 实践方式方式 1: 页面跳转 (京东购物)在每个需要绑定的按钮上添加跳转逻辑,如果当前小程序没有绑定,可以跳转到另外一个页面上确认授权。 方式2: 按钮控制 (华为商城+)在每个需要绑定按钮上添加 open-type='getuserinfo',后续可以根据状态变化,切换掉按钮(也可以不切换,因为第二次绑定数据不会跳出组件)。 方式3: 遮罩层拦截 (抽奖助手)在需要绑定的页面添加一个 透明模态框,增加以整个页面大小的button。用fixed布局,还可以向下滚动。无论在当前页面点击任何地方都会出现需要绑定选项。 组件代码: // wxml<view style="z-index: {{zIndex}}" class="mask"> <button open-type="{{ openType }}" bindtap="onClick" bindgetuserinfo="bindGetUserInfo" bindgetphonenumber="bindGetPhoneNumber" bindopensetting="bindOpenSetting" binderror="bindError" class="mask"/></view>// wxss.mask{ position: fixed; top: 0; bottom:0; left:0; right:0; background-color: inherit; opacity: 0;}然后在绑定后令 mask 消失。该方案初看起来不是那么的合适,但是仔细想想却也没什么问题,因为用户99%可能点击所需求的按钮,就算点击到按钮之间的空隙之处跳出要求绑定也没有什么问题。 ...

May 15, 2019 · 1 min · jiezi

解决微信小程序云开发中获取数据库的内容为空

问题描述:在前端想获取数据库某集合中的数据时,返回的参数data始终为空数组,如下: 相关代码如下:const db = wx.cloud.database();const activityInfo = db.collection('activityInfo');Page({ ...省略不相干代码... onLoad(){ activityInfo.get().then((res)=>{ console.log(res) }) } ...省略不相干代码...})解决方案:数据库新建的collectioin需要设置权限,没有问题就可以读取和更新了;小程序云开发控制台->你的集合名称->权限设置->所有用户可读,仅创建者可读写结果:成功获取到数据!

May 14, 2019 · 1 min · jiezi

如何探测小程序返回到webview页面

在公司项目中经常会遇到一个场景, 尝试过各种不同的方法, 最后想到了一种很技术上简单且可行的方法. 经常被QA同学反应同一类型的问题项目是小程序(wepy), 部分页面使用webview(vue). 经常会遇见一个场景: 当小程序navigateTo到一些页面对用户的"收藏状态", "身材细节"做了修改后, 用户点击返回按钮回到上一个页面, 收藏的状态或是身材细节没有改变. 那是当然的, 作为一个小程序中的webview, api相当有限, 没有一个事件可以让网页触发重新渲染动作, 轮询更是不理智的表面功夫. 我们试过绑定blur和click事件来模拟事件, 试过从业务逻辑上加入一些时间点检查状态, 最后才想到个技术简单, 操作简单的解决方案. 解决方法第一步, 在小程序webview绑定的url上加上时间戳. <web-view src="{{url}}"/>onShow () { this.url = ${base_url}?ts=Date.now()}第二步, 在html里监听query变化. 我遇到问题的项目使用的是vue. watch: { '$route.query.ts': function () { this.fetchData() this.patchRender() // 获取数据, 重新渲染变化的部分 } }这样就解决了触发退回到webview的事件探测问题, 剩下的只要根据业务来重新渲染可能变化的部分就行了. 更多小程序的部分每次都需要改变url的query参数没有办法, 但是对vue设计这么良好的框架还有一定改良空间. 我们可以把这串代码写到mixin里, 对性能有些小影响, 但方法没写也不会去执行, 只是在不需要的页面上多了个observer. Vue.use(function () { Vue.mixin({ watch: { '$route.query.ts': function () { this.$options.onShow && this.$options.onShow.call(this) } } })})那么在vue页面中就省去了写watch的麻烦, 直接像小程序那样写onShow方法就行了. ...

May 13, 2019 · 1 min · jiezi

没有实战经验从零敲一个企业级共享项目前后端

本博客 猫叔的博客,转载请申明出阅读本文约“3分钟”适读人群:Java后端、Java初级、小程序前端 本文是两个GitHub项目的序章,旨在指导初级程序员完成一个企业级共享项目的前后端代码实践,丰富自身的实战经验与知识。 项目介绍,这个一个企业级的共享图书项目,涉及部分Iot实践环节,整个项目主要以SpringBoot为后台提供API,前端小程序调用接口,同时项目会涉及共享书柜硬件的通信环节,其中涉及netty知识,整个项目大致的技术栈应该会有小程序源码MVC开发模式、ES6基础能力提升、共享书柜二维码生成、图书管理系统、图书业务知识、netty构建简易Iot通信,SpringBoot实现基本的业务功能。 业务具体介绍,本系统是一个共享图书的小程序项目,企业级,创业项目。类似共享自行车,投放自行车,本项目投放图书书柜(小型快递柜),书柜内部有24本图书,每个书柜会有定位,可以在小程序搜到距离你最近的书柜,并且每个书柜会有专属的二维码,因为每个书柜存放的图书不一样,你可以在A书柜扫码借书,之后在B书柜还书,前提是B书柜有空余格子。具体业务流程类似共享自行车,也有设计押金、月卡、季卡等等。 先看看项目的效果吧,暂时给前端小程序,因为从零带着敲,所以原本的后端是SSM的,我将重新改为SpringBoot,后端的管理平台就暂时没有给gif了。 前后端项目的地址ShareBookServerShareBookClient前端知识盘点因为我前端的基础不行,所以说得不好的,还请各位码字留情。 前端的目录是比较简单的,各位后端的同学也可以简单学习,毕竟到时会给源码,所以大家可以调式试试。imgs是主要小程序的静态资源,即图片什么的,因为小程序自身本来就有限制,所以如果加载大量的图片就直接用url去加载,小业务的话,可以和业务服务器一起,如果数据量大,就自己做一个ftp的文件服务器或者使用阿里的文件存储oss,其他平台的也有很多,这里就不一一介绍了。 以上是单个页面的实现基本文件目录。整个前端没有使用什么便捷的框架生成,而是原生以MVC的思路去敲,这也是我推荐的,具体理由,...一下省略一万字。 我也是采用后端的MVC模式,xsml是页面骨架,wxss就是H5的css,就是我们的炫酷外表,而内容展示什么,是由js而定,wxml会数据绑定js里面的字段,而js会调用-model.js里面的方法,-model.js就是请求我们的后台服务器的具体业务调用端。 虽然大家看到小程序前端都写好了,不过秉承教学目的,所以还是要分步骤,加注释,一步一步的上传GitHub。 后端知识盘点 后端本身是SSM的框架,不过比较久远,大家可能调试不便,所以就整改为SpringBoot版本,还有数据库设计,这一块我也暂时还没整理出一个结构图,下一篇预计会出,或者下下篇。(本系列因为秉承开源,免费的原则,所以更新时间可能会有波动,个人能力有限,还请见谅。) 后端会使用到freemarker框架来生成后端管理页面,主要是管理图书库存,还有二维码生成子系统是针对书柜设计的,不同书柜会有对应的图书。而系统会以原生netty对接单片机。(因为硬件不属于软件部分,而且单片机一块的基本上有经验的都可以做到,所以到时会用普通的代码模拟) 后端会出两套API,一套是针对小程序的,一套是后台管理系统的。其中还涉及微信支付环节。 具体大家可以关注一下。 公众号:Java猫说学习交流群:728698035 现架构设计(码农)兼创业技术顾问,不羁平庸,热爱开源,杂谈程序人生与不定期干货。

May 13, 2019 · 1 min · jiezi

uniapp小程序支付app-支付

<template> <view> <button @click="paymini">小程序支付</button> <button @click="payapp">app支付</button> </view></template> <script> export default { data() { return { }; }, methods: { payapp: function() { // 请求后台数据 prepay_id paySign nonceStr timeStamp uni.request({ url: '', data: { code: code, payMoney: 1, uid: '', type: '1' }, header: { 'custom-header': '' //自定义请求头信息 }, success: (res) => { console.log(res); // 调起支付 uni.requestPayment({ provider: 'alipay', orderInfo: { "dealId": res.dealId, "appKey": res.appKey, "totalAmount": res.totalAmount, "tpOrderId": res.tpOrderId, "dealTitle": res.dealTitle, "rsaSign": res.rsaSign, "bizInfo": res.bizInfo }, //订单数据 success: function(res) { console.log('success:' + JSON.stringify(res)); }, fail: function(err) { console.log('fail:' + JSON.stringify(err)); } }); } }); }, paymini: function() { uni.login({ provider: 'weixin', success: function(loginRes) { let code = loginRes.code; // 请求后台数据 prepay_id paySign nonceStr timeStamp uni.request({ url: '', data: { code: code, payMoney: 1, uid: '', type: '1' }, header: { 'custom-header': '' //自定义请求头信息 }, success: (res) => { console.log(res); // 调起支付 uni.requestPayment({ provider: 'wxpay', timeStamp: String(Date.now()), nonceStr: res.nonceStr, package: res.package, signType: 'MD5', paySign: res.paySign, success: function(res) { console.log('success:' + JSON.stringify(res)); }, fail: function(err) { console.log('fail:' + JSON.stringify(err)); } }); } }); } }); } } }</script> <style> </style>

May 11, 2019 · 1 min · jiezi

基于Taro开发的小程序多端UI组件库-tarocustomui

taro-custom-uiCustomUI 是一套基于Taro开发的小程序多端UI组件库,目的在于给开发者提供更灵活的布局组件及样式,以满足更多个性化的场景 Featured Components<CustomPage /> <CustomTransition /> //类似vue的transition 支持transition动画Commmon Components<CustomList /><CustomSwitch />Developing , Welcome To Experience // 开发中,欢迎体验

May 10, 2019 · 1 min · jiezi

浅谈小程序运行机制

写作背景接触小程序有一段时间了,总得来说小程序开发门槛比较低,但其中基本的运行机制和原理还是要懂的。“比如我在面试的时候问到一个关于小程序的问题,问小程序有window对象吗?他说有吧”,但其实是没有的。感觉他并没有了解小程序底层的一些东西,归根结底来说应该只能算会使用这个工具,但并不明白其中的道理。 小程序与普通网页开发是有很大差别的,这就要从它的技术架构底层去剖析了。还有比如习惯Vue,react开发的开发者会吐槽小程序新建页面的繁琐,page必须由多个文件组成、组件化支持不完善、每次更改 data 里的数据都得setData、没有像Vue方便的watch监听、不能操作Dom,对于复杂性场景不太好,之前不支持npm,不支持sass,less预编译处理语言。 “有的人说小程序就像被阉割的Vue”,哈哈当然了,他们从设计的出发点就不同,咱也得理解小程序设计的初衷,通过它的使用场景,它为什么采用这种技术架构,这种技术架构有什么好处,相信在你了解完这些之后,就会理解了。下面我会从以下几个角度去分析小程序的运行机制和它的整体技术架构。 了解小程序的由来在小程序没有出来之前,最初微信WebView逐渐成为移动web重要入口,微信发布了一整套网页开发工具包,称之为 JS-SDK,给所有的 Web 开发者打开了一扇全新的窗户,让所有开发者都可以使用到微信的原生能力,去完成一些之前做不到或者难以做到的事情。 但JS-SDK 的模式并没有解决使用移动网页遇到的体验不良的问题,比如受限于设备性能和网络速度,会出现白屏的可能。因此又设计了一个增强版JS-SDK,也就是“微信 Web 资源离线存储”,但在复杂的页面上依然会出现白屏的问题,原因表现在页面切换的生硬和点击的迟滞感。这个时候需要一个 JS-SDK 所处理不了的,使用户体验更好的一个系统,小程序应运而生。 快速的加载更强大的能力原生的体验易用且安全的微信数据开放高效和简单的开发小程序与普通网页开发的区别小程序的开发同普通的网页开发相比有很大的相似性,小程序的主要开发语言也是 JavaScript,但是二者还是有些差别的。 普通网页开发可以使用各种浏览器提供的 DOM API,进行 DOM 操作,小程序的逻辑层和渲染层是分开的,逻辑层运行在 JSCore 中,并没有一个完整浏览器对象,因而缺少相关的DOM API和BOM API。普通网页开发渲染线程和脚本线程是互斥的,这也是为什么长时间的脚本运行可能会导致页面失去响应,而在小程序中,二者是分开的,分别运行在不同的线程中。网页开发者在开发网页的时候,只需要使用到浏览器,并且搭配上一些辅助工具或者编辑器即可。小程序的开发则有所不同,需要经过申请小程序帐号、安装小程序开发者工具、配置项目等等过程方可完成。小程序的执行环境 小程序架构一、技术选型一般来说,渲染界面的技术有三种: 用纯客户端原生技术来渲染用纯 Web 技术来渲染用客户端原生技术与 Web 技术结合的混合技术(简称 Hybrid 技术)来渲染通过以下几个方面分析,小程序采用哪种技术方案 开发门槛:Web 门槛低,Native 也有像 RN 这样的框架支持体验:Native 体验比 Web 要好太多,Hybrid 在一定程度上比 Web 接近原生体验版本更新:Web 支持在线更新,Native 则需要打包到微信一起审核发布管控和安全:Web 可跳转或是改变页面内容,存在一些不可控因素和安全风险由于小程序的宿主环境是微信,如果用纯客户端原生技术来编写小程序,那么小程序代码每次都需要与微信代码一起发版,这种方式肯定是不行的。 所以需要像web技术那样,有一份随时可更新的资源包放在云端,通过下载到本地,动态执行后即可渲染出界面。如果用纯web技术来渲染小程序,在一些复杂的交互上可能会面临一些性能问题,这是因为在web技术中,UI渲染跟JavaScript的脚本执行都在一个单线程中执行,这就容易导致一些逻辑任务抢占UI渲染的资源。 所以最终采用了两者结合起来的Hybrid 技术来渲染小程序,可以用一种近似web的方式来开发,并且可以实现在线更新代码,同时引入组件也有以下好处: 扩展 Web 的能力。比如像输入框组件(input, textarea)有更好地控制键盘的能力体验更好,同时也减轻 WebView 的渲染工作绕过 setData、数据通信和重渲染流程,使渲染性能更好用客户端原生渲染内置一些复杂组件,可以提供更好的性能二、双线程模型小程序的渲染层和逻辑层分别由 2 个线程管理:视图层的界面使用了 WebView 进行渲染,逻辑层采用 JsCore 线程运行 JS脚本。 ...

May 10, 2019 · 1 min · jiezi

码code-利用AI技术你的小程序也能图文识别

近日,明星旧照修复图在网络上引发热议,在打拐方面也有凭童年照找到被拐儿童的技术突破,这些看似天方夜谭的操作均由AI实现。如今AI技术发展迅猛,市场接受度也较好,开发者可以将其视作提升自身小程序的一个契机。 在此之前,腾讯官方就推出了腾讯AI开放平台,提供众多关于AI技术的接口,方便开发者开发以及应用这项技术。 对于小程序开发者来说,可以利用哪些AI技术让自己的小程序出奇制胜?今天我们特别介绍应用较为广泛的AI图片识别技术。 AI图片识别技术的应用腾讯图片识别依托腾讯领先的图片处理技术和深度识别引擎,可以快速、准确地识别图片内容信息并自动生成文字描述。这项AI技术,能够帮助小程序实现图文识别功能,为用户提供更贴心的服务。 这项技术是基于腾讯AI Lab领先的深度学习算法,对图片的信息进行提取。目前它已支持证件、名片、手写体等OCR和物体、场景等图片的识别。 由于图文识别功能的实用性和综合性较强,生活服务类、网络购物类、科普类等小程序的开发者们可以选择AI图片识别技术,优化自己的小程序。以下是我们挑选的两个场景示例: 场景一:查询快递,但不想手动输入长长的快递码现在查快递、实名认证、绑定银行卡等操作在互联网已经是家常便饭,但号码将近20位数字,如果挨个输入可能会输到头秃。 要是开发者能够在自己的小程序里接入OCR,支持用户扫图自动录入号码,那么将会大大提高用户体验。 「顺丰速运+」通过AI图片识别技术,自动识别快递单上的快递号,再结合自有运单数据库,向用户自动展示完整的运单信息。 场景二:想了解某样东西,却无法提取文字信息去搜索世界那么大,总有自己的认知短板。当用户想了解在路上、展览上看到的某样物品,会选择拍下来,再去寻求科普信息。 如果小程序能够使用图片识别技术,那么用户就可以随拍随科普,获取该物品相关的信息,操作流程也简单许多,真正实现“现在!我要拿到它的全部信息!” 「博物官」应用了AI图片识别技术,用户在参观展馆时,通过拍摄展品,可获取对应的展品信息,无需导览员的讲解。 接入AI图片识别技术的步骤(以身份证OCR为例)1、成为开发者登录腾讯AI开放平台(https://ai.qq.com/),点击顶部导航栏右侧控制台或者底部立即使用,注册成为开发者后即可进入控制台页面。 2、 创建应用在控制台页面,可在「应用」板块点击创建应用,填写应用的相关信息,勾选身份证OCR,完成应用的创建。(*注:最多可以创建100个应用,在创建应用的表单中,可以自行勾选所需的AI技术接口,最多可以为应用开放所有的接口权限。) 3、获取接入凭证在应用创建完毕后,开发者可在应用详情中查看到此应用的接入凭证,主要为AppID、AppKey。 4、 接口鉴权使用应用所分配到的AppID、AppKey,获取接口鉴权签名。 5、 调试调用平台AI技术接口,根据需求进行调试。 参考示例:假设示例请求数据如下。 假设应用密钥为:a95eceb1ac8c24ee28b70f7dbba912bf,示例图片文件存储路径为:/path/to/image。 下面使用PHP实现该HTTP API调用,其中getReqSign、doHttpPost可以从接口鉴权获取。 // 图片base64编码$path = '/path/to/image';$data = file_get_contents($path);$base64 = base64_encode($data);// 设置请求数据$appkey = 'a95eceb1ac8c24ee28b70f7dbba912bf';$params = array( 'app_id' => '1000001', 'image' => $base64, 'card_type' => '0', 'time_stamp' => strval(time()), 'nonce_str' => strval(rand()), 'sign' => '',);$params['sign'] = getReqSign($params, $appkey);// 执行API调用$url = 'https://api.ai.qq.com/fcgi-bin/ocr/ocr_idcardocr';$response = doHttpPost($url, $params);echo $response;上述echo $response的输出结果即API的响应结果(注意使用UTF-8编码): ...

May 9, 2019 · 1 min · jiezi

吃鸡吗和平精英来了感觉不一般

本博客 猫叔的博客,转载请申明出阅读本文约“3分钟”适读人群:IT/互联网工作者、游戏爱好者 吃鸡吗? 本文部分素材摘抄自“36Kr-《最前线 | 腾讯“吃鸡”游戏或借壳变现,《绝地求生》“成为”《和平精英》》”。玩过吃鸡类手游的朋友,应该都大致了解过各类大厂出的吃鸡游戏吧。今日,腾讯旗下已过审游戏《和平精英》测试服务器安卓端已开启,用腾讯社交账号体系登陆后,继承了《绝地求生:刺激战场》的游戏数据。此外,除了游戏的世界观不太一样,《和平精英》的美术、UI都与《绝地求生:刺激战场》极为相似。 商业变现?高度保密?国家军队机构宣传广告!经济价值我是一个LOL的老玩家了(一脚盲僧),不过吃鸡真的玩不过来,毕竟3D眩晕的感觉一次就足够我体会了。 在TalkingData免费版搜了一下,查询手机游戏的射击类排行,3月份的前10是这样的,前3还是依旧是大厂。 我比较少玩吃鸡(几乎没有),不过对于游戏的好奇感一直高于其他行业。 今天来和大家说点游戏技术上的事情吧。 就说简单的吧,毕竟我本身也不是做专业游戏出身的。说一举例说,就说一下射击子弹与玩家角色之间的关系与基本实现思路。 吃鸡是3D的,我举例就用微信小游戏的模版来说吧,是2D的,不过大同小异。 这个是微信小游戏,官方的Demo,使用快速模板就可以生成运行,是一个很传统的飞机射击游戏,其实原理也很简单,精灵(所有运动角色的简称)是通过x/y轴改变位置来实现移动,过程中精灵的动作可以通过一系列的帧图片实现走动效果或者爆炸。 让我们玩玩这个游戏看看。 我们来说说这个子弹击中敌军飞机,然后爆炸,分数+1的过程。 简单的说,就是判断子弹的坐标与敌军飞机是否重叠或者“接触”,如果是,那么就执行击中音乐、飞机消失、子弹爆炸动画、分数+1等子函数的动作。 如果我们想要让其在判断后,不执行哪一部分的操作,那么也可以将该部分的动作代码注释掉。 如上的游戏效果,就是我把飞机消失的动画效果去除后的游戏体验,因为敌军没有消失,所以当它接触到我方的时候,游戏就结束了。 太久没有玩小程序,一些ES6的语法也记不太清楚了~ 公众号:Java猫说学习交流群:728698035 现架构设计(码农)兼创业技术顾问,不羁平庸,热爱开源,杂谈程序人生与不定期干货。

May 9, 2019 · 1 min · jiezi

知晓推送正式上线送你-13-亿条模板消息

「知晓推送」能帮助小程序运营人员有效解决粉丝转化、消息推送、数据分析等多个层面的麻烦事,让小程序推广难、留存差的问题从此成为过去式。在服务上线的这个重要的日子里,贴心的小云专门向”知晓开发联盟“总部申请了一笔庆祝基金全额当做用户福利发放。(谨遵局长史塔克的教导:钱都不是事儿,先交个朋友~” 于是有了这次巨额福利活动。开不开心鸭! 活动时间:5 月 8 日 - 5 月 22 日 新人专享 - 注册即得活动期间通过下方链接注册的新用户,即可获得 90 元优惠券及 20W 条模板消息。不设上限。 (注册点这里???? https://cloud.minapp.com/?inv...) 充值返利 - 瓜分 13 亿条模板消息活动期间成功充值(含购买模板消息资源包)的小伙伴,将共同瓜分 13 亿条模板消息。充得越早、越多,分得越多。 比如说,今天充 100 大概可以获得 100w 条模板消息,而随着参与人数变多,奖励被稀释,明天充 100 可能就只能分到 50w 条,so 你懂的,速来 ~ 我们将在 5 月 23 日进行抽奖公示并发放奖励。 老用户回馈 - 专属诚意礼包在 5 月 8 日前创建的应用都会获赠一定数额的模板消息。(获赠条数=应用创建月数*套餐每月免费额度;不足 1W 条的向上取整) 另外,活动期间每个升级至个人版或以上版本的应用,都将获赠 50W 条模板消息。 抽奖啦朋友有知晓云限量 T 恤 + 90 元小程序开发基金 (20 份)作为本次活动的奖品。另外邀请好友中奖,你也能得到同等奖励哦~ T 恤长这样????抽奖需要扫描图片下面的微信小程序码哦~打开微信扫描二维码即可参与抽奖???? ...

May 9, 2019 · 1 min · jiezi

小程序Android端movableview拖拽卡顿掉帧的优化

背景: 最近项目中使用到movable-view来做一个拖拽排序的功能,等到功能都实现完成后到真机测试发现,拖拽动画在Android端存在严重的卡顿掉帧,及其不跟手,但是在IOS端却挺流畅。查阅Google发现也有相同的小伙伴有类似问题:小程序的移动拖动图片安卓太过卡顿如何解决导致卡顿掉帧的原因例如页面有 2 个元素 A 和 B,用户在 A 上做 touchmove 手势,要求 B 也跟随移动,movable-view 就是一个典型的例子。一次 touchmove 事件的响应过程为: a、touchmove 事件从视图层(Webview)抛到逻辑层(App Service) b、逻辑层(App Service)处理 touchmove 事件,再通过 setData 来改变 B 的位置 一次 touchmove 的响应需要经过2 次的逻辑层和渲染层的通信 以及一次渲染,通信的耗时比较大。此外setData渲染也会阻塞其它脚本执行,导致了整个用户交互的动画过程会有延迟。 针对以上原因,微信小程序推出了WXS(WX Script),其作用是能够让逻辑代码在视图层(Webview)运行,通过减少数据在视图层和逻辑层之间的传输次数,进而达到优化的目的。具体参考:WXS 在Taro中使用WXS的优化实践背景:由于目前Taro中还没有支持WXS(taro#2959),所以我在项目中不能直接编写WXS代码,让Taro帮我编译成WXML。所以得用点小技巧来实现,希望未来Taro能够支持WXS。如果你是使用原生小程序开发可以直接参考WXS来实现,如果是其他框架则可以参照本文章进行实践。 优化前的代码优化前通过setState来动态更新x,y坐标值,从而利用movable-view达到拖拽效果。 进行优化首先需要去除掉movable-view组件,因为无法使用movable-view和WXS来达到减少数据传输经过的路径次数,其次movable-view是用CSS做的动画,我们可以用position:absolute来代替,在WXS中动态设置top&left的值,达到movable-view的效果。 其次我在小程序开发者dist目录下对应组件(使用到WXS的组件或页面)的目录下创建了一个move.wxs的脚本文件,用于动态设置需要做动画的节点的top&left坐标值。 在dist目录下写move.wxs的原因是因为Taro没有支持WXS,因此无法识别.wxs类型文件,也不会进行编译。 最后在对应的JSX下引入move.wxs并且与touchmove事件绑定。 在线演示经过上面的优化,在Android机型上拖拽动画的流畅度会得到大幅度提升。大家可以扫下方的小程序码进行体验,流程如下: 扫描小程序码进入小程序登陆小程序在个人书库页面,扫描书籍后方的条形码添加几本书籍长按书籍后进行拖拽

May 8, 2019 · 1 min · jiezi

SSL证书转换一关于JKS-转换成-CRT-和-KEY

[SSL证书转换(一)]关于JKS 转换成 CRT 和 KEY之前遇到个问题,客户做小程序系统,而小程序前后端交互需要https协议,因此就需要在后端nginx前置服务器配置SSL证书。而客户给的SSL证书,是Java版的jks证书;且客户提供的配置好基本环境的nginx,所需要的证书是crt和key组合形式,因此需要进行证书转换。在证书转换和证书配置过程中,以及后续的实际生产部署的过程中,也遇到了各种坑。[强烈建议,有钱的用户,或者省事的用户,使用云服务器,不要自建服务器,这样可以有免费的ssl证书,可以很简单的配置] 现在简单记录下配置的步骤:拿到jks证书,和证书密码(确认没有密码的,拿刀找你们运维去,或找供应方去)先将jks 转换成p12格式,具体命令如下:keytool -importkeystore -srckeystore C:\cert\server.jks -destkeystore C:\cert\server.p12 -srcstoretype jks -deststoretype pkcs12输入命令后,会提示你三步骤,需要输入口令(建议输入相同的口令,就是你的jks口令,防止后续证书转换忘记密码) 1).输入目标密钥库口令: 2).再次输入新口令: 3).输入源密钥库口令: 接下来就会提示你如下: 已成功导入别名 ca_root 的条目 已完成导入命令: 1 个条目成功导入, 0 个条目失败或取消 到了这一步,说明已经OK了,剩下的就是转换成crt证书和key了 3.将p12转换成crt证书, 命令如下: openssl pkcs12 -in C:\cert\server.p12 -nokeys -clcerts -out C:\cert\server.crt4.将p12生成非加密的key, 命令如下:openssl pkcs12 -in C:\cert\server.p12 -nocerts -nodes -out C:\cert\server.key5.将证书配置到nginx以后,重启nginx服务器 6.使用ssl漏洞扫描工具,检验证书链的完整性,并获取证书链(<font color=red>防止小程序报: fail ssl hand shake error</font>),推荐地址https://myssl.com/chain_download.html 7.拷贝证书链以后,将服务器上server.crt内容替换,重启nginx(或nginx -s reload) 8.如果还不行,(比如:网页访问,依然不安全) 请清空缓存,刷新 ps : 至于以上的命令,比如: keytool、openssl哪里来?你问我?问我为什么不安装下呢?百度啊!

May 6, 2019 · 1 min · jiezi

小程序如何生成海报分享朋友圈

项目需求写完有一段时间了,但是还是想回过来总结一下,一是对项目的回顾优化等,二是对坑的地方做个记录,避免以后遇到类似的问题。 需求利用微信强大的社交能力通过小程序达到裂变的目的,拉取新用户。生成的海报如下 需求分析1、利用小程序官方提供的api可以直接分享转发到微信群打开小程序2、利用小程序生成海报保存图片到相册分享到朋友圈,用户长按识别二维码关注公众号或者打开小程序来达到裂变的目的 实现方案一、分析如何实现相信大家应该都会有类似的迷惑,就是如何按照产品设计的那样绘制成海报,其实当时我也是不知道如何下手,认真想了下得通过canvas绘制成图片,这样用户保存这个图片到相册,就可以分享到朋友圈了。但是要绘制的图片上面不仅有文字还有数字、图片、二维码等且都是活的,这个要怎么动态生成呢。认真想了下,需要一点一点的将文字和数字,背景图绘制到画布上去,这样通过api最终合成一个图片导出到手机相册中。 二、需要解决的问题1、二维码的动态获取和绘制(包括如何生成小程序二维码、公众号二维码、打开网页二维码)2、背景图如何绘制,获取图片信息3、将绘制完成的图片保存到本地相册4、处理用户是否取消授权保存到相册 三、实现步骤这里我具体写下围绕上面所提出的问题,描述大概实现的过程 ①首先创建canvas画布,我把画布定位设成负的,是为了不让它显示在页面上,是因为我尝试把canvas通过判断条件动态的显示和隐藏,在绘制的时候会出现问题,所以采用了这种方法,这里还有一定要设置画布的大小。 <canvas canvas-id="myCanvas" style="width: 690px;height:1085px;position: fixed;top: -10000px;"></canvas>②创建好画布之后,先绘制背景图,因为背景图我是放在本地,所以获取 <canvas> 组件 canvas-id 属性,通过createCanvasContext创建canvas的绘图上下文 CanvasContext 对象。使用drawImage绘制图像到画布,第一个参数是图片的本地地址,后面两个参数是图像相对画布左上角位置的x轴和y轴,最后两个参数是设置图像的宽高。 const ctx = wx.createCanvasContext('myCanvas')ctx.drawImage('/img/study/shareimg.png', 0, 0, 690, 1085)③创建好背景图后,在背景图上绘制头像,文字和数字。通过getImageInfo获取头像的信息,这里需要注意下在获取的网络图片要先配置download域名才能生效,具体在小程序后台设置里配置。 获取头像地址,首先量取头像在画布中的大小,和x轴Y轴的坐标,这里的result[0]是我用promise封装返回的一个图片地址 let headImg = new Promise(function (resolve) { wx.getImageInfo({ src: `${app.globalData.baseUrl2}${that.data.currentChildren.headImg}`, success: function (res) { resolve(res.path) }, fail: function (err) { console.log(err) wx.showToast({ title: '网络错误请重试', icon: 'loading' }) } }) }) let avatarurl_width = 60, //绘制的头像宽度 avatarurl_heigth = 60, //绘制的头像高度 avatarurl_x = 28, //绘制的头像在画布上的位置 avatarurl_y = 36; //绘制的头像在画布上的位置 ctx.save(); // 先保存状态 已便于画完圆再用 ctx.beginPath(); //开始绘制 //先画个圆 前两个参数确定了圆心 (x,y) 坐标 第三个参数是圆的半径 四参数是绘图方向 默认是false,即顺时针 ctx.arc(avatarurl_width / 2 + avatarurl_x, avatarurl_heigth / 2 + avatarurl_y, avatarurl_width / 2, 0, Math.PI * 2, false); ctx.clip(); //画了圆 再剪切 原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内 ctx.drawImage(result[0], avatarurl_x, avatarurl_y, avatarurl_width, avatarurl_heigth); // 推进去图片 这里举个例子说下如何绘制文字,比如我要绘制如下这个“字”,需要动态获取前面字数的总宽度,这样才能设置“字”的x轴坐标,这里我本来是想通过measureText来测量字体的宽度,但是在iOS端第一次获取的宽度值不对,关于这个问题,我还在微信开发者社区提了bug,所以我想用另一个方法来实现,就是先获取正常情况下一个字的宽度值,然后乘以总字数就获得了总宽度,亲试是可以的。 ...

May 6, 2019 · 6 min · jiezi

Licia-支持小程序的-JS-工具库

导语Licia 是一套在开发中实践积累起来的实用 JavaScript 工具库。该库目前拥有超过 300 个模块,同时支持浏览器、node 及小程序运行环境,提供了包括日期格式化、md5、颜色转换等实用模块,可以极大地提高开发效率。 前言因为小程序运行的是 JavaScript 代码,传统前端所使用的 JS 库理应也能够被用在小程序中才对。然而,经过实际测试,你会发现有相当一部分 npm 包是无法直接在小程序中跑起来的。比如前端工程师十分常用的 lodash,在小程序中引入会报错。 为什么会这样? 主要原因就是绝大部分库的开发者在设计时只会考虑两种运行环境,浏览器和 node,而小程序并不会在其考虑范围内。因此,只要开发者的 JS 代码使用了只有浏览器与 node 中才有的接口,如 DOM 操作、文件读写等,该库就不能正常地运行在小程序环境中。除此之外,假如他们使用了小程序禁用的功能,例如全局变量与动态代码执行,这时候代码跑在小程序环境也会出错。 使用使用 npm 安装1、 安装 npm 包 npm i miniprogram-licia --save2、点击开发者工具中的菜单栏:工具 --> 构建 npm 3、直接在代码中引入使用 const licia = require('miniprogram-licia');licia.md5('licia'); // -> 'e59f337d85e9a467f1783fab282a41d0'licia.safeGet({a: {b: 1}}, 'a.b'); // -> 1生成定制化 util.js使用 npm 包的方式会将所有功能引入到代码包中,大概会增加 100 kb 的大小。如果你只想引入所需脚本,可以使用在线工具生成定制化 util 库。 1、访问 https://licia.liriliri.io/builder.html 2、输入需要的模块名,点击生成下载 util.js。 3、将生成的工具库拷贝到小程序项目任意目录下然后直接引入使用。 const util = require('../lib/util');util.wx.getStorage({ key: 'test'}).then(res => console.log(res.data));优点1、目前拥有 270 多个模块可在小程序中正常运行,而 underscore 只有 120 个函数左右。 ...

May 5, 2019 · 3 min · jiezi

为微信小程序开发的网易云音乐api库

之前我们已经开发过一款小程序适用的qq音乐api库https://github.com/FisherWY/Q...,这次开发网易云音乐api库的原因是qq音乐api库在小程序中iOS环境下无法使用小程序提供的背景音频播放器播放的问题网易云的加密算法真的比其他几家api复杂太多了。。。完爆QQ和酷狗想要直接用的话可以到Github直接取我封装好的api库。Github地址https://github.com/JabinGP/Ne... 依赖本api库参考了Github上面开源的node库,因为我们只想要查找音乐和播放音乐这两个功能,虽然Github那个库很方便,但是我们不想为了两个接口特意去跑一个node.js服务。Github上的库 big-integer.js 这里注意,不要使用最新版的,最新版的库再模拟器上运行没有问题,但是在真机调试的上传包阶段会报错说无法识别big-integer.js,最后在我的尝试下,选用了一个老版本的库解决了这个问题。crypto-js这个库是用来aes加密的,在node上面有一个原生的crypto,但是在小程序里我们没有,所以我照着Github上的源码一点一点用这个库翻译过来的,还有Buffer在小程序里也没有,我使用这个库的方法代替了。 获取api的原理网上很多帖子讲的很清楚了,这里推荐几篇文章,我只做一个简单的总结,方便大家理解这个库。网易云的加密算法大概使用了两个: AES加密+BASE64编码RSA加密加密大致流程: api请求信息先被转成json字符串格式,然后再使用一个固定的密钥aes+base64编码加密,得到了第一个加密结果a。客户端从abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/随机生成一个新的16位密钥,然后用这个密钥去加密加密结果a,得到加密结果b。3.这样我们的数据就被双重加密了,但是我们要发给服务器去查询对应的数据,服务器知道第一个固定的密钥是多少,可以解开第一个加密结果,但是服务器可不知道我们第二次加密用的是什么,所以服务器还需要得到我们的第二个生成的随机加密密钥。 第二个随机加密密钥要是直接发给服务器好像就不太安全了,所以客户端对第二个随机加密密钥也进行了加密,使用的就是RSA加密,加密后得到的数据我们称为c将b和c发送给服务器,服务器就会返回给我们对应的结果了。加密核心代码这段代码传入对象后可以直接加密成符合网易云api加密的结果。 // 生成随机数,size默认16function createSecretKey(size) { const keys = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" let key = "" for (let i = 0; i < size; i++) { let pos = Math.random() * keys.length pos = Math.floor(pos) key = key + keys.charAt(pos) } return key}// aes加密方法function aesEncrypt(word, secKey) { let key = CryptoJS.enc.Utf8.parse(secKey); //十六位十六进制数作为密钥 let iv = CryptoJS.enc.Utf8.parse(aes_mv); //十六位十六进制数作为密钥偏移量 let srcs = CryptoJS.enc.Utf8.parse(word); let encrypted = CryptoJS.AES.encrypt(srcs, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); let res = encrypted.toString(); console.log(res); return res;}// 填充方法function zfill(str, size) { while (str.length < size) str = "0" + str return str}// rsa加密方法function rsaEncrypt(text, pubKey, modulus) { const _text = text.split('').reverse().join('') const biText = bigInt(CryptoJS.enc.Utf8.parse(_text).toString(), 16), biEx = bigInt(pubKey, 16), biMod = bigInt(modulus, 16), biRet = biText.modPow(biEx, biMod) return zfill(biRet.toString(16), 256)}// 加密总入口function Encrypt(obj) { const text = JSON.stringify(obj) const secKey = createSecretKey(16) const encText = aesEncrypt(aesEncrypt(text, nonce), secKey) const encSecKey = rsaEncrypt(secKey, pubKey, modulus) return { params: encText, encSecKey: encSecKey }}封装好的Api库首先到Github下载我的Api库https://github.com/JabinGP/Ne...下载完成后,这个库应该是可以直接导入微信小程序开发工具运行的,但是有几个注意事项 ...

May 4, 2019 · 3 min · jiezi

UI组件-来做一个可配置的滑块进度条吧

在一些需要用户填写资料的业务场景中,有时会让用户选择某个业务的范围,这时就需要用到滑块进度条。然后你们最爱的产品经理会说,给我整一个颜色可控,滑块按钮可大可小,滑块边框也要可大可小的滑动条来.. emmm,一看这样的设计需求就意味着小程序原生的slider组件就不能用了。因为这玩意在样式上就不能自由的配置,只好来手动实现一个。 结构设计 行吧,那说干就干。首先滑动条可以从俯视图角度来看,分为三层。分别是底部滑轨区域,进度条区域以及供用户操作的滑块本身。 在结构设计中,可以将底部滑轨区域,进度条区域分为一块,这样进度条区域可以根据随着滑动条的高度变化而变化, 宽度则由js控制。除此之外还需要暴露一些参数给外部,让它自己定义长粗宽。 Component({ /** * 组件的属性列表 */ properties: { // 滑块大小 blockSize: { type: Number, value: 32, }, // 滑块宽度 blockBorderWidth: { type: Number, value: 3 }, // 滑轨高度 height: { type: Number, value: 2 }, // 滑轨进度 step: { type: Number, value: 0, }, // 进度值小数位 digits: { type: Number, value: 0, }, },});<view id="slider-wrap" class="slider-wrap"> <view class="silder-bg" style="height: {{height}}rpx;"> <view class="silder-bg-inner"></view> </view> <view class="silder-block" style="height: {{blockSize}}rpx; border-width: {{blockBorderWidth}}rpx;" ></view></view>.slider-wrap { position: relative; display: flex; align-items: center; width: 100%;}.silder-bg,.silder-bg-inner,.silder-block { position: absolute; left: 0;}.silder-bg,.silder-bg-inner { width: 100%; height: 2rpx; flex: 1;}.silder-bg { overflow: hidden; background-color: #eeeeee; border-radius: 8rpx; z-index: 0;}.silder-bg-inner { height: 100%; background-color: #66a6ff; /* border-radius: 8rpx; */ z-index: 1; border-bottom-left-radius: 8rpx; border-top-left-radius: 8rpx;}.silder-block { width: 32rpx; height: 32rpx; background-color: #ffffff; border: solid 3rpx #66a6ff; z-index: 2; border-radius: 50%; box-sizing: border-box;}点击行为事件滑块进度条的滑块是一个听话的小朋友,就是说我们叫它去哪它就听话的过去。所以就不要抓它去煲汤了~在组件外部容器中绑定一个点击事件,我们必须得要知道用户点击位置,在bind:tap事件中取到clientX属性。除此之外还需要取到进度条的位置信息。 ...

May 4, 2019 · 4 min · jiezi

Fundebug-微信小程-BUG-监控插件更新至-121优化错误上报次数的限制算法

摘要: 1.2.1优化错误上报次数的限制算法,新增silentHttpHeader配置选项,请大家及时更新哈! Fundebug提供专业的微信小程序 BUG 监控服务,可以第一时间为您捕获生存环境中小程序的异常、错误或者 BUG,及时给开发者发送报警,帮助您快速修复 BUG。欢迎大家免费试用,也欢迎各位用户反馈建议或者问题。 优化错误上报次数的限制算法在小程序生命周期之内,Fundebug 最多错误上报次数为 50 次,这是为了避免无限循环导致无限报错。这里所说的生命周期,指的是小程序仍然存在于内存里面。 根据微信小程序的文档,wx.request的最大并发限制是  10  个。因此,Fundebug 同一时间上报的错误数最多为 5 个,这是为了避免占用微信小程序的网络请求的并发数。 silentHttpHeader如果你不希望监控 HTTP 请求错误的 Header 的话,可以将 silentHttpHeader 属性设为 true: fundebug.init({ silentHttpHeader: true});最后,感谢 Fundebug 用户熊文的反馈。 参考Fundebug 文档 - silentHttpHeader微信小程序文档 - 网络关于FundebugFundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了10亿+错误事件,付费客户有Google、360、金山软件、百姓网等众多品牌企业。欢迎大家免费试用! 版权声明转载时请注明作者Fundebug以及本文地址:https://blog.fundebug.com/2019/04/29/fundebug-wechat-miniprogram-upgrade-1-2-1/

April 30, 2019 · 1 min · jiezi

行业log-4月不能错过的微信小程序更新动态

延伸阅读:《码code | 小程序接入「激励式视频广告」硬核指南》 《云调用,小程序鉴权正确姿势》

April 30, 2019 · 1 min · jiezi

Taro小程序从0到1架构项目打造自己的完美脚手架

这个可以让你的Taro小程序跑的更优雅一些 https://github.com/wsdo/taro-kit7个月前输出了一套taro-kit 脚手架,有不少人加我微信,咨询一些问题,这段时间把这个脚手架升级后,总结并录制了课程,希望能帮助到大家,提高效率,节约时间。升级后的项目仓库地址: 观看视频的同学加微信,发送你的gitlab账号,添加权限,你就看源代码了。https://gitlab.com/itxishu/ta... 课程地址思否编程 segmentfaulthttps://segmentfault.com/ls/1... 适宜人群taro小程序开发者需要taro基础架构开发人员课程说明本次课程主要针对于,正在使用taro小程序框架的同学,通过课程,你可以学到,框架的request请求优雅封装,异常自动重试,日志异常上报,redux的三剑客优雅的配合使用,reducer 的swich简化繁琐操作,增加state的请求前,请求成功和失败的状态等。从开始架构足以支撑庞大业务小程序项目 课程有问题可以在 https://shudong.wang 我的博客扎到我,添加微信咨询 课程大纲01.taro从0到1项目架构课程介绍02.初始化项目流程介绍、目录设计03.让alias别名解决路径引用的烦恼04.请求api返回redux的状态流程05.封装request get请求,给url添加时间戳防止浏览器缓存06.封装request post Content-Type 分类请求07.把taro-advance脚手架推送到私有仓库08.弱网请求失败时自动发起api重试09.异常日志上报封装设计思路10.异常日志上报封装,五种级别输出。11.上报收集日志平台系统介绍12.实战接入日志平台13.深度序列化错误error控制台上报14.登录流程讲解(前端和后端实现流程)15.登录实现详细讲解(token附加到请求header头)16.用户授权后更新用户信息流程17.设计createApiAction自动dispatch优化开发体验18.改造actionType支持庞大业务19.Action三种ActionType的集合20.简化reducers的swich繁琐操作21.增加request的状态22.课程总结 课程主站https://www.itxishu.comhttps://github.com/itxishu 关于https://shudong.wang 有问题来这里提问http://t.shudong.wang

April 28, 2019 · 1 min · jiezi

从-VantComponent-谈-小程序维护

在开发小程序的时候,我们总是期望用以往的技术规范和语法特点来书写当前的小程序,所以才会有各色的小程序框架,例如 mpvue、taro 等这些编译型框架。当然这些框架本身对于新开发的项目是有所帮助。而对于老项目,我们又想要利用 vue 的语法特性进行维护,又该如何呢? 在此我研究了一下youzan的 vant-weapp。而发现该项目中的组件是如此编写的。 import { VantComponent } from '../common/component';VantComponent({ mixins: [], props: { name: String, size: String }, // 可以使用 watch 来监控 props 变化 // 其实就是把properties中的observer提取出来 watch: { name(newVal) { ... }, // 可以直接使用字符串 代替函数调用 size: 'changeSize' }, // 使用计算属性 来 获取数据,可以在 wxml直接使用 computed: { bigSize() { return this.data.size + 100 } }, data: { size: 0 }, methods: { onClick() { this.$emit('click'); }, changeSize(size) { // 使用set this.set(size) } }, // 对应小程序组件 created 周期 beforeCreate() {}, // 对应小程序组件 attached 周期 created() {}, // 对应小程序组件 ready 周期 mounted() {}, // 对应小程序组件 detached 周期 destroyed: {}});居然发现该组件写法整体上类似于 Vue 语法。而本身却没有任何编译。看来问题是出在了导入的 VantComponet 这个方法上。下面我们开始详细介绍一下如何利用 VantComponet 来对老项目进行维护。 ...

April 27, 2019 · 5 min · jiezi

微信小程序-unionid-登录解决方案

第三方登录模块使开发者能快捷灵活的拥有自己的用户系统,是 LeanCloud 最受欢迎的功能之一。随着第三方平台的演化,特别是微信小程序的流行,LeanCloud 第三方登录模块也一直在改进: v2.0*:增加微信小程序一键登录功能。支持开发者不写任何后端代码实现微信小程序用户系统与 LeanCloud 用户系统的关联。v3.6:增加 unionid 登录接口。支持开发者使用 unionid 关联一个微信开发者帐号下的多个应用从而共享一套 LeanCloud 用户系统。这两个功能各自都非常简单可靠,但是其中重叠的部分需求却是一个难题:「如何在小程序中支持 unionid 登录,既能得到 unionid 登录机制的灵活性,又保留一键登录功能的便利性」。 在最近发布的 JavaScript SDK v3.13 中包含了微信小程序 unionid 登录支持。我们根据不同的需求设计了不同的解决方案。 *这里的版本指开始支持该功能的 JavaScript SDK 版本。 一键登录LeanCloud 的用户系统支持一键使用微信用户身份登录。要使用一键登录功能,需要先设置小程序的 AppID 与 AppSecret: 1.登录 微信公众平台,在 设置 > 开发设置 中获得 AppID 与 AppSecret。前往 LeanCloud 控制台 > 组件 > 社交,保存「微信小程序」的 AppID 与 AppSecret。这样你就可以在应用中使用 AV.User.loginWithWeapp() 方法来使用当前用户身份登录了。 AV.User.loginWithWeapp().then(user => { this.globalData.user = user;}).catch(console.error);使用一键登录方式登录时,LeanCloud 会将该用户的小程序 openid 与 session_key 等信息保存在对应的 user.authData.lc_weapp 属性中,你可以在控制台的 _User 表中看到: ...

April 26, 2019 · 3 min · jiezi

uniapp-全局变量globalData

uni-app神坑记录uni-app 在app.vue文件export default里面定义globalData,在当前文件(app.vue)里面获取globalData需要用this.$options.globalData获取,其他文件则用getApp().globalData获取 app.vue this.$options是用来获取自定义属性...

April 26, 2019 · 1 min · jiezi

小程序页面栈管理

小程序页面栈的管理小程序的每个页面都是一个page对象,小程序中页面栈最多十层,了解小程序页面栈的管理机制有助于我们进行页面跳转参数的传递,以及在目的页面改变原页面的属性达到传参的效果: 通过getCurrentPages();获取页面栈内所有的Page对象,去某一个Page对象即可操作其方法和属性。 比如页面跳转传参: A调用wx.navigateTo({ url: '/pages/B/B' });  跳转到B页面,此时的动作是push(入栈)一个页面,其效果如下: B页面从栈里面取A页面的Page对象: ` var currPage = pages[pages.length - 1];   //当前页面,B页面Page对象var prevPage = pages[pages.length - 2];  //上一个页面,A页面的Page对象  3. 调用setData传参:prevPage.setData({name:"三三" }); 4. 调用wx.navigateBack();即可返回到上一个页面,此时即A页面,这是一个页面出栈(pop)的过程; 5. 调用wx.redirectTo();这是一个原页面出栈,新页面入栈的过程;

April 26, 2019 · 1 min · jiezi

从入门到撞门手把手教你开发一款记录类小程序

最近开发了一款记录类的小程序“我我”,决定把这段时间里学到的知识由浅到深的总结一下,分享给大家,如有不对之处还望大佬指出。 目录小程序的申请开发者工具的使用小程序的开发统计发布进阶1. 小程序的申请小程序的申请流程可以照着官网的教程走,需要注意的是,后台的设置里,很多项目一个月只能改3/5次,开发-->开发设置-->服务器域名一个月也只能改5次,所以建议提前规划好要修改的内容,比如服务器域名,应该提前把接口地址、图片资源地址、统计打点地址等域名统一填好(审核有延迟,一般为1小时左右)。 另外,申请的账号邮箱最好不要用个人邮箱,建议专门注册一个产品用的,不然这个同事离职了的话账号处理会很蛋疼。 2. 开发者工具的使用 右上角详情里,可以把这些选项都点上,如果有使用npm模块,则把那个选项也点上。如果有域名还未申请或还未通过审核,可以把最后一个选项点上,就可以跳过白名单检查。如果有使用npm模块,还需要点击工具-->构建npm,生成一个miniprogram_npm文件。如果有用到shell命令去控制开发者工具,则需要把设置-->安全设置-->安全里的服务端口开启,至于如何用shell命令,以及用它的好处是什么,让我们放后面慢慢聊。 3. 小程序的开发3.1 小程序文件结构项目├── components // 组件├── node_modules // 项目依赖├── miniprogram_npm├── page // 页面├── images├── .gitignore├── app.json├── app.wxss├── app.js├── package.json├── project.config.json└── README.md3.2 自定义topbar的开发因为“我我”项目需要自定义topbar,所以需要解决这些问题: 获取胶囊到手机顶部的距离,使返回按钮和标题能自适应与胶囊处于同一行。 wx.getSystemInfo({ success: function(res) { that.globalData.comPostInfo = res; if (res.system.indexOf('iOS') > -1) { that.globalData.system = 'ios'; that.globalData.paddingTop = res.statusBarHeight + 6; } else { that.globalData.system = 'android'; that.globalData.paddingTop = res.statusBarHeight + 10; } }});通过wx.getSystemInfo的statusBarHeight能获取到胶囊到手机顶部的距离,再根据需要加上几像素令文字与胶囊居中。 另外,返回按钮并不是所有情况都该出现,当用户处于一级页面,或者通过二维码进入时,这时候就不该有返回按钮了(如果是通过二维码等方式进入,还应该加上一个返回首页的按钮),这里我们这样判断一下: let that = this;let tabs = ['pages/index/index', 'pages/find/find', 'pages/msg/msg', 'pages/me/me'] // “我我”里的4个一级页面let pages = getCurrentPages();for (let i = 0; i < pages.length; i++) { let page = pages[i]; if (tabs.indexOf(page.route) > -1) { break; } else { that.setData({ show: true }); }}通过getCurrentPages来获取当前页面列表进而判断是否有一级页面存在。 ...

April 26, 2019 · 3 min · jiezi

Fundebug支付宝小程序BUG监控插件更新至020新增test方法报错增加Page数据

摘要: 0.2.0新增fundebug.test()方法,同时报错增加了Page数据。 Fundebug提供专业支付宝小程序BUG监控服务,可以第一时间为您捕获生存环境中小程序的异常、错误或者BUG,及时给开发者发送报警,帮助您快速修复BUG。欢迎大家免费试用,也欢迎各位用户反馈建议或者问题。 test(name, message)fundebug.test()用于测试,可以将测试数据发送到Fundebug,并收到报警邮件。 name: 错误名称,参数类型为字符串,默认值为"Test"message: 错误信息,参数类型为字符串,默认值为"Hello, Fundebug!"示例: fundebug.test()fundebug.test("Test", "Hello, Fundebug!")fundebug.test() 主要用于测试,它发送的错误每次都会报警邮件(每天的限额是 20 封),这样可能会给您造成困扰。为了避免重复报警,请使用其他 API 记录错误,这样同一个错误将只会在错误数达到阈值(10, 100, 100...)的时候报警。 notifynotifyErrorPageFundebug插件会调用getCurrentPages方法获取报错页面的Page数据,与错误数据一起上报: { "route": "pages/index/index", "_viewId": "1556021552987", "data": { "title": "Alipay" }}如果不需要收集Page数据的话,可以将silentPage属性设为true: fundebug.init({ silentPage : true})最后,感谢 Fundebug 用户闵胖胖的反馈。 参考Fundebug文档 - fundebug.test()Fundebug文档 - silentPage关于FundebugFundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了10亿+错误事件,付费客户有Google、360、金山软件、百姓网等众多品牌企业。欢迎大家免费试用! 版权声明转载时请注明作者Fundebug以及本文地址:https://blog.fundebug.com/2019/04/25/fundebug-alipay-miniprogram-upgrade-0-2-0/

April 26, 2019 · 1 min · jiezi

基于mpvue小程序使用echarts画折线图

第一次使用mpvue框架来写小程序,项目开发直接搬用mpvue-shop(一个仿网易严选的小程序开发项目),项目结构清楚,实现了大部分功能,对于初次使用mpvue的小伙伴们来说,是一个很好的选择。关于组件的选择:1.echarts-for-weixin,官方echarts的小程序版本。使用参考:echarts-for-weixin介绍,如果你是原生开发小程序版本,这个组件非常适合你,开发过程中可使用echarts官方提供的所有配置和Api,但并不适合mpvue项目。 2、wx-charts,一个个人开发的微信小程序图表插件,体积只有30K,可用于mpvue项目和原生小程序项目,支持大部分图表绘制,缺点是可配置化不强,对于UI没有太大要求的可使用此组件,比较适合于个人项目开发。 3、mpvue-echarts与echarts结合。特别适合mpvue项目,mpvue-echarts是一个基于mpvue开发的echarts组件,echarts的加入可完全使用官方所有的图表绘制功能,让echarts在小程序当中得到全部应用。 mpvue-echarts配合echarts的使用下载相关包 npm install mpvue-echarts --save echarts的下载可到官网上下载,由于小程序中对文件大小有限制,建议通过勾选所需要的功能按需下载。 vue文件中使用 template: <mpvue-echarts :echarts="echarts" :onInit="initChart" canvasId="demo-canvas" /> js: import mpvueEcharts from 'mpvue-echarts';let echarts = require("../../../static/lib/echarts.min.js"); //按需下载的压缩文件放在项目文件夹中import charts from './charts'; //本地mixin文件,图表的所有配置let chart = null;export default { data() { return { echarts, }; }, async mounted() { let data = await post("/product/marketInfo",{ }); this.initCombineLineData(data.trendData); chart.setOption(this.trendChart); }, mixins: [charts], methods: { initChart(canvas, width, height) { chart = echarts.init(canvas, null, { width: width, height: height }); canvas.setChart(chart); chart.setOption(this.trendChart); return chart; } }, components: { mpvueEcharts }}charts.js文件 ...

April 24, 2019 · 2 min · jiezi

获取已发布微信小游戏和小程序源码

小游戏或者小程序和 H5 、 网页 不一样,不能直接F12 看代码,要怎么才能拿他们的代码呢 ? 那么具体怎么实现呢 ,接下来具体说一下: 首先需要知道的是小程序在手机里的文件储存那么这个位置具体在哪呢 ? 具体目录位置:/data/data/com.tencent.mm/MicroMsg/{{一串32位的16进制字符串名文件夹}}/appbrand/pkg/ 在这个目录下会有一些 xxx.wxapkg 这样后缀的文件,这些就是小程序或者小游戏的包。xxx.wxapkg 是什么呢?微信小程序源码阅读笔记1 这里有一篇详细介绍的文件 大家可以看一下。 获取小程序的 .wxapkg 包在电脑上用root过的安卓的手机模拟器 ,上安装RE文件管理器 ,然后通过管理器获取到的。 具体实现 :1 、 安装手机模拟器(这里我用的是夜神模拟器) 下载地址 :https://www.yeshen.com/cn/dow... 2 、 在模拟器上安装 微信 , qq ,RE管理器 RE管理器先下载到电脑上,然后再拖到模拟器里面就可以了。 RE管理器 下载地址 :YPSuperKey Checkedhttps://pan.baidu.com/s/1PPBx08rNutXxhlMMJbuTpQ 微信 ,qq 直接在模拟上下载。3 、 设置超级用户 安装好RE 管理器之后需要 给RE 设置超级用户这个权限。4 、 去缓存小游戏或小程序 打开微信 然后找到你想要获取代码的小游戏或小程序 打开这个小游戏或小程序,程序开始运行之后源文件就已经下载到本地了。5 、 找到源文件 将模拟器的操作页面切换到桌面 ,运行RE管理器 ,然后在管理器里面找到之前说到的那个目录:/data/data/com.tencent.mm/MicroMsg/{{一串32位的16进制字符串名文件夹}}/appbrand/pkg/ 这里这些就是我们需要的源文件包,然后再通过 访问的时间 找到刚才运行的程序是哪一个就可以了。6 、 压缩 ...

April 24, 2019 · 1 min · jiezi

小程序开发二使用hapi快速开发接口

上篇文章中,我们介绍了数据采集相关的知识,这篇文章中,我们来整理下nodejs开发后台常用的库,然后选择hapi来进行restful API的开发,以及定时任务、RPC的使用。nodejs主流框架介绍我们先来看下目前nodejs主流的框架: 1. Express(43.4k)对于一个已经在使用nodejs的开发人员来说,Express并不是一个新鲜事,它提供了对nodejs原始API的比较好的封装,从而使开发者更加容易使用nodejs。 2. Meteor(41k)Meteor也是一个很出色的框架,记得官网有一句话,“Ship more with less code”, 确实也是像这句话一样,不管是服务器数据库的访问,业务逻辑实现,还是客户端的展示,所有的流程都是开箱即用的。还有一个点应该是 “配置大于开发”的思想,很多东西都是可以直接通过配置来实现,不需要太多的代码,这点我觉得也是这个框架很厉害的一个点。 3. Koa(25.8k)Koa是express的原班人马开发的,核心是ES6的generator,使用generator来实现中间件的流程控制,在Koa框架中就再不会看到复杂的callback了。框架本身非常小,只打包了一些必要的功能,但是它本身通过良好的模块化组织,让使用者可以按照自己的想法来实现一个扩展性非常好的应用。 4. sails(20.4k)Sails在底层使用express来提供对http请求的处理,同时使用Socket.IO框架来处理websocket请求,也通过waterline框架实现了ORM功能,你的应该程序可以在不进行大的修改的前提下,就可以从一个后端数据库,切换到另外后端数据库(也可以是一个NoSQL数据库)。 5. egg(12.4k)egg是阿里的一个团队,基于Koa开发的框架,奉行【约定优于配置】,按照一套统一的约定进行应用开发,插件机制也比较完善,也是很好用的。之前写的微博词云的api就是用egg来写的,http://zz.mcust.cn,这个网站也是egg来写的。 6.hapi(11k)Hapi在众多的框架中并非一个老牌选手,然而他却成功的在这当中创造了自己的一个生态圈。致力于完全的分离node HTTP服务器,路由以及业务逻辑,并更多的聚焦于如何尽可能的通过配置而非代码来控制东西。 这次选择Hapi的原因其实也很简单,因为之前没用过。 使用Hapi每一次学习一个东西,其实套路都是差不多的,我们先去官网看看。 这里我们有很多的关键点,有更新信息,指南说明,api文档,插件,版本号,最近更新时间,下载次数,源码等等信息。看更新时间和下载次数看来,活跃人数还是比较多的,这些数据也能从某个维度上来对一个框架的做一些评判。 然后进入tutorials,照着里面的教程动手实践一下,学习如何创建http服务,如何使用路由,获取url参数,cookies,日志、验证、视图等等。 下面就正式进入小程序的接口开发中 创建项目,项目文件目录大致如下: models代表数据模型,我在里面定义了sequelize的模型,数据结构;controllers里边是大部分的业务逻辑;routers里边定义了路由,以及参数的验证,处理路由的方法等;common里面定义了公共的一些方法,一些加密的方法,生成uuid的方法等;config里面是项目数据库配置和插件配置;log是放日志文件的地方。 然后我们这里也用了很多的插件,和一些工具包等来帮助我们更快地完成任务。 这块其实比较重要的一点是热部署,开发环境中,使用了supervisor来部署;而生产环境我们是用了pm2来部署。 下面我们来看下hapi中如何使用定时任务 我们先看看hapi有没有已经有的定时任务工具,我们去官网插件里搜一下“cron”, 发现是有的,那我们就直接用hapi-cron这个库即可。 需要先配置下定时任务: 然后注入到服务中即可。 上面的配置表示每天的6点、11点、16点、23点回去请求/spider_articles这个请求。对cron表达式不熟悉的同志们可以稍微补补这方面的知识。 然后这个接口里是发送了三个请求,是我们上次部署好的爬虫服务。 这样我们就通过定时任务完成了定时去爬数据的工作。 别的接口都是比较正常的,需要操作下数据库即可,还有一部分是需要rpc的,也是比较简单好理解的,在这里就不细谈了。 本节关于hapi的部分到这里就结束了。 NEXT下一篇,我们会介绍小程序的开发,mpvue,以及小程序原始组件的使用,还有小程序一些重要的配置等。

April 24, 2019 · 1 min · jiezi

小程序开发一使用scrapy爬虫采集数据

过完年回来,业余时间一直在独立开发一个小程序。主要数据是8000+个视频和10000+篇文章,并且数据会每天自动更新。 我会整理下整个开发过程中遇到的问题和一些细节问题,因为内容会比较多,我会分成三到四篇文章来进行,本文是该系列的第一篇文章,内容偏python爬虫。 本系列文章大致会介绍一下内容: 数据准备(python的scrapy框架)接口准备(nodejs的hapijs框架)小程序开发(mpvue以及小程序自带的组件等)部署上线(小程序安全域名等配置以及爬虫/接口等线上部署维护) 数据获取 数据获取的方法有很多种,这次我们选择了爬虫的方式,当然写一个爬虫也可以用不同的语言,不同的方式。之前写过很多爬虫,这次我们选择了python的scrapy库。关于scrapy,百度百科解释如下: Scrapy,Python开发的一个快速、高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据。Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试。 学习scrapy,最好的方式就是先阅读一遍文档(Scrapy 1.6 documentation),然后照着文档里的例子写一写,慢慢就熟悉了。里面有几个很重要的概念是必须要理解的: Items 官方对items的定义是“The main goal in scraping is to extract structured data from unstructured sources, typically, web pages.”,个人理解为数据结构,也就是要爬取数据的字段,最好能和数据库字段对应,便于入库。Spiders “Spiders are classes which define how a certain site (or a group of sites) will be scraped, including how to perform the crawl (i.e. follow links) and how to extract structured data from their pages (i.e. scraping items). ”,也就是爬虫比较核心的内容,定义爬虫的方式,一些策略,以及获取那些字段等等。pipelines ...

April 23, 2019 · 1 min · jiezi

字节跳动小程序开发中遇到的问题与处理

和微信小程序差不多了。1、button组件设置圆角时 边框还是保持原来的样子,样式选择器:after{border:none}即可

April 22, 2019 · 1 min · jiezi

Fundebug微信小程序错误监控插件更新至1.1.0,新增test()与notifyHttpError()方法

摘要: 1.1.0新增fundebug.test()和fundebug.notifyHttpError()方法,同时大小压缩至15K。 Fundebug是专业的小程序BUG监控服务,可以第一时间为您捕获生存环境中小程序的异常、错误或者BUG,及时给开发者发送报警,帮助您快速修复BUG。欢迎大家免费试用,也欢迎各位用户反馈建议或者问题。 test(name, message)使用 fundebug.test()方法可以用于测试 Fundebug 插件。 name: 错误名称,参数类型为字符串,默认值为"Test" message: 错误信息,参数类型为字符串,默认值为"Hello, Fundebug!" 示例 1 : 没有参数 fundebug.test();示例 2 : 带参数 fundebug.test("Hello", "This is a Test");fundebug.test() 主要用于测试,它发送的错误每次都会报警邮件(每天的限额是 20 封),这样可能会给您造成困扰。为了避免重复报警,请使用其他 API 记录错误,这样同一个错误将只会在错误数达到阈值(10, 100, 100...)的时候报警。 notifynotifyErrornotifyHttpErrornotifyHttpError(req, res, option)使用 notifyHttpError,可以将 HTTP 请求错误发送到 Fundebug。 req: HTTP 请求参数,参数类型为 Object,其子属性与wx.request的请求参数一致,如下: methodurldataheaderdataTyperesponseTyperes: HTTP 返回参数,参数类型为 Object,其子属性与wx.request的返回参数一致,如下: statusCodeerrMsgdataheaderoption: 可选对象,参数类型为 Object,用于发送一些额外信息,比如: metaData: 其他自定义信息示例: wx.request({ method: "POST", url: "https://example.com/create", data: { test: "test" }, success(res) { fundebug.notifyHttpError( { method: "POST", url: "https://example.com/create" }, res ); }, fail(res) { fundebug.notifyHttpError( { method: "POST", url: "https://example.com/create" }, res ); }});最后,感谢 Fundebug 用户无事忙的反馈。 ...

April 22, 2019 · 1 min · jiezi

讲case | 小程序+零售+社交=轻松涨业绩?

导购:“不好意思,这边没有L码,我们帮您到其他门店调过来,您过两天再来拿?”顾客:“这么麻烦,我不买了。” 这类对话相信做服装行业的大家都经历过。受门店库存局限性的影响,断码缺货成了赶客的行为。与此同时,受网络冲击,顾客更加适应线上消费送货上门的形式。 所以,线下服装实体店流量在不断减少,这也直接影响了门店导购的业绩。要怎么做才能缓解线下流量流失的状况?如何才能与顾客沟通从而抓住他们的心? 门店以往的做法是利用小程序打造电商平台,而此次腾讯智慧零售另辟蹊径,利用人的社交天性以及微信本身的社交环境,和绫致时装共同打造了专供门店导购使用的小程序社交电商平台“WeMall”。 它的模式主要是,门店导购在线下添加顾客微信,积累流量,然后在线上借助小程序,对顾客进行1对1或1对n的服务,针对性地为他们解决痛点。 WeMall小程序相当于是把以线下导购为中心的流量转到线上去做维护,进行场景补充。这也体现了“智慧零售+社交”的一个趋势。 智慧零售:打通线上线下腾讯集团智慧零售项目总监陈浩辅认为:“线上线下就是密不可分的,做销售就是要全渠道、多触点地覆盖到你的顾客。”小程序的出现恰好是能够打通线上线下渠道,帮助商家实现智慧零售。 像绫致时装的WeMall,拓展了零售的时间和空间,打破传统的顾客到店的销售瓶颈。它能够满足顾客获取店内商品信息等需求,让他们实时了解商家的新品活动,从而刺激消费。同时小程序线上下单的模式也能弥补线下购买的不足,解决断码缺货和顾客提货难的问题。 如果顾客再次遇到所在门店断码缺货的情况,导购可引导他们使用小程序下单,数据后台调取其他门店的货品,再快递送到家中。 社交:私人定制化营销移动社交时代要求商家结合社交玩法和自身门店的优势,去创造出与用户连接的丰富触点。 基于微信生态的小程序天然具备强关联的社交属性,门店导购的加入能够让小程序把腾讯独有社交场景发挥到极致。 在WeMall的实际操作中,导购会先在线下根据对到店顾客的观察标注标签,再使用小程序提供的工具为他们量身定制包括搭配组合、明星单品、促销活动等内容,然后分享至朋友圈、顾客群,进行专属营销。 虽然是隔着屏幕建立联系,但类似于私人定制的营销模式多了些许人情味,更能给予顾客VIP享受,也有助于巩固客源,提高复购率。 “小程序+零售+社交”模式的应用在服装行业中,提高顾客的购衣体验是一个涨业绩的有效手段。目前大多服装商家也注意到这一点,会选择搭建电子商城与门店互通,又或者引导顾客关注公众号、加微信,不定期向他们推荐资讯,以达到与顾客建立沟通、增强互动的目的。 小程序作为一个工具的出现,能够将商家的智慧零售模式和社交手段结合在一起,收集线下流量,将线下的服务线上化,实现“1+1>2”的效果。它可应用的场景也极为广泛: 顾客A皮肤比较黑:导购便在小程序内的推荐搭配板块中挑选能够显白的衣物搭配,再在微信上分享给顾客。顾客B是北方人:导购可以通过小程序向他推荐一些羽绒服打折活动。如果顾客满意还能直接下单,中间省去了沟通交流的时间。 顾客C提着大包小包逛店:导购为了不让顾客担心腾不出手提货,可以加他微信,手把手教他到小程序下单,享受送货上门的服务。 这种“小程序+智慧零售+社交” 的营销模式,无疑是能够最大化地利用微信生态的流量价值以及工作人员的能动性,填补门店的空缺,随时随地与顾客建立联系。 补充阅读《案例丨线上线下不分家,腾讯和绫致让你买衣服有新体验!》《案例丨弹指之间 业绩到手——WeMall小程序撬动绫致千万大生意》《这家时装大集团出了个小程序 导购现在接单忙个不停》 了解更多小程序开发相关内容,欢迎微信扫描下方二维码关注「微信极客WeGeek」公众号,共筑微信生态。

April 22, 2019 · 1 min · jiezi

[博客小程序]评论通知功能实现(二)——实战过程中的坑

上一篇小程序发送模板消息的几种实现主要介绍了实现评论通知功能最重要的一环,这篇文章主要介绍实现该功能的具体实战。实现流程思路其实很简单,简单画了个流程图如下: 这里有两个比较坑的地方,一个是微信本身发送模板消息的限制: 当用户在小程序内发生过提交表单行为且该表单声明为要发模板消息的,开发者需要向用户提供服务时,可允许开发者向用户在7天内推送有限条数的模板消息(1次提交表单可下发1条,多次提交下发条数独立,相互不影响)另外一个就是管理员如何初始化自己的formId的问题,而且自身的formId需求量比较大,读者评论完之后就要向管理员推送消息。 所以无奈,增加了一个后台配置的功能,定期手动触发去生成自己的FormId「自动不行,只能手动,泪奔中」 另外补充下,网上说的通过嵌套穿透的方式无限获取formId的方式已经行不通了,生成出来的formId都是一样的。 评论提交收集FormId首先我们需要收集用户的FormId,有FormId才能发送对应的模板消息,在表单标签上加上report-submit属性即可。 <form catchsubmit="formSubmit" report-submit="true">这样我们在提交评论表单的时候会获取到对应的FormId, 我们将这个FormId保存至我们的云函数中。 //评论提交按钮部分代码console.info(e.detail.formId)if (e.detail != undefined && e.detail.formId != undefined) { var data = { formId: e.detail.formId, author: 0, timestamp: new Date().getTime() } wxApi.insertFormIds(data).then(res => { console.info(res) }) } //调用云数据库function insertFormIds(data) { return db.collection('openid_formids').add({ data: data })}这样管理员在接收到评论之后回复时就可以到openid_formids的集合中找到对应的formId来进行评论回复的模板消息推送了。 管理员生成FormId为了让管理员能有更多的FormId来接收评论通知,因此我在小程序中搭建了个生成FormId的小页面。 这样偶尔登录自己的小程序,查看下自己FormId的使用情况,若没有了可以手动生成几个。 当然,这里会有一个权限问题,理论上这个页面只有管理员才可以展示,而其他人是没有权限访问的,因此需要提供个验证权限的云函数。 这里可以使用云函数的环境变量来简单做个验证,将你的管理员的openId配置在环境变量中,云函数验证下openId是否一致即可。 云函数代码如下,这样代码中不会存放敏感信息,开源的代码上传github也不会泄露。 /** * 验证 * @param {} event */async function checkAuthor(event) { if (event.userInfo.openId == process.env.author) { return true; } return false;}发送模板消息最后就是发送模板消息的实现了,方法在上一篇说的比较具体了,基于我的博客小程序,使用云调用是最方便的。 ...

April 21, 2019 · 1 min · jiezi

模版消息智能推送!我们教你发得更快更多更省

「模板消息」能力,几乎是小程序触达用户的唯一渠道。有了它,运营人员才有足够的发挥空间,来提高用户的留存,转化。微信为了防止有人用模板消息频繁骚扰用户,推出了一套严格的监督机制。一旦发现有人滥用,立刻对模板消息进行封禁处理,这将直接影响线上业务。然而受人为因素影响,模板消息的审查有很大的不确定性,运营者即使遵照微信运营规范执行也有可能被误伤封禁。以下是模版消息被封的一些常见原因。模版消息被封的常见原因:同一时间段大批量发送,被系统判定为行为异常。推送内容违规或推送内容与用户需求不符,导致用户举报。推送次数过于频繁,一天内向同一个用户推送多次模板消息,导致用户举报。简单总结,主要还是因为模板消息推给了不该推的人,被人当垃圾邮件一样处理,自然容易被封。「知晓推送」就针对以上场景做了功能优化,其新推出的智能推送服务可以助力小程序高效匹配目标用户,极大的降低模板消息被封的概率,为小程序业务的稳定运行再上一层保险。除此之外,「知晓推送」还解决了你的难题:运营灵活性差,每次推送内容变更都得通过修改代码来实现。formid 限制太大,收集麻烦,每一次业务变更都需要重新埋点。推送成本高,后端服务需要单独开发,还不能保证消息推送的稳定性与效率。「知晓推送」提前尝鲜5 月 8 日,我们将正式推出「知晓推送」服务,帮助运营者处理好粉丝转化、消息推送、数据分析等多个层面的麻烦事,真正解决复购难、留存差的问题。四大核心功能助力实现小程序用户的高效转化:1.在线发送完全可视化操作,提前预览发送效果。让模板消息推送变得和发微博一样简单。使用在线推送服务,运营人员不用在对着代码一脸懵逼了。2.自动收集 formid 组件让 formid 不足导致无法推送模板消息的状况成为过去式,两行代码即可完成接入,业务变更也无需重复埋点。3.智能推送支持根据自定义规则过滤出与小程序匹配的目标用户,同时可以设置同一批模板消息的推送次数与单次发送数量,避免骚扰用户,实现精准推送,高效转化。4.便宜限时福利大放送「知晓推送」正式上线前完全免费,服务上线当天还有额外福利。5.8 日前注册的用户都可获赠价值不少于 198 元的资源包(详询,微信:minsupport3)哦!抓紧时间注册吧~

April 19, 2019 · 1 min · jiezi

安卓手机微信7.0.4调试小程序抓包https请求失败的问题和解决

注意:阅读本文需要一台已经root的安卓手机!说明系统:MacOS 10.13.6手机:小米6(已root)抓包工具:Charles微信版本:7.0.4现象安卓手机无法通过Charles代理抓包https请求,我前天(2019年04月16日)用的7.0.3不知道为什么能抓到,昨天手残更新到7.0.4就不行了。而iOS(iPhone5S 12.1.4)没有问题。查找相关资料,都说微信升级到版本7之后就限制了用户证书凭据。根据网上较多的推荐方案,建议把证书放在系统证书存放目录下,那这就需要Root手机了,如果没有,以下内容不适合阅读。接下来,我尝试将Charles生成的证书放在手机的系统证书中,并没有那么顺利,很失败!我慢慢来讲解一下。步骤生成Charles证书我们要生成一个可以存放在系统证书目录下的可被识别的证书。手机代理设置好了后,手机访问:<chls.pro/ssl>下载下来证书,名称是这样的charles-proxy-ssl-proxying-certificate.pem(你把这个文件搞到电脑上,假设该证书存在电脑的路径:~/charles-proxy-ssl-proxying-certificate.pem)。在你的电脑终端通过这个命令生成一个hash值:openssl x509 -subject_hash_old -in ~/charles-proxy-ssl-proxying-certificate.pem可以看到输出了类似如下P750TM:webs whidy$ openssl x509 -subject_hash_old -in ~/certificate.pem 07e87b3d—–BEGIN CERTIFICATE—–MIIFYjCCBEqgAwIBAgIGAWeQpfWHMA…….77JclxPc0UdJHi5rOf7w+LU8YZFPdMTLa/c2JjMlspt08UeQVDE=—–END CERTIFICATE—–将证书更名07e87b3d.0注意后缀!接下来你可以用任意手段将该文件拷贝至手机的/system/etc/security/cacerts/目录,如果成功则再次尝试抓包,如果失败,请继续看。超级终端操作如果不嫌麻烦的话,你完全可以在安卓手机上面的超级终端(自行下载的工具)进行以下操作,但是我没有这样,我在MacOSX中启用adb连接操作手机,如果你正有此意,请按照我的方式操作。电脑终端执行以下命令(这里不介绍brew,不理解的自行学习)brew cask install android-platform-tools装好后,数据线连上手机,测试一下adb devices没报错,且大概出现以下信息则正常:List of devices attached* daemon not running; starting now at tcp:5037* daemon started successfullyfa8a05fd device然后获取root权限,尝试将文件07e87b3d.0拷贝到/system/etc/security/cacerts/adb root获得权限后,直接执行下面命令将证书放入系统目录。push ~/07e87b3d.0 /system/etc/security/cacerts/如果成功了,请尝试抓包。如果提示失败,比如权限不足,只读啥的,反正大概错误信息如下:P750TM:/ whidy$ adb push ~/07e87b3d.0 /system/etc/security/cacerts/adb: error: failed to copy ‘/Users/whidy/07e87b3d.0’ to ‘/system/etc/security/cacerts/07e87b3d.0’: remote couldn’t create file: Read-only file system/Users/whidy/07e87b3d.0: 0 files pushed. 0.0 MB/s (1947 bytes in 0.119s)那就要继续折腾了。网上抄到的chmod 777目前是不管用的。要通过mount的相关操作来解决这个问题。装载可写的system目录查看当前system目录挂载在哪里mount,可以得到大致如下:rootfs on / type rootfs (ro,seclabel,size=2828452k,nr_inodes=707113)tmpfs on /dev type tmpfs (rw,seclabel,nosuid,relatime,size=2912600k,nr_inodes=728150,mode=755)devpts on /dev/pts type devpts (rw,seclabel,relatime,mode=600)proc on /proc type proc (rw,relatime,gid=3009,hidepid=2)sysfs on /sys type sysfs (rw,seclabel,relatime)selinuxfs on /sys/fs/selinux type selinuxfs (rw,relatime)/dev/block/dm-0 on /system type ext4 (ro,seclabel,relatime,discard,data=ordered)debugfs on /sys/kernel/debug type debugfs (rw,seclabel,relatime)none on /acct type cgroup (rw,relatime,cpuacct)none on /dev/stune type cgroup (rw,relatime,schedtune)tmpfs on /mnt type tmpfs (rw,seclabel,relatime,size=2912600k,nr_inodes=728150,mode=755,gid=1000)none on /config type configfs (rw,relatime)none on /dev/memcg type cgroup (rw,relatime,memory)注意到/dev/block/dm-0 on /system type ext4 (ro,seclabel,relatime,discard,data=ordered)这一行,后面括号有个ro,代表readonly!接下来尝试修改为可写(rw)状态:mount -o rw,remount /dev/block/dm-0 /system如果成功了,就试试将文件拷贝进去,失败了,例如提示:’/dev/block/dm-0’ is read-only,请继续阅读。这里参考Android O, failed to mount /system, /dev/block/dm-0 is read only,一顿操作!我这边是这样的:adb disable-verityadb reboot关闭验证是要重启设备的。执行重启后,继续:adb rootadb remountadb shell再执行mount发现结果跟刚才不一样了,找到有system的那一行发现这样的/dev/block/sde43 on /system type ext4 (rw,seclabel,relatime,discard,data=ordered)已经可写了,我试试拷贝进去。执行adb push /07e87b3d.0 /system/etc/security/cacerts/,出现以下结果:P750TM:/ whidy$ adb push /07e87b3d.0 /system/etc/security/cacerts//Users/whidy/07e87b3d.0: 1 file pushed. 0.1 MB/s (1947 bytes in 0.022s)应该就完成了。再去我的小米6手机里面的设置 > 更多设置 > 系统安全 > 加密与凭据 > 信任的凭据 > 系统里面看看,滚到最低部,ok,证书导入成功了。再去抓包看看我这文章是边写边记录的,现在可以看到https请求的抓包已经Ok啦最后我建议最后还原之前操作的disable-verity,这样操作一下:adb rootadb enable-verityadb reboot行了差不多就这些了。 ...

April 18, 2019 · 1 min · jiezi

mpvue性能优化实战技巧

最近一直在折腾mpvue写的微信小程序的性能优化,分享下实战的过程。先上个优化前后的图:可以看到打包后的代码量从813KB减少到387KB,Audits体验评分从B到A,效果还是比较明显的。其实这个指标说明不了什么,而且轻易就可以做到,更重要的是优化小程序运行过程中的卡顿感,请耐心往下看。常规优化常规的Web端优化方法在小程序中也是适用的,而且不可忽视。一、压缩图片这一步最简单,但是容易被忽视。在tiny上在线压缩,然后下载替换即可。我这项目的压缩率高达72%,可以说打包后的代码从813KB降到387KB大部分都是归功于压缩图片了。二、移除无用的库我之前在项目中使用了Vant Weapp,在static目录下引入了整个库,但实际上我只使用了button,field,dialog等几个组件,实在是没必要。所以干脆移除掉了,微信小程序自身提供的button,wx.showModal等一些组件基本可以满足需求,自己手写一下样式也不用花什么时间。在这里建议大家,在微信小程序中,尽量避免使用过多的依赖库。不要贪图方便而引入一些比较大的库,小程序不同于Web,限制比较多,能自己写一下就尽量自己写一下吧。小程序的优化咱们首先得看一下官方优化建议,大多是围绕这个建议去做。一、开启Vue.config._mpTrace = true这个是mpvue性能优化的一个黑科技啊,可能大多数同学都不知道这个,我在官方文档都没有搜到到这个配置,我真的是服了。我能找到这个配置也是Google机缘巧合下看到的,出处:mpvue重要更新,页面更新机制进行全面升级具体做法是在/src/main.js添加Vue.config._mpTrace = true,如:Vue.config._mpTrace = trueVue.config.productionTip = falseApp.mpType = ‘app’添加了Vue.config._mpTrace属性,这样就可以看到console里会打印每500ms更新的数据量。如图:如果数据更新量很大,会明显感觉小程序运行卡顿,反之就流畅。因此我们可以根据这个指标,逐步找出性能瓶颈并解决掉。二、精简data1. 过滤api返回的冗余数据后端的api可能是需要同时为iOS,Android,H5等提供服务的,往往会有些冗余的数据小程序是用不到的。比如api返回的一个文章列表数据有很多字段:this.articleList = [ { articleId: 1, desc: ‘xxxxxx’, author: ‘fengxianqi’, time: ‘xxx’, comments: [ { userId: 2, conent: ‘xxx’ } ] }, { articleId: 2 // … }, // …]假设我们在小程序中只需要用到列表中的部分字段,如果不对数据做处理,将整个articleList都setData进去,是不明智的。小程序官方文档: 单次设置的数据不能超过1024kB,请尽量避免一次设置过多的数据。可以看出,内存是很宝贵的,当articleList数据量非常大超过1M时,某些机型就会爆掉(我在iOS中遇到过很多次)。因此,需要将接口返回的数据剔除掉不需要的,再setData,回到我们上面的articleList例子,假设我们只需要用articleId和author这两个字段,可以这样:import { getArticleList } from ‘@/api/article’export default { data () { return { articleList: [] } } methods: { getList () { getArticleList().then(res => { let rawList = res.list this.articleList = this.simplifyArticleList(rawList) }) }, simplifyArticleList (list) { return list.map(item => { return { articleId: item.articleId, author: item.author // 需要哪些字段就加上哪些字段 } }) } }}这里我们将返回的数据通过simplifyArticleList 来精简数据,此时过滤后的articleList中的数据类似:[ {articleId: 1, author: ‘fengxianqi’}, {articleId: 2, author: ‘others’} // …]当然,如果你的需求中是所有数据都要用到(或者大部分数据),就没必要做一层精简了,收益不大。毕竟精简数据的函数中具体的字段,是会增加维护成本的。PS: 在我个人的实际操作中,做数据过滤虽然增加了维护的成本,但一般收益都很大,因次这个方法比较推荐。2. data()中只放需要的数据import xx from ‘xx.js’export default { data () { return { xx, otherXX: ‘2’ } }}有些同学可能会习惯将import的东西都先放进data中,再在methods中使用,在小程序中可能是个不好的习惯。因为通过Vue.config._mpTrace = true在更新某个数据时,我对比放进data和不放进data中的两种情况会有差别。所以我猜测可能是data是会一起更新的,比如只是想更新otherXX时,会同时将xx也一起合起来setData了。3. 静态图片放进static这个问题和上面的问题其实是一样的,有时候我们会通过import的方式引入,比如这样:<template> <img :src=“UserIcon”></template><script>import UserIcon from ‘@/assets/images/user_icon.png’export default { data () { return { UserIcon } }}</script>这样会导致打包后的代码,图片是base64形式(很长的一段字符串)存放在data中,不利于精简data。同时当该组件多个地方使用时,每个组件实例都会携带这一段很长的base64代码,进一步导致数据的冗余。因此,建议将静态图片放到static目录下,这样引用:<template> <img src="/static/images/user_icon.png"></template>代码也更简洁清爽。看一下做了上面操作的前后对比图,使用体验上也流畅了很多。三、swiper优化小程序自身提供的swiper组件性能上不是很好,使用时要注意。参考着两个思路:【优化】解决swiper渲染很多图片时的卡顿想请教一下小程序swiper组件的问题在我使用时,由于需求原因,动态删掉swiper-item的思路不可行(手滑时会造成抖动)。因此只能作罢。但仍然可以优化一下:将未显示的swiper-item中的图片用v-if隐藏到,当判断到current时才显示,防止大量图片的渲染导致的性能问题。四、vuex使用注意事项我之前写过的一篇mpvue开发音频类小程序踩坑和建议里面有讲如何在小程序中使用vuex。但遇到了个比较严重的性能问题。1. 问题描述我开发的是一个音频类的小程序,所以需要将播放列表playList,当前索引currentIndex和当前时长currentTime放进state.js中:const state = { currentIndex: 0, // playList当前索引 currentTime: 0, // 当前播放的进度 playList: [], // {title: ‘’, url: ‘’, singer: ‘’}}每次用户点击播放音频时,都会先加载音频的播放列表playList,然后播放时更新当前时长currentTime,发现有时候播音频时整个小程序非常卡顿。注意到,音频需每秒就得更新一次currentTime,即每秒就做一次setData操作,稍微有些卡顿是可以理解的。但我发现是播放列表数据比较多时会特别卡,比如playList的长度是100条以上时。2. 问题原因我开启Vue.config._mpTrace = true后发现一个规律:当palyList数据量小时,console显示造成的数据量更新数值比较小;当playList比较大时,console显示造成的数据量更新数值比较大。PS: 我曾尝试将playList数据量增加到200条,每500ms的数据量更新达到800KB左右。到这里基本可以确定一个事实就是:更新state中的任何一个字段,将导致整个state全量一起setData。在我这里的例子,虽然我每次只是更新currentTime这个字段的值,但依然导致将state中的其他字段如playList,currentIndex都一起做了一次setData操作。3. 解决问题有两个思路:精简state中保存的数据,即限制playList的数据不能太多,可将一些数据暂存在storage中vuex采用Module的写法能改善这个问题,虽然使用时命名空间造成一定的麻烦。vuex传送门一般情况下,推荐使用后者。我在项目中尝试使用了前者,同样能达到很好的效果,请继续看下面的分享。五、善用storage1.为什么说要善用storage由于小程序的内存非常宝贵,占用内存过大会非常卡顿,因此最好尽可能少的将数据放到内存中,即vuex存的数据要尽可能少。而小程序的storage支持单个 key允许存储的最大数据长度为 1MB,所有数据存储上限为 10MB。所以可以将一些相对取用不频繁的数据放进storage中,需要时再将这些数据放进内存,从而缓解内存的紧张,有点类似Windows中虚拟内存的概念。2.storage换内存的实例这个例子讲的会有点啰嗦,真正能用到的朋友可以详细看下。上面讲到playList数据量太多,播放一条音频时其实只需要最多保证3条数据在内存中即可,即上一首,播放中的,下一首,我们可以将多余的播放列表存放在storage中。PS: 为了保证更平滑地连续切换下一首,我们可以稍微保存多几条,比如我这里选择保存5条数据在vuex中,播放时始终保证当前播放的音频前后都有两条数据。// 首次播放背景音频的方法async function playAudio (audioId) { // 拿到播放列表,此时的playList最多只有5条数据。getPlayList方法看下面 const playList = await getPlayList(audioId) // 当前音频在vuex中的currentIndex const currentIndex = playList.findIndex(item => item.audioId === audioId) // 播放背景音频 this.audio = wx.getBackgroundAudioManager() this.audio.title = playList[currentIndex].title this.audio.src = playList[currentIndex].url // 通过mapActions将播放列表和currentIndex更新到vuex中 this.updateCurrentIndex(index) this.updatePlayList(playList) // updateCurrentIndex和updatePlayList是vuex写好的方法}// 播放音频时获取播放列表的方法,将所有数据存在storage,然后返回当前音频的前后2条数据,保证最多5条数据import { loadPlayList } from ‘@/api/audio’async function getPlayList (courseId, currentAudioId) { // 从api中请求得到播放列表 // loadPlayList是api的方法, courseId是获取列表的参数,表示当前课程下的播放列表 let rawList = await loadPlayList(courseId) // simplifyPlayList过滤掉一些字段 const list = this.simplifyPlayList(rawList) // 将列表存到storage中 wx.setStorage({ key: ‘playList’, data: list }) return subPlayList(list, currentAudioId)}重点是subPlayList方法,这个方法保证了拿到的播放列表是最多5条数据。function subPlayList(playList, currentAudioId) { let tempArr = […playList] const count = 5 // 保持vuex中最多5条数据 const middle = parseInt(count / 2) // 中点的索引 const len = tempArr.length // 如果整个原始的播放列表本来就少于5条数据,说明不需要裁剪,直接返回 if (len <= count) { return tempArr } // 找到当前要播放的音频的所在位置 const index = tempArr.findIndex(item => item.audioId === currentAudioId) // 截取当前音频的前后两条数据 tempArr = tempArr.splice(Math.max(0, Math.min(len - count, index - middle)), count) return tempArr}tempArr.splice(Math.max(0, index - middle), count)可能有些同学比较难理解,需要仔细琢磨一下。假设playList有10条数据:当前音频是列表中的第1条(索引是0),截取前5个:playList.splice(0, 5),此时currentAudio在这5个数据的索引是0,没有上一首,有4个下一首当前音频是列表中的第2条(索引是1),截取前5个:playList.splice(0, 5),此时currentAudio在这5个数据的索引是1,有1个上一首,3个下一首当前音频是列表中的第3条(索引是2),截取前5个:playList.splice(0, 5),此时currentAudio在这5个数据的索引是2,有2个上一首,2个下一首当前音频是列表中的第4条(索引是3),截取第1到6个:playList.splice(1, 5),此时currentAudio在这5个数据的索引是2,有2个上一首,2个下一首当前音频是列表中的第5条(索引是4),截取第2到7个:playList.splice(2, 5),此时currentAudio在这5个数据的索引是2,有2个上一首,2个下一首…当前音频是列表中的第9条(索引是8),截取后5个:playList.splice(4, 5),此时currentAudio在这5个数据的索引是3,有3个上一首,1个下一首当前音频是列表中的最后1条(索引是9),截取后的5个:playList.splice(4, 5),此时currentAudio在这5个数据的索引是4,有4个上一首,没有下一首有点啰嗦,感兴趣的同学仔细琢磨下,无论当前音频在哪,都始终保证了拿到当前音频前后的最多5条数据。接下来就是维护播放上一首或下一首时保证当前vuex中的playList始终是包含当前音频的前后2条。播放下一首function playNextAudio() { const nextIndex = this.currentIndex + 1 if (nextIndex < this.playList.length) { // 没有超出数组长度,说明在vuex的列表中,可以直接播放 this.audio = wx.getBackgroundAudioManager() this.audio.src = this.playList[nextIndex].url this.audio.title = this.playList[nextIndex].title this.updateCurrentIndex(nextIndex) // 当判断到已经到vuex的playList的边界了,重新从storage中拿数据补充到playList if (nextIndex === this.playList.length - 1 || nextIndex === 0) { // 拿到只有当前音频前后最多5条数据的列表 const newList = getPlayList(this.playList[nextIndex].courseId, this.playList[nextIndex].audioId) // 当前音频在这5条数据中的索引 const index = newList.findIndex(item => item.audioId === this.playList[nextIndex].audioId) // 更新到vuex this.updateCurrentIndex(index) this.updatePlayList(newList) } }}这里的getPlayList方法是上面讲过的,本来是从api中直接获取的,为了避免每次都从api直接获取,所以需要改一下,先读storage,若无则从api获取:import { loadPlayList } from ‘@/api/audio’async function getPlayList (courseId, currentAudioId) { // 先从缓存列表中拿 const playList = wx.getStorageSync(‘playList’) if (playList && playList.length > 0 && courseId === playList[0].courseId) { // 命中缓存,则从直接返回 return subPlayList(playList, currentAudioId) } else { // 没有命中缓存,则从api中获取 const list = await loadPlayList(courseId) wx.setStorage({ key: ‘playList’, data: list }) return subPlayList(list, currentAudioId) }}播放上一首也是同理,就不赘述了。PS: 将vuex中的数据精简后,我所做的小程序在播放音频时刷其他页面已经非常流畅啦,效果非常好。六、动画优化这个问题在mpvue开发音频类小程序踩坑和建议已经讲过了,感兴趣的可以移步看一眼,这里只写下概述:如果要使用动画,尽量用css动画代替wx.createAnimation使用css动画时建议开启硬件加速最后大致总结一下上面所讲的几个要点:开发时打开Vue.config._mpTrace = true。谨慎引入第三方库,权衡收益。添加数据到data中时要克制,能精简尽量精简。图片记得要压缩,图片在显示时才渲染。vuex保持数据精简,必要时可先存storage。性能优化是一个永不止步的话题,我也还在摸索,不足之处还请大家指点和分享。欢迎关注,会持续分享前端实战中遇到的一些问题和解决办法。 ...

April 17, 2019 · 3 min · jiezi

C4J私有化的小程序数据统计分析

线上流量红利逐渐消失的今天,产品的获客成本从几元,飙升到了现在的几百元,甚至上千元,流量大战悄然打响!而 “微信社会”中的小程序,凭借着离消费者一指之遥的距离,成为商家不被淘汰的制胜法宝 。2019年4月,开源的用户行为分析厂商Cobub推出全渠道的用户增长利器—C4J,即Cobub for Java,全新一代低成本、私有化、全渠道、高性能的用户行分析平台。新增对小程序模块的统计分析,实现了产品多渠道数据的打通,形成跨渠道用户全生命周期的行为数据流, 从而提升用户体验,驱动用户及业务增长。C4J四大优势低成本极简的架构,提供License低成本轻松部署,提高效率,节省研发人力,初创团队也能低成本实现数据私有。私有化私有化解决方案有效的防止了用户数据的泄露,为业务提供强有力的数据支撑,深度分析更容易,数据应用灵活更安全,定制化贴近业务。全渠道支持APP(iOS/Android)、小程序、H5、网站、服务器端调用(API)等多渠道数据采集,贯穿用户的全生命周期。高性能基于Cobub开源版、商业版、大数据版产品的多年技术积累, C4J在提高性能的前提下简化了架构,独特的数据存储和计算方案,充分利用服务器资源,轻松支持百万日活,满足产品从初创到发展期的无缝衔接!模块的即插即用部署简单方便,Bug随时修复按需安装应用模块,降低使用成本通用工具可定制,实施简单可控系统架构简单,维护成本低廉三大应用价值鉴别有效渠道,降低运营成本C4J可以通过对不同渠道新增用户数、活跃用户数、用户使用时长等相关指标进行统计及质量分析,可以更好地评估渠道效果,鉴别出哪些是用户新增最有效的渠道,哪些是用户转化率最高的渠道以及哪些是用户成本最低渠道!助力企业改善运营策略,降低运营成本。归因产品迭代,提升用户体验产品迭代的目的是提升用户的体验,每次产品迭代后都是需要新的用户体验大于旧的用户体验和产品成本,这就需要产品经理通过已产生的数据了解用户关注点,洞察用户需求,使产品迭代后的用户体验要超过用户的预期,减少用户跳出和用户流失,提升用户粘性和满意度,只有这样你的产品迭代优化才是有意义的。洞察用户需求,实现精准营销通过C4J对用户点击和浏览等行为数据进行采集分析,建立数据模型,从不同维度给用户打标签,进行分群画像,能够让企业对每类用户进行有针对性的精细化运营活动,真正做到千人千面的个性化服务。从而减少了运营人员不必要的行为成本,提升运营的效率和效果,增加用户的留存率及转化率。C4J,全渠道的用户增长利器,用低成本、私有化、全渠道、高性能的全新产品助力您的用户及业务增长。C4J全渠道的用户增长利器C4J即Cobub for Java是一款低成本、私有化、全渠道、高性能的用户行为分析工具,您可以将它私有化部署在您的应用上,收集并展现来自您的iOS、Android、小程序等的相关用户行为,数据私有灵活更安全。它可以帮助企业降低运营成本,提高用户体验,精细化运营助力业务增长。查看demo:https://c4j.cn/demo/?r=3g1h1g免费试用:https://c4j.cn/ucenter/#/appl…

April 16, 2019 · 1 min · jiezi

[博客小程序]评论通知功能实现(一)——小程序发送模板消息的几种实现

这两天抽空把评论通知的功能给基本实现了,主要解决读者评论后,我无法及时看到并回复的痛点。这篇主要说说模板消息发送的坑。使用前准备准备的话就是先读下文档,了解下模板消息怎么发送和怎么接入的,然后到你的后台去选择你想要的消息模板,记录好对应的模板ID即可。最初看文档的时候感觉挺简单的,无非先调用个接口获取ACCESS_TOKEN, 然后调用发送模板消息的接口就完事了,当然事实也确实如此,但其中还是有些小坑的。后端实现后端实现对于我来说最轻松,毕竟是搞后端开发的嘛,我用.net core的方式实现了一把,轻松搞定,贴下代码,至于java或者php,其实差不多。/// <summary>/// 获取新的 AccessToken/// </summary>/// <returns></returns>public static async Task<string> GetAccessToken(){ var url = $"{WechatApiHost}/cgi-bin/token"; var response = await HttpRequestHelper.GetAsync<dynamic>(url, new { grant_type = “client_credential”, appid = WechatAppId, secret = WechatSecret }, null, GlobalRequestConfig); return response.IsSucceed && response.Data != null ? response.Data.access_token : null;}/// <summary>/// 发送模板消息/// </summary>/// <returns>The template message.</returns>/// <param name=“openId”>Open identifier.</param>public static async Task<ResponseResult> sendTemplateMessage(String openId){ //先从redis获取token var accessToken = await RedisInstance.Get<string>(MiniAccessTokenRedisKey); if(string.IsNullOrWhiteSpace(accessToken)) { accessToken =await GetNewAccessToken(); if (string.IsNullOrWhiteSpace(accessToken)) return new ResponseResult { Result = false, ErrorMessage = “token获取失败”, Code = ResponseCode.InvalidParameters }; //保存到redis,默认1小时 await RedisInstance.Set<string>(MiniAccessTokenRedisKey, accessToken, 1 * 60 * 60); } var url = $"{WechatApiHost}/cgi-bin/message/wxopen/template/send?access_token={accessToken}"; var tempData = new { touser = openId, template_id = MiniMessageTemplate,//申请的模板消息id, page = “/pages/detail/detail?blog=1”, form_id = FormId, data = new { keyword1 = new { value = “元素1” }, keyword2 = new { value = “元素2” }, keyword3 = new { value = “元素3” } }, //emphasis_keyword= “keyword1.DATA” }; var response = await HttpRequestHelper.PostAsync<dynamic>(url, tempData, null, GlobalRequestConfig); var sendResult = “”; if (!response.IsSucceed) return new ResponseResult { Result = false, ErrorMessage = response.ErrorMessage, Code = ResponseCode.UnknownException }; return new ResponseResult { Result = true, ErrorMessage = “”, Code = ResponseCode.Success };}js实现js的实现方式和后端代码实现也差不多,也是调用两个接口,逻辑一致,这里主要介绍util函数,避免重复造轮子。#github地址https://github.com/lcxfs1991/wx-js-utils对应的微信开放平台接口都基本已经封装好了,文档也比较详细,有兴趣的可以自己体验下。云调用实现这才是我想要的,本身我的博客小程序部分功能是基于云开发的,同时云调用实现的方式省去了获取ACCESS_TOKEN的步骤,使用起来比较方便。具体实现文档还是比较详细的,在使用前一定要在你的云函数目录下添加config.json文件,声明好所需调用的接口,并上传到云端。#声明使用发送模板消息接口{ “permissions”: { “openapi”: [“templateMessage.send”] }}这样就可以正常使用啦,贴下我的发送模板消息的代码: const sendResult = await cloud.openapi.templateMessage.send({ touser: touser, templateId: template, formId: form_id, page: ‘pages/detail/detail?blogId=’ + event.blogId, data: { keyword1: { value: event.nickName // keyword1 的值 }, keyword2: { value: event.message // keyword2 的值 } }, })本以为一切顺利,但终究好事多磨,上传到云端之后一直提示:function has no permission to call this API首先怀疑我的config.json没有上传上去,通过云开发后台去下载对应的函数,发现已经上传,同时也确定配置没有问题。再次仔细看文档,看到这样一句话:版本要求:wx-server-sdk >= 0.4.0、开发者工具 >= 1.02.1903251 (目前需开发版或测试版)于是尝试下载了开发版,重新上传了云函数,问题解决了「泪奔中」所以有使用云调用实现的小伙伴一定要注意自己的开发中工具。其他使用ACCESS_TOKEN的时候一定要注意,建议使用统一的服务来获取和刷新 access_token,其他业务逻辑所使用的 access_token 均来自于该服务,不应该各自去刷新,否则容易造成冲突,导致 access_token 覆盖而影响业务。另外开发版工具支持本地调试云函数了,同时云开发的管理界面也有很大改动,有兴趣的可以尝试下载看看。最后,下一篇文章讲讲我的博客小程序中评论通知功能的具体实现。Ps.小程序名称:程序员的博客 ...

April 14, 2019 · 2 min · jiezi

小程序文字溢出显示省略号

单行文本溢出显示省略号.title{ text-overflow: ellipsis; white-space: nowrap; overflow: hidden;}多行文本溢出显示省略号.description{ font-size: 30rpx; display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical; color : #cccccc; text-overflow: ellipsis; overflow: hidden;}

April 14, 2019 · 1 min · jiezi

不止微信、支付宝!一文带你了解所有小程序平台

小程序的平台越来越多了,开发者的精力也越来越分散。事实上,这些平台有怎样的特色?他们有怎样的代表作品?他们有几个入口?开发成本高吗?他们有给开发者怎样的扶持政策?一文为你解析小程序六大平台。01 微信关于微信小程序2017 年 1 月 9 日,微信小程序正式上线。经过三年的发展,它俨然成为了开发者最关注的小程序开发平台。在 2018 年 8 月,马化腾就透露已有 150 万开发者加入了小程序的开发队伍,小程序应用数量超过 100 万,覆盖 200 多个细分行业,日活用户达到 2 亿。而在 2018 的全年财报也表明,微信小程序日活跃账户数增长迅速,用户人均日访问量同比增长 54%,而中长尾小程序也占到了小程序日均总访问量的 43%。在小游戏中,微信已有单月流水过亿的杰出小游戏作品。10 款内购道具月流水过千万小游戏变为了 10 款,11 款广告月流水过千万小游戏。头部小游戏的成功已经无需证明,但从整个行业来看,三十天留存率 43% 亦足够优秀。微信里的社交关系让小程序拥有了更多的吸引力,小程序则让微信的「操作系统梦」成为现实。在微信中,小程序拥有着超越公众号之外的连接和服务能力,也能将公众号、群聊、对话、朋友圈串联起来,为用户提供更延展也更丰富的服务。代表作品小程序:拼多多、跳一跳、享物说、小打卡、轻芒、小年糕、乘车码、粤省事等小游戏:跳一跳、物理弹球正版、头脑王者、欢乐斗地主、星途 WeGoing、羽毛球高高手等主要入口微信聊天下拉的小程序界面是小程序最重要的入口之一。聊天的小程序卡片、公众号推文中的、分享小程序、四散的小程序都是小程序的重要入口。据不完全统计,微信小程序已有 60 余个入口。开发成本小程序的主要开发语言是 JavaScript ,小程序的开发同普通的网页开发相比有很大的相似性。对于前端开发者而言,从网页开发迁移到小程序的开发成本并不高,但是二者还是有些许区别的,毕竟小程序还处于一个封闭的程序运行环境。开发文档:https://developers.weixin.qq….扶持政策在小程序和小游戏上,微信都推出了不同的扶持计划。????小程序腾讯云在微信公开课上宣布推出的「小程序 · 云开发」资源扶持计划价值 10 亿。该计划分为长期普惠、进阶扶持和高阶扶持三种机制。腾讯云提供的基础版套餐、专业版资源、旗舰版资源都是扶持奖励。????小游戏创意小游戏鼓励计划:创意标识、初始用户、分成激励、创意保护。种子用户计划:针对新游,微信将无差别分配等额的种子用户。在第一批无差别等额用户发布后,微信会持续观察所有小游戏的数据,根据平台的数据模型,给新游戏第二批的种子用户。在这两个计划之外,微信提供的应收转投放和应收预提将帮助开发者快周转。同时对普通开发者的抽成比例进一步降低。月流水 50 万以下的小游戏免抽成。月流水在 50 万以上的部分,游戏内购抽成 40%;日流水在 100 万以下的部分,广告抽成 50%。02 支付宝关于支付宝小程序2018 年 9 月 12 日,支付宝小程序正式上线,主要活跃在商业和生活生活领域,暂不支持小游戏(严格来说目前仅支持支付宝官方开发游戏类小程序,如「叠叠乐」)。据悉,截至 2019 年 1 月,支付宝小程序的数量已增至 13 万,日活跃用户数突破 2.3 亿,平均 7 日留存率为 43.26%。目前,支付宝小程序对企业账号及个人账号(已开启个人开发者限量公测)开放。支付宝的实名认证并与「钱」挂钩让用户和商家都更具信任感;而有独特优势的信用体系则让支付宝在与押金、租赁相关的场景大放异彩,比如共享单车、共享充电宝等支付宝小程序,在接入芝麻信用后为用户提供了免押金等便捷服务。代表作品免押金类:来电、内啥、人人租机、哈啰出行等其他:好食期、青团社兼职、航旅纵横、淘票票电影等主要入口主要为支付宝 app 首页顶部搜索栏,以及首页下拉呼出「小程序收藏」。更多支付宝小程序入口,可以查看 ???? 《细数支付宝小程序的 35 个入口,我们终于找全了》。开发成本与微信小程序的整体架构基本一致。如果你想将微信小程序迁移至支付宝,只需重命名小程序文件后缀、一些事件函数和部分 API 即可。开发文档:https://docs.alipay.com/mini/…扶持政策3 月 21 日,在 2019 阿里云峰会 · 北京上,阿里巴巴旗下的阿里云、支付宝、淘宝、钉钉、高德等联合发布「阿里巴巴小程序繁星计划」:提供 20 亿元补贴,扶持 200W+ 小程序开发者、100W+ 商家。凡入选「超星」的小程序,入驻支付宝、淘宝、钉钉、高德后还能得到流量重点支持。03 百度关于百度智能小程序2018 年 7 月 4 日,百度智能小程序正式上线,主要运行在百度 app 上,主打「体验、流量、智能、开放」四大特点。据了解,12 月时百度 app 已为小程序开放了 40 多个流量入口,并为小程序开发者提供了超过 60 个 AI 接口和超过 20 个 NA 化组件。百度智能小程序支持小游戏开发,不过目前支持的主体主要为媒体、企业、政府及其他组织,个人主体类型开发者暂时无法入驻。代表作品AI 相关:爱说唱、长隆 AR 动物园、AI 分诊助手等其他:小红书、爱奇艺视频、几何大逃亡、贴吧等主要入口可以从百度 app 的搜索栏联想、搜索结果、底部菜单「我的」中进入百度智能小程序。更多百度智能小程序入口,可以查看 ????《百度的搜索流量终于全面开放!新入口就在王牌产品主场景》。开发成本与微信小程序的整体架构基本一致。如果你想将微信小程序迁移至百度,只需使用百度的「搬家工具」转换已有的微信小程序即可。开发文档:https://smartprogram.baidu.co…扶持政策在 2018 年的百度世界大会上,百度宣布了智能小程序「开发者共筑计划」——「千百十一」,分别对应着百度将为智能小程序开放全域千亿用户流量、提供百亿的广告分成、成立一个提供投资与推广的创新基金以及像公开课一样的一对一专人服务。04 淘宝关于「轻店铺」2018 年 9 月,手机淘宝上的小程序「轻店铺」开始内测。淘宝「轻店铺」是一个支持个人或者企业进行开店的工具,具有群聊、发文章、门店导航等功能。据了解,「轻店铺」将把淘宝品牌主的直播、微淘内容以及门店信息进行汇集,最后形成了一个信息块,当用户在线上搜索该品牌时会打包弹出。代表作品严格来说,目前手淘上只有「星巴克中国」是真正的「轻店铺」,底层与支付宝小程序相通。其他的淘宝店铺虽然同样有小程序标志性「胶囊键」,但并不是小程序,且胶囊键与「轻店铺」按键不同。主要入口在淘宝搜索「星巴克中国」,即可从顶部的横幅进入。开发成本因仍处于内测阶段,开发者可将姓名、联系方式、公司名称、职务发送邮件至 taolite@service.taobao.com 申请成为内测用户。未获取内测资格的用户将无法进行入驻。05 字节跳动关于字节跳动小程序2018 年 11 月 8 日,字节跳动小程序正式上线,小程序旨在利用优质内容所关联和产生的使用场景进行小程序导流,解决开发者流量与转化困扰。开发一套小程序就可以服务多个产品是头条小程序的优势所在。在字节跳动开发者平台开发的小程序有机会出现在抖音、西瓜视频等不同平台。目前字节跳动被人所熟知的小程序,多为其他平台的已有内容。但在游戏、电商、娱乐等领域,字节跳动反倒有了更多拿得出手的作品。不过由于平台尚在发展阶段,很多内容构架都尚未完善。代表作品小游戏:光与森、行星毁灭、音悦球球、一笔画完等主要入口今日头条文章详情页、微头条、小视频、搜索等入口均为今日头条小程序入口,新版今日头条「常用」底部导航栏还在内测一个类似小程序桌面的新界面。而在其他平台,抖音短视频左下角也有对应的小程序入口。开发成本字节跳动小程序暂不支持一键转换工具。暂不支持 wepy,mpvue 等框架,需开发者主动把利用 wepy 框架开发的代码,编译为小程序的语法,才能在头条上正常的渲染。开发文档:https://microapp.bytedance.com/扶持政策目前字节跳动公布的扶持政策仅面向小游戏。针对普通游戏,开发者可以拿到广告日流水不超过 100 万部分的 60%,超过 100 万的部分开发者可保留 50%。而在字节跳动首发的游戏将获得更多资源倾斜,开发者可以拿到广告日流水不超过 100 万部分的 70%,而超过 100 万的部分开发者可保留 60%。06 快应用关于快应用vivo、华为、OPPO、小米、联想、金立、魅族、中兴、努比亚、一加、海信、中国移动终端想要一起做一个基于手机硬件平台的新型应用形态。十二家手机厂商和服务商组成的快应用联盟来势汹汹。覆盖 10 亿设备、月活 2 亿、打开快应用 20 亿次、留存 1 亿个桌面图标,35% 的流量来自桌面留存图标。快应用与其他小程序平台应用同质化严重,联盟 12 个合作伙伴对开发者的资源分配亦有较大不同。代表作品工具类:菜鸟裹裹、西窗烛、吐司工具箱等主要入口快应用有四类入口:应用分发、智能场景、二次入口、开发者自身入口开发成本快应用使用前端技术栈开发,原生渲染,同时具备 HTML 5 页面和原生应用的双重优点。快应用使用 MVVM 的设计模式进行开发,开发者也无需直接操作 DOM 节点的增删,利用数据驱动的方式完成节点更新。相比微信、支付宝小程序,快应用的开发语法标准,其语法也更接近传统网页。开发文档:https://doc.quickapp.cn/除了以上几大平台推出的小程序,其实优酷、钉钉、网易云音乐也出现过小程序的身影:优酷的小程序、钉钉的 E 应用,还有网易云音乐的「私藏推荐」。▲ 左为优酷小程序,右为网易云音乐小程序 在已有几大平台的努力下,小程序存在的方式和其代表的服务形态已经被越来越多的平台所认可。这些平台或许不会 all in 小程序,却也会在自己的生态内对小程序进行更多的尝试。和一个成熟、有包容性的平台相比,这几个平台或有严格的类目限制;或者只是将原有的 H5 内容转为了小程序;有的则只是模仿了小程序相似的界面。对于开发者而言,他们似乎不能算一个开放的开发平台,但也与小程序有着不小的联系。知晓云福利参与 iOS、Android SDK 内测领福利「知晓云」cloud.minapp.com,诞生于 2017 年 8 月 8 日,是以小程序开发为起点的后端云服务,它免去了小程序开发中服务器搭建、域名备案、数据接口开发、线上运维等繁琐流程,让开发者更快、更地做出优质的小程序。你的主要业务不在小程序,而是在移动端?没关系,iOS、Android 的应用开发也可以使用知晓云来完成了哦~知晓云移动端(iOS、Android)支持的内测活动已经开启:即日起至 4 月 17 日,填写表单报名参与内测活动的用户,在成功接入移动端(iOS、Android)应用后将获得 100 元无门槛优惠券???? 报名点这里 ???? ...

April 11, 2019 · 1 min · jiezi

QQ轻应用的开发问题与总结

最快的方法:可以直接用开发工具把微信小程序的代码直接转码。使用API文档开发时目前遇到好多问题,在等QQ的技术人员的处理。1、webView页面不能渲染。在等升级处理。2、加载、数据请求速度慢。3、其他问题没了,基本完全和微信小程序一样。

April 11, 2019 · 1 min · jiezi

Fundebug支持浏览器报警

摘要: 除了邮件报警和第三方报警,我们新增了浏览器报警功能。邮件报警与第三方报警Fundebug是专业的应用BUG监控服务,当您的线上应用,比如网页、小程序、Java等发生BUG时,我们会第一时间发送邮件报警,这样可以帮助您及时发现BUG,快速修复BUG。另外,我们还支持各种第三方报警方式,如下:钉钉Slack倍洽简聊Worktile零信自定义Webhook浏览器报警为了帮助用户第一时间发现BUG,我们支持了浏览器报警。默认情况下,如果您保持Fundebug控制台打开,我们会每隔1个小时检查是否有新的错误出现,并且通过浏览器提醒告诉您:您也可以在项目设置页面对该功能进行配置,选择开启或者关闭浏览器提醒,或者配置浏览器提醒的时间间隔(取值为60到3600秒之间)。最后,感谢Fundebug用户大宝的反馈。关于FundebugFundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了9亿+错误事件,付费客户有Google、360、金山软件、百姓网等众多品牌企业。欢迎大家免费试用!版权声明转载时请注明作者Fundebug以及本文地址:https://blog.fundebug.com/2019/02/25/fundebug-javascript-1-6-0/

April 10, 2019 · 1 min · jiezi

阿里小程序云应用上线了,有哪些看点?

3月21日,在2019阿里云峰会·北京上,阿里巴巴旗下的阿里云、支付宝、淘宝、钉钉、高德等联合发布“阿里巴巴小程序繁星计划”:提供20亿元补贴,扶持200万+小程序开发者、100万+商家。凡入选“超星”的小程序,入驻支付宝、淘宝、钉钉、高德后还能得到流量重点支持。阿里云近期发布小程序云应用,提供一站式云服务,为开发者提供稳定和便捷的后端云服务,包括 Serverless 开发套件、应用托管服务、函数计算等。开发者可在这些小程序端上进行统一的应用发布、资源管理、数据管理。接下来,我带大家来了解一下小程序云应用的具体内容:小程序云应用限量免费申请入口云应用产品架构产品价值通过一站式的资源编排、应用托管、DevOps 的能力降低企业和个人对小程序后端的开发成本。产品特色直接搭建和初始化好运行环境。支持 Node.js、Spring Boot 等主流框架应用托管。一站式的发布、运维、监控操作。方案优势资源编排通过对 ECS、RDS、SLB、EIP 等资源进行编排,帮助用户根据自身的业务情况提供不同规格配置自动搭建好符合业务场景的最优运行环境,低成本、高效率。应用托管为开发者提供主流应用框架的运行环境,直接上传 Node.js、Spring Boot、Java Web 部署包发布,开箱即用,极大的降低了前后端开发者对云服务的开发成本。一站式 DevOps支持开发者一站完成测试环境、生产环境的版本发布、扩容、资源监控等操作。无需运维即可高效进行线上服务的自动扩容、业务指标监控等。产品操作指引查看详情:https://yq.aliyun.com/activity/820?utm_content=g_1000051340扶持计划 - 云应用篇扶持计划说明:https://help.aliyun.com/document_detail/113009.html申请入口:https://yq.aliyun.com/activity/820?utm_content=g_1000051340本文作者:管理贝贝 阅读原文本文为云栖社区原创内容,未经允许不得转载。

April 10, 2019 · 1 min · jiezi

小程序中引用iconfont图标

1.在阿里图标库中找到需要的图标并加入项目2.把项目下载项目到本地3.在本地打开下载的目录将 iconfont.css文件改为iconfont.wxss复制到项目中4.在app.wxss中引入iconfont.wxss5.在阿里图标库我的项目中 点击复制代码6.将复制的@font-face替换掉iconfont.wxss中的@font-face7.在项目中引用详细教程点击传送门

April 9, 2019 · 1 min · jiezi

使用mpvue开发微信小程序——音乐小程序源码分享

使用mpvue开发微信小程序——音乐小程序项目源码分享:文章链接源码链接:https://github.com/XieTongXue…

April 9, 2019 · 1 min · jiezi

【Copy攻城狮日志】踩坑小程序之使用svg作为图标

Created 2019-4-4 22:02:27 by huqi Updated 2019-4-4 23:12:34 by huqi↑开局一张图,故事全靠编↑本地资源无法通过 WXSS 获取都9102年了,我居然还会犯如此低级的错误。不经想起去年犯的一个更低级的错误,事情的经过是这样的,去年@肖蜀黍 在某个群里丢了一个小程序链接–tell心语,这个小程序本身就具有传奇色彩,背后的故事更是感动人心,就是现实版的解忧杂货店;主要的功能是写信,也就是文字输入。然后,我居然脑残地去测试xss!!!不学无术,还要自命不凡,像我这样的没被祭天就是万幸了。这次,又是基本的常识都没掌握,直接淹死在浅坑里。background-image:可以使用网络图片,或者 base64,或者使用<image/>标签。这个是常识,连入门级小程序员都知道的。那我究竟写了个什么B.U.G?毫无疑问,一定是在BG中直接引用了本地图片。乳此低级的错误,一定要贴出来,示众以鞭策!.refresh-icon{ background: url(‘refresh.svg’);}.del-icon{ background: url(‘del.svg’);}获取iconfont的svg图作为老司机的“幼儿班程序员”,应该是没有资格拿到切好的图标了,没办法,技不如人,只能自己动手去啥都有的网上找找。关于图标,我最先想到的是阿里巴巴矢量图标库,这个由阿里妈妈MUX倾力打造的矢量图标管理、交流平台,设计师可以将图标上传到这个平台,用户可以自定义下载多种格式的icon,平台也可将图标转换为字体,便于前端工程师自由调整与调用。虽然可以将图标转化为字体应用,但对于我来说,就使用那么几个图标,实在是不想引用一大堆css、ttf等文件,只想用下svg。具体怎么操作,胸中自然有了竹子。搜索和UI图一模一样的图标,建议按照英文关键字查询,如del、refresh等点击下载进入下载模态详情页,选择合适的颜色下载svg转换svg为background既然官方文档说了,不让直接引用本地图片,但给了三条路,那我就随便远一条喽,反正我不想用网络图片,我也不想用image标签,那就只有转成base64喽,至于什么是base64,我也不知道,那就超度一下喽:☛base64。但是怎么快速将svg转换成这个base64甚至直接输出成css样式呢?我说,首先您得有工具得到svg源码,我用vscode,直接打开svg就是svg源代码;然后转base64,偶然发现了国外大佬在codepan上的在线实现,文章的话可以参考下“优化数据uris中的svgs” ,我特意fork了一份来学习,感兴趣的可以看下源码。有了这个工具,svg生成background也就是我专门干的事=copy&paste获取svg源码生成background重写background既然base64已经手到擒来了,那么实现图标按钮还会远吗,来来来,有请代码说话:超级简单!!!搜衣滋!.my-icon{ background-size: cover; display: inline-block; width: 50rpx; height: 50rpx; vertical-align: middle; margin-right: 4px;}.refresh-icon{ background-image: url(“data:image/svg+xml,%3C?xml version=‘1.0’ standalone=‘no’?%3E%3C!DOCTYPE svg PUBLIC ‘-//W3C//DTD SVG 1.1//EN’ ‘http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'%3E%3Csvg t=‘1554354671724’ class=‘icon’ style=’’ viewBox=‘0 0 1024 1024’ version=‘1.1’ xmlns=‘http://www.w3.org/2000/svg' p-id=‘1543’ xmlns:xlink=‘http://www.w3.org/1999/xlink' width=‘200’ height=‘200’%3E%3Cdefs%3E%3Cstyle type=‘text/css’%3E%3C/style%3E%3C/defs%3E%3Cpath d=‘M936.571429 603.428571q0 2.857143-0.571429 4-36.571429 153.142857-153.142857 248.285715T509.714286 950.857143q-83.428571 0-161.428572-31.428572T209.142857 829.714286l-73.714286 73.714285q-10.857143 10.857143-25.714285 10.857143t-25.714286-10.857143-10.857143-25.714285v-256q0-14.857143 10.857143-25.714286t25.714286-10.857143h256q14.857143 0 25.714285 10.857143t10.857143 25.714286-10.857143 25.714285l-78.285714 78.285715q40.571429 37.714286 92 58.285714t106.857143 20.571429q76.571429 0 142.857143-37.142858t106.285714-102.285714q6.285714-9.714286 30.285714-66.857143 4.571429-13.142857 17.142858-13.142857h109.714285q7.428571 0 12.857143 5.428572t5.428572 12.857142z m14.285714-457.142857v256q0 14.857143-10.857143 25.714286t-25.714286 10.857143h-256q-14.857143 0-25.714285-10.857143t-10.857143-25.714286 10.857143-25.714285l78.857142-78.857143q-84.571429-78.285714-199.428571-78.285715-76.571429 0-142.857143 37.142858T262.857143 358.857143q-6.285714 9.714286-30.285714 66.857143-4.571429 13.142857-17.142858 13.142857H101.714286q-7.428571 0-12.857143-5.428572T83.428571 420.571429v-4q37.142857-153.142857 154.285715-248.285715T512 73.142857q83.428571 0 162.285714 31.714286T814.285714 194.285714l74.285715-73.714285q10.857143-10.857143 25.714285-10.857143t25.714286 10.857143 10.857143 25.714285z’ p-id=‘1544’ fill=’%23ffffff’%3E%3C/path%3E%3C/svg%3E”);}.del-icon{ background-image: url(“data:image/svg+xml,%3C?xml version=‘1.0’ standalone=‘no’?%3E%3C!DOCTYPE svg PUBLIC ‘-//W3C//DTD SVG 1.1//EN’ ‘http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'%3E%3Csvg t=‘1554355910565’ class=‘icon’ style=’’ viewBox=‘0 0 1024 1024’ version=‘1.1’ xmlns=‘http://www.w3.org/2000/svg' p-id=‘2306’ xmlns:xlink=‘http://www.w3.org/1999/xlink' width=‘200’ height=‘200’%3E%3Cdefs%3E%3Cstyle type=‘text/css’%3E%3C/style%3E%3C/defs%3E%3Cpath d=‘M817.968553 215.897142l-169.357176 0 0-58.869782c0-25.391297-20.657482-46.048779-46.048779-46.048779l-181.125197 0c-25.391297 0-46.048779 20.657482-46.048779 46.048779l0 58.869782-169.357176 0c-25.391297 0-46.048779 20.657482-46.048779 46.048779l0 71.631434c0 25.391297 20.657482 46.048779 46.048779 46.048779l28.321022 0 0 425.947112c0 59.246359 48.200792 107.447151 107.447151 107.447151l340.40076 0c59.246359 0 107.447151-48.200792 107.447151-107.447151L789.647531 379.626133l28.321022 0c25.391297 0 46.048779-20.657482 46.048779-46.048779l0-71.631434C864.017332 236.554624 843.35985 215.897142 817.968553 215.897142zM426.553932 162.14389l170.892135 0 0 53.753251-170.892135 0L426.553932 162.14389zM738.482221 805.574269c0 31.033807-25.248034 56.281841-56.281841 56.281841L341.79962 861.85611c-31.033807 0-56.281841-25.248034-56.281841-56.281841L285.517779 379.626133l452.964442 0L738.482221 805.574269zM812.852022 328.460824l-601.704045 0 0-61.398372 203.227588 0c2.302439 0.356111 4.66116 0.542352 7.061836 0.542352l181.125197 0c2.400676 0 4.759397-0.186242 7.062859-0.542352l203.226564 0L812.852022 328.460824zM513.023306 783.320429c14.128789 0 25.582655-11.453866 25.582655-25.582655l0-288.572348c0-14.128789-11.453866-25.582655-25.582655-25.582655-14.128789 0-25.582655 11.453866-25.582655 25.582655l0 288.572348C487.440651 771.866562 498.894518 783.320429 513.023306 783.320429zM645.541459 783.320429c14.128789 0 25.582655-11.453866 25.582655-25.582655l0-288.572348c0-14.128789-11.453866-25.582655-25.582655-25.582655s-25.582655 11.453866-25.582655 25.582655l0 288.572348C619.958804 771.866562 631.41267 783.320429 645.541459 783.320429zM380.505154 783.320429c14.128789 0 25.582655-11.453866 25.582655-25.582655l0-288.572348c0-14.128789-11.453866-25.582655-25.582655-25.582655s-25.582655 11.453866-25.582655 25.582655l0 288.572348C354.922499 771.866562 366.376365 783.320429 380.505154 783.320429z’ p-id=‘2307’ fill=’%23ffffff’%3E%3C/path%3E%3C/svg%3E”);}附上效果图:svg转换核心源码// 用于创建优化的svg url的函数// Version: 1.0.6@function svg-url($svg){ // // 补齐命名空间 // @if not str-index($svg,xmlns) { $svg: str-replace($svg, ‘&ltsvg’,’&ltsvg xmlns=“http://www.w3.org/2000/svg"'); } // // 避免一大块的字符串 // 抛出“堆栈级别太深”错误 // $encoded:’’; $slice: 2000; $index: 0; $loops: ceil(str-length($svg)/$slice); @for $i from 1 through $loops { $chunk: str-slice($svg, $index, $index + $slice - 1); // // 编码 // $chunk: str-replace($chunk, ‘”’, ‘'’); $chunk: str-replace($chunk, ‘%’, ‘%25’); $chunk: str-replace($chunk, ‘#’, ‘%23’); $chunk: str-replace($chunk, ‘{’, ‘%7B’); $chunk: str-replace($chunk, ‘}’, ‘%7D’); $chunk: str-replace($chunk, ‘&lt;’, ‘%3C’); $chunk: str-replace($chunk, ‘&gt;’, ‘%3E’); // // 预计列表 // // 保持大小并缩短编译时间 // … 只添加记录的失败 // // $chunk: str-replace($chunk, ‘&’, ‘%26’); // $chunk: str-replace($chunk, ‘|’, ‘%7C’); // $chunk: str-replace($chunk, ‘[’, ‘%5B’); // $chunk: str-replace($chunk, ‘]’, ‘%5D’); // $chunk: str-replace($chunk, ‘^’, ‘%5E’); // $chunk: str-replace($chunk, ‘`’, ‘%60’); // $chunk: str-replace($chunk, ‘;’, ‘%3B’); // $chunk: str-replace($chunk, ‘?’, ‘%3F’); // $chunk: str-replace($chunk, ‘:’, ‘%3A’); // $chunk: str-replace($chunk, ‘@’, ‘%40’); // $chunk: str-replace($chunk, ‘=’, ‘%3D’); $encoded: #{$encoded}#{$chunk}; $index: $index + $slice; } @return url(“data:image/svg+xml,#{$encoded}”); } // Background svg mixin @mixin background-svg($svg){ background-image: svg-url($svg); } // 替换字符串中的字符的辅助函数@function str-replace($string, $search, $replace: ‘’) { $index: str-index($string, $search); @return if($index, str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace), $string); } 总算是又get了一个知识点,最近做小程序,遇到的难题还是挺多的,比如还没有解决的wx.redirectTo闪屏问题,有大佬要是恰好遇到过类似的坑,欢迎多多指教! ...

April 5, 2019 · 3 min · jiezi

手动实现“低配版”IOC

引言IOC,全称Inversion of Control,控制反转。也算是老生常谈了。老生常谈:原指老书生的平凡议论;今指常讲的没有新意的老话。同时另一个话题,依赖注入,用什么就声明什么,直接就声明,或者构造函数或者加注解,控制反转是实现依赖注入的一种方式。通过依赖注入:我们无需管理对象的创建,通过控制反转:我们可以一键修改注入的对象。最近在做Android实验与小程序相关的开发,发现用惯了IOC的我们再去手动new对象的时候总感觉心里不舒服,以后改起来怎么办呢?既然没有IOC,我们就自己写一个吧。实现就像我在标题中描述的一样,我先给大家讲解一下标配IOC的原理,使大家更清晰明了,但是受Android与小程序相关的限制,我具体的实现,是低配版IOC。个人扯淡不管是Spring还是Angular,要么是开源大家,要么是商业巨头,具体的框架实现都是相当优秀。我还没水平也没精力去研读源码,只希望分享自己对IOC的理解,帮到更多的人。毕竟现在小学生都开始写Python,以后的框架设计会越来越优秀,学习成本越来越低,开发效率越来越高。可能是个人报个培训班学个俩月也会设计微服务,也能成为全栈工程师。所以我们应该想的是如何设计框架,而不是仅停留在使用的层面,渐渐地被只会写增删改查天天搬砖的人取代。996加班的工程师都开始挤时间写框架扩大影响力,让社会听到程序员的呐喊,我们还有什么不努力的理由?“标配”IOC不管是Spring还是Angular,它们的核心是什么呢?打上mvn spring-boot:run后台就Started Application in xxx seconds了,它到底干什么了呢?容器Spring与Angular就是一个大的IOC容器,所以应用启动的过程,其实就是构造容器的过程。容器,肯定是装东西的啊?IOC容器里装的是什么?装的是对象。控制器Controller,服务Service,自定义的组件Component,所有被Spring管理的对象都将被放进IOC容器里。所以,大家应该能明白,为什么IOC是依赖注入的一种实现方式?因为这个对象不是你自己new的,是从容器中拿的,容器初始化的时候,就已经把这个对象构造好了,该注的都注进来了。思考从上面大家可以看到,依赖注入的前提是什么?是要求这个对象必须是从容器中拿的,所以才能依赖注入成功。Spring Boot中没问题,Tomcat转发的路由直接交给容器中相应的对象去处理,同理,Angular也一样。Android呢?手机调用的并不是我们构造的Activity,而是它自己实例化的,小程序也与之类似,Page的实例化不归我们管。所以“标配”IOC在这里不适用,所以我设计了“低配”IOC容器。“低配”IOC找点自己能管得了的对象放在IOC容器里,这样再需要对象就不用去new了,Service有变更直接修改注入就行了。受我们管理的只有Service,计划设计一个管理所有Service的IOC容器,然后Activity或Page里用的时候,直接从容器中拿。(低配在这里,不能依赖注入了,得自己拿)。Android端一个单例的Configuration负责注册Bean和获取Bean,存储着一个context上下文。看着挺高级的,其实就是一个HashMap存储着接口类型到容器对象的映射。/** * 全局配置类 /public class Configuration { private static Map<Class<?>, Object> context = new HashMap<>(); private static final class Holder { private static final Configuration INSTANCE = new Configuration(); } public static Configuration getInstance() { return Holder.INSTANCE; } public Configuration registerBean(Class<?> clazz, Object bean) { context.put(clazz, bean); return this; } public <T> T getBean(Class<?> clazz) { return (T) context.get(clazz); }}写一个静态方法,更加方便配置。/* * 云智,全局配置辅助类 */public class Yunzhi { … public static <T> T getBean(Class<?> clazz) { return Configuration.getInstance().getBean(clazz); }}一个Application负责容器中所有对象的创建。public class App extends Application { @Override public void onCreate() { super.onCreate(); Yunzhi.init() .setApi(“http://192.168.2.110:8888”) .setTimeout(1L) .registerBean(AuthService.class, new AuthServiceImpl()) .registerBean(LetterService.class, new LetterServiceImpl()); }}使用方法和原来就一样了,一个接口,一个实现类。这里用到了RxJava,看上去倒是类似我们的Angular了。public interface AuthService { Observable<Auth> login(String username, String password);}public class AuthServiceImpl implements AuthService { private static final String TAG = “AuthServiceImpl”; @Override public Observable<Auth> login(String username, String password) { Log.d(TAG, “BASIC 认证”); String credentials = username + “:” + password; String basicAuth = “Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP); Log.d(TAG, “请求登录”); return HttpClient.request(AuthRequest.class) .login(basicAuth) .subscribeOn(Schedulers.io()) // 在IO线程发起网络请求 .observeOn(AndroidSchedulers.mainThread()); // 在主线程处理 }}因为Activity我们管不着,所以在Activity里用不了依赖注入,需要手动从容器里拿。@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.authService = Yunzhi.getBean(AuthService.class);}这里有一处没考虑到的问题,就是手机端的性能问题,手机和服务器的处理能力肯定是比不了的,服务器在初始化的时候把所有对象都创建处理无可厚非,但是感觉手机端这样做还是会对性能产生一定影响的。应该是某些对象用到的时候再创建,实验要求时间很紧,这个就先这样吧,不改了。小程序端小程序是在Android之后写的,想到了之前设计的部分缺陷,对容器使用了另一种思想进行实现。export class YunzhiService { private static context = new Map<string, object>(); public static getBean(beanName: string): object { // 从context里拿对象 let bean = this.context.get(beanName); // 如果没有,构造一个,并放进context if (!bean) { bean = this.createBeanByName(beanName); this.context.set(beanName, bean); } // 返回 return bean; } public static createBeanByName(beanName: string): object { // 根据不同名称构造不同的Bean switch (beanName) { case Bean.AUTH_SERVICE: return new AuthServiceImpl(); case Bean.SCORE_SERVICE: return new ScoreServiceImpl(); case Bean.SEMESTER_SERVICE: return new SemesterServiceImpl(); default: throw ‘错误,未注册的bean’; } }}总结Spring Boot真厉害,什么时候我们也能写出如此优秀的框架? ...

April 3, 2019 · 2 min · jiezi

【Copy攻城狮日志】踩坑小程序之canvas的显示层级问题

Created 2019-4-3 18:29:53 by huqiUpdated 2019-4-3 19:12:22 by huqi↑开局一张图,故事全靠编↑从一个需求说起狼叔@i5ting 曾说过:“单纯讲技术进阶点意义不大,脱离场景都是耍流氓”。今天,依旧从一个需求说起。什么需求呢?一个二维码,一个二次确认弹窗。这里的二维码是前端生成的,二维码下边有个button,点击button调起自定义的弹窗组件。依旧是很简单的需求,但是对于“资深”的Copy攻城狮来说,除了布局,其他的就只能去Copy了。分析了一下可能需要的代码,就开始’刷刷刷’一顿CP(Copy&Paste)操作猛如虎,结果跑下代码发现error二百五。特别是真机跑的时候,问题特别多。像这次的问题,开发者工具上压根就发现不了,幸好习惯性真机预览,不然一通push就等着失业了。还是坑在基础不牢固,文档看得不深入,对小程序原生组件应该注意的事项把握不准,才会掉入这个非常基础的坑。(图片来源于网络)canvas生成二维码通常来说,遇到这种类似的需要,我都会先找找被人造的轮子,尝试一下,有合适的就直接拿过来用了。这次用的是@yingye 大佬开源的weapp-qrcode,这个js应该是借鉴了jquery-qrcode 和 node-qrcode,有兴趣的同学可以研究研究,生码的逻辑应该是类似的,只是小程序中没有DOM操作,都是利用canvas来实现的。具体怎么实现,各位看客可以直接看相关的源码或文档。我的实现:wxml<canvas style=“width: 140px; height: 140px;” canvas-id=“myQrcode”></canvas>wxsscanvas{ display: block; margin: 0rpx auto; /** 居中 /}js drawQrcode({ width: 140, // 必须,二维码宽度,与canvas的width保持一致 height: 140, // 必须,二维码高度,与canvas的height保持一致 x: 0, // 非必须,二维码绘制的 x 轴起始位置,默认值0 y: 0, // 非必须,二维码绘制的 y 轴起始位置,默认值0 canvasId: ‘myQrcode’, // 非必须,绘制的canvasId typeNumber: 10, // 非必须,二维码的计算模式,默认值-1 text: ‘您的二维码内容’, // 必须,二维码内容 callback(e) { // 非必须,绘制完成后的回调函数 console.log(’e: ‘, e) } })二维码效果:canvas使用限制当我页面如上图一样。底部有个按钮。点击唤起自定义的弹窗组件,在开发者工具上呈现的效果十分正常。但是在真机上就会出现文字开头的不和谐现象。canvas直接覆盖住了自定义组件。通过翻阅文档,您会发现官方特别写出了Bug&Tip:3.tip:请注意原生组件使用限制。4.bug: 避免设置过大的宽高,在安卓下会有crash的问题然后点开原生组件使用限制,就会发现本B.U.G的根本原因了:原生组件的层级是最高的,所以页面中的其他组件无论设置 z-index 为多少,都无法盖在原生组件上。也就是说canvas会覆盖自定义的dialog组件。那么怎么解决呢?我的思路是“曲线救国”–将canvas转成image。一不做二不休,撸起袖子,开干!将canvas转换成image既然原生组件(camera、canvas、focus时的input、live-player、live-pusher、map、textarea、video)这么牛逼,那就打压一下,去掉他们高贵的身份,豁免他们享有的特权,彻底ge他们的命,恢复他们的平民身份。按照这个思路,开始一步一步来实现wxml <canvas wx:if="{{!renderImg}}" style=“width: 140px; height: 140px;” canvas-id=“myQrcode”></canvas> <image wx:else mode=“scaleToFill” class=“image” style=“width: 140px; height: 140px;” src="{{renderImg}}"></image>js data: { renderImg: ’’ }, onLoad: function(){ drawQrcode({ width: 140, // 必须,二维码宽度,与canvas的width保持一致 height: 140, // 必须,二维码高度,与canvas的height保持一致 x: 0, // 非必须,二维码绘制的 x 轴起始位置,默认值0 y: 0, // 非必须,二维码绘制的 y 轴起始位置,默认值0 canvasId: ‘myQrcode’, // 非必须,绘制的canvasId typeNumber: 10, // 非必须,二维码的计算模式,默认值-1 text: ‘您的二维码内容’, // 必须,二维码内容 callback(e) { // 非必须,绘制完成后的回调函数 console.log(’e: ‘, e) if(e.errMsg == ‘drawCanvas:ok’) { // 新增转图片 wx.canvasToTempFilePath({ x: 0, y: 0, width: 140, height: 140, canvasId: ‘myQrcode’, success: function(res) { me.setData({ renderImg: res.tempFilePath}); } }); } } }) }以上将canvas替换成image,不过遇到闪烁的问题,这是wx:if特有的,这里通过取巧的办法,只改了canvas的样式:wxsscanvas{ display: block; margin: 0rpx -9999px; / 占位解决二维码闪屏 /}image{ display: block; margin: 0rpx auto; / 居中 **/}至此,已填了这个canvas显示层级过高的坑。如您有更好的方案,欢迎提出指正!如您觉得文章解决了您的问题,欢迎打赏 ...

April 3, 2019 · 1 min · jiezi

【Copy攻城狮日志】踩坑小程序之can't read property 'offsetLeft' of undefined

Created 2019-4-2 22:17:34 by huqiUpdated 2019-4-2 23:17:34 by huqi↑开局一张图,故事全靠编↑从一个需求说起接触过小程序的同学应该都接触过这样一个需求:点击列表页的某一项,进入详情页。同样,今天我也遇到这样一个需求,其实很简单的一个需求,无非就是一个tap事件加dataset传参实现路由带参数跳转到详情页。以前开发小程序的时候,也处理过这样的需求,本来应该是得心应手的。不过,可能是Copy别人代码Copy得太多太久太深,也从来没自主去想过别人为什么这样写、换种方式要怎样写、为什么换种方式就会报错等等诸如此类的问题,更别说去熟读开源源码,甚至自己造轮子。有时候反思,自己入行这么多年了,资质依旧平平,别说造轮子,就算是把别人轮子拿过来安上,都能整出一堆B.U.G。就比如开头的图片上,用的是鹅厂旗下某著名公司的豪华套餐,居然被我用得翻车了!–TypeError: Cannot read property ‘offsetLeft’ of undefined !!!简直了,还是只能怪自己技术太low了。(图片来源于网络)提问的智慧自从朋友给了我一个SS的IP和密码,现在我一有问题就是直接google开干。在我看来,与其把问题抛到各种广告满天飞的技术群或者丢给朋友圈里边的大佬,倒不如自己先动手解决,哪怕是尝试了所有的答案,至少对问题会有更深的理解,以后面试中遇到面试官问您在项目中遇到过什么问题之类的,因为经过自己的一番搜索加实践,一般印象会深刻很多。反而别人直接告诉您答案的,可能您的成本更小,但是收获甚微。根据以往的经验,遇到问题,自己动手,是更接近答案的唯一出路。或许您在开发中,遇到了某些问题,您通过一些途径解决了这个问题,然后,您又记录了下来,后续您遇到同样的问题,应该是可以迎刃而解的。如果您还把解决方案分享出来了,您简直是在造福人类。后来者,托您的福,更快的解决了同样的问题。尝试方案1–重启开发者工具can’t read property ‘offsetLeft’ of undefined #1132这是来自全球最大的同性交友网站GitHub上的一个issue,是由@yuwanlin 在一套遵循 React 语法规范的多端统一开发框架Taro中提出来的。根据当时的情境,是在微信开发者工具中删掉该小程序然后重新载入就解决了,大家给出的结论是微信小程序开发者工具的B.U.G。(注:该操作不会删除文件,请放心使用)–但是,我按照楼主的说法操作了一遍,结果然并卵,还是原来的B.U.G,还是一样的报错。该方案失败尝试方案2–外层加view自定义组件在首次点击后会报错@欧新志 这个小咯咯在2018-06-14向微信社区提出了类似的问题,他那个是自定义组件在点击之后出现了和我同款的B.U.G,而且也是存在嵌套子组件。评论中各位大神给出的答案是嵌套view。我也尝试了,试着加了一层view,但是问题依旧存在。不过我感还是和嵌套的子组件有关。于是,我各种尝试终于找到了一个方案。第一次滚动和点击的时候都有这个报错,下面是报错时的组件wxml<view class=“wraper” bindtap=“onClick”> <slot></slot></view>如果换成下面这样就不报错了<view><view class=“wraper” bindtap=“onClick”> <slot></slot></view></view>解决方案3–tap事件加在子组件里面原代码: <block wx:for="{{itemList}}" wx:key=“key” wx:code="{{item}}"> <view style=“margin-top: 15px” bindtap=“toDetail”> <dgd-preview> <!–常规 preview-list 控件 –> <view class=“dgd-preview-list” data-item="{{item}}"> <dgd-preview-item label=“服务中心名称” style=“color:#000;"> {{item.name}} </dgd-preview-item> <dgd-preview-item label=“预约业务” style=“color:#000;"> {{item.business}} </dgd-preview-item> <dgd-preview-item label=“预约时间” style=“color:#000;"> {{item.time}} </dgd-preview-item> <dgd-preview-item label=“预约状态” style=“color:#000;"> {{item.status}} </dgd-preview-item> </view> </dgd-preview> </view> </block>修改之后: <block wx:for=”{{itemList}}” wx:key=“key” wx:code=”{{item}}"> <view style=“margin-top: 15px”> <dgd-preview> <!–常规 preview-list 控件 –> <view class=“dgd-preview-list” bindtap=“toDetail” data-item=”{{item}}"> <dgd-preview-item label=“服务中心名称” style=“color:#000;"> {{item.name}} </dgd-preview-item> <dgd-preview-item label=“预约业务” style=“color:#000;"> {{item.business}} </dgd-preview-item> <dgd-preview-item label=“预约时间” style=“color:#000;"> {{item.time}} </dgd-preview-item> <dgd-preview-item label=“预约状态” style=“color:#000;"> {{item.status}} </dgd-preview-item> </view> </dgd-preview> </view> </block>只是把方法挂载到了不同的位置,确实截然不同的效果。看来接下来应该再研究一下小程序的组件。 ...

April 3, 2019 · 1 min · jiezi

想要更精准的小程序模版消息推送?我们来帮你实现

两年多前,为了让更多的人找到好玩、好用的小程序,我们成立了「知晓程序」。再后来,我们推出了后端云服务平台——知晓云,帮助大家降低创业成本,提升开发效率。「知晓云」cloud.minapp.com,诞生于 2017 年 8 月 8 日,是以小程序开发为起点的后端云服务,它免去了小程序开发中服务器搭建、域名备案、数据接口开发、线上运维等繁琐流程,让开发者更快、更低成本地做出优质的小程序。随着小程序生态的不断发展、用户规模的不断扩大,开发者的项目也在高速增长。他们不再满足于现有的后端服务支持,开始需要更多开箱即用的功能。为此,我们围绕「简化开发流程,让用户仅需专注于业务」这一目标,相继研发了多个好用的功能。在用户喜爱的众多功能中,使用率最高的是模版消息推送。这一功能自 2018 年 4 月上线后,使用率不断提升,完美的达成了我们设计此功能时的初衷——使用户获得【开箱即用,无需编码】的推送能力,并将其用于小规模的消息通知及用户管理。一年来,知晓云平台上有越来越多的小程序,从数百用户的小项目成长到 UV 过百万级,甚至超过千万的明星项目。模版消息推送数的量级也由早期每天几百条,变为后来的每天数百万条。客户的项目逐渐成熟,其需求也从简单的模版消息推送,逐渐转变为基于推送的转化、留存全链路触达与数据分析服务。因此,我们决定再往前迈进一步。5 月 8 日,我们将正式推出「知晓推送」服务,帮助运营者处理好粉丝转化、消息推送、数据分析等多个层面的麻烦事,真正解决复购难、留存差的问题。决定推出「知晓推送」服务前我们考察了市场上现在服务存在的问题,主要有这几条:平台支持少:只做了微信小程序平台支持,无法实现在支付宝小程序及其他平台发推送的需求。服务价格贵:按年收费且价格高昂,发送一千条推送就需要付出 10 块钱的成本。效果追踪差:模板消息发完就完事儿了,推送效果如何、用户是否点击,点击的用户特征,这些数据都无法追踪与分析。这些问题,我们来逐一解决。平台支持少?知晓云已经支持包括微信小程序和支付宝小程序在内的各大小程序平台的消息推送,对 Android、iOS 平台的支持也将在近期上线。大家的业务版图拓展到哪儿,我们支持到哪儿!服务价格贵?不得不说,友商的定价确实高得离谱。我们来算一笔账:假设小王有一个 2 万用户的小程序,日常运营每周一次推送,一年要发 100 万条模板消息。如用 x 神推的服务,要花 2 万块。2 万块啊!痛大家所痛,我们决定把它除以 200——只要 100 块。效果追踪差?经过长期的实践总结,我们推出 3 大重磅特性:过滤低价值用户,提升回访转化率大数据精准过滤有恶意举报行为或被标记为机器人的用户,有效减少无效发送,提升模板消息的回访转化率。一键埋点,自动收集 formid收集用户的 formid 是发送模板消息的前提条件,知晓云 SDK 提供透明页面自动收集 formid 功能,在不打扰用户的前提下即可收集大量 formid。智能发送规则,实现精准推送开发者可以自行定义用户行为,为满足特定条件的用户发送对应的模板消息。实现消息的精准推送。知晓云结合不同行业的海量行业案例,挖掘了一套专有的用户过滤机制,祝你实现业务量的翻倍增长。「知晓推送」活动预告「知晓推送」的主要特性说完了。考虑到 5 月还比较遥远,我们先预告一下福利吧:如你还不是知晓云用户,赶紧注册用起来吧~「知晓推送」正式上线前完全免费,服务上线当天还有额外福利~如你已经是知晓云用户了,也请您放心。5.8 日前注册的用户都可获赠价值不少于 198 元的资源包哦~支持 iOS、Android 的公测福利(4/2 - 4/10)「知晓云」cloud.minapp.com,诞生于 2017 年 8 月 8 日,是以小程序开发为起点的后端云服务,它免去了小程序开发中服务器搭建、域名备案、数据接口开发、线上运维等繁琐流程,让开发者更快、更低成本地做出优质的小程序。另外,知晓云支持移动端(iOS、Android)的公测活动即将开启:即日起至 4 月 10 日,通过扫描下方的二维码填写表单报名参与公测活动的用户,在成功接入移动端(iOS、Android)应用后将获得 100 元无门槛优惠券???? 报名点这里????知晓云是国内首家专注于小程序开发的后端云服务。使用知晓云,小程序开发快人一步。

April 2, 2019 · 1 min · jiezi

跨端开发框架深度横评

上周,Taro 团队发布了一篇《小程序多端框架全面测评》,让开发者对业界主流的跨端框架,有了初步认识。感谢 Taro 团队的付出。不过横评这件事,要想做完善,其实非常花费时间。不是只看文档就行,它需要:真实的动手写多个平台的测试demo,比较各个平台的功能、性能,它们的实际情况到底是不是如文档宣传的那样?真实的学习每个框架,了解它们的学习曲线,在实际开发中遇到问题时,感受它们的文档、教程、社区生态和技服能力到底怎么样?我们 uni-app 团队投入一周完成了这个深度评测,下面我们就分享下,实际开发不同框架的测试例遇到的问题,和最终的测试结果。评测实验介绍开发内容:开发一个仿微博小程序首页的复杂长列表,支持下拉刷新、上拉翻页、点赞。界面如下:开发版本:一共开发了6个版本,包括微信原生版、wepy版、mpvue版、taro版、uni-app版、chameleon版(以这些产品发布时间排序,下同),按照官网指引通过cli方式默认安装(应该是最新稳定版)。测试代码开源(Github仓库地址:https://github.com/dcloudio/test-framework),Tips:若有同学觉得测试代码写法欠妥,欢迎提交 PR 或 Issus测试机型:红米 Redmi 6 Pro、MIUI 10.2.2.0 稳定版(最新版)、微信版本 7.0.3(最新版)测试环境:每个框架开始测试前,杀掉各App进程、清空内存,保证测试机环境基本一致;每次从本地读取静态数据,屏蔽网络差异。测试维度:跨端支持度如何?性能如何?学习门槛工具与周边生态1. 跨端支持度如何开发一次,到处运行,是每个程序员的梦想。但现实往往变成开发一次,到处调错。各个待评测框架,是否真得如宣传的那样,一次开发、多端发布?我们将上述仿微博App依次发布到各平台,验证每个框架在各端的兼容性,结果如下:平台微信原生wepympvuetarouni-appchameleon微信小程序⭕️⭕️⭕️⭕️⭕️⭕️支付宝小程序❌❌⭕️⭕️⭕️❌百度小程序❌❌⭕️⭕️⭕️❌头条小程序❌❌⭕️⭕️⭕️❌H5端❌❌❌上拉加载/下拉刷新失效⭕️上拉加载/下拉刷新失效App端❌❌❌上拉加载失效⭕️列表无法滚动,无法测试上拉加载/下拉刷新测试结果说明:⭕ 表示支持且功能正常,❌ 表示不支持,其它则表示支持但存在部分bug或兼容问题wepy 2.0 宣称版已支持其他家小程序,本测试基于wepy官网指引安装的wepy-cli默认版本为1.7.3,尚不支持多端chameleon尝鲜版宣称支付宝、百度小程序,本测试基于chameleon官网指引安装的chameleon-tool默认版本为0.1.1,尚不支持其它小程序通过这个简单的例子可以看出,跨端支持度测评结论:uni-app > taro > chameleon > mpvue >wepy、原生微信小程序但是仅有上面的测试还不全面,实际业务要比这个测试例复杂很多。但我们没法开发很多复杂业务做评测,所以还需要再对照各家文档补充一些信息。由于每个框架的文档中都描述了各种组件和API的跨端支持程度。我们过了几家的文档,发现各家基本是以微信小程序为基线,然后把各种组件和API在其他端实现了一遍:taro:H5端实现了大部分微信的API,App端和微信的差异比较大。uni-app:组件、API、配置,大部分在各个端均已实现,个别API有说明在某些端不支持。可以看出uni-app是完整在H5端实现了一套微信模拟器,在App端实现了一套微信小程序引擎,才达到比较完善的平台兼容性。chameleon:非常常用的一些组件和API在各端已经实现,这部分的平台差异较少。但大量组件和API需要开发者自己分平台写代码。跨端框架,一方面要考虑框架提供的通用api跨端支持,同时还要考虑不同端的特色差异如何兼容。毕竟每个端都会有自己的特色,不可能完全一致。taro:提供了js环境变量判断和统一接口的多端文件,可以在组件、js、文件方面扩展多端,不支持其他环节的分平台处理。uni-app:提供了条件编译模型,所有代码包括组件、js、css、配置json、文件、目录,均支持条件编译,可不受限的编写各端差异代码。chameleon:提供了多态方案,可以在组件、js、文件方面扩展多端,不支持其他方式的分平台处理。跨端框架,还涉及一个ui框架的跨端问题,评测结果如下:taro:官方提供了taro ui,支持小程序(微信/支付宝/百度)、H5平台,不支持App,详见uni-app:官方提供了uni ui,可全端运行;uni-app还有一个插件市场,里面有很多三方ui组件,详见chameleon:官方提供了cml-ui扩展组件库,可全端运行,但组件数量略少,详见最后补充跨端案例:mpvue:微信端案例丰富,未见其它端案例taro:微信端案例丰富,百度、支付宝、H5端亦有少量案例uni-app:微信、App、H5三端案例丰富,官方示例已发布到6端chameleon:未看到任何端案例综合以上信息,本项的最终评测结论:uni-app > taro > chameleon > mpvue > wepy、原生微信小程序之前曾有友商掀起一番真跨端和伪跨端之争,通过本次Demo实测,这个争论可以盖棺定论了。2. 跨端框架性能如何跨端框架基本都是compiler + runtime模式,引入的runtime是否会降低运行性能?尤其是与原生微信小程序开发相比性能怎么样,这是大家普遍关心的问题。我们依然以上述仿微博小程序为例,测试2个容易出性能问题的点:长列表加载、大量点赞组件的响应。2.1 长列表加载仿微博的列表是一个包含很多组件的列表,这种复杂列表对性能的压力更大,很适合做性能测试。从触发上拉加载到数据更新、页面渲染完成,需要准确计时。人眼视觉计时肯定不行,我们采用程序埋点的方式,制定了如下计时时机:计时开始时机:交互事件触发,框架赋值之前,如:上拉加载(onReachBottom)函数开头计时结束时机:页面渲染完毕(微信setData回调函数开头)Tips:setData回调函数开头可认为是页面渲染完成的时间,是因为微信setData定义如下(微信规范):字段类型必填描述dataObject是这次要改变的数据callbackFunction否setData引起的界面更新渲染完毕后的回调函数测试方式:从页面空列表开始,通过程序自动触发上拉加载,每次新增20条列表,记录单次耗时;固定间隔连续触发 N 次上拉加载,使得页面达到 20*N 条列表,计算这 N 次触发上拉 -> 渲染完成的平均耗时。测试结果如下:列表条数微信原生wepympvuetarouni-appchameleon2007706259697526411261400876781449397474119706001111–125091029178001406–15471113404010001690–187813215196说明:以400条微博列表为例,从页面空列表开始,每隔1秒触发一次上拉加载(新增20条微博),记录单次耗时,触发20次后停止(页面达到400条微博),计算这20次的平均耗时,结果微信原生在这20次 触发上拉 -> 渲染完成 的平均耗时为876毫秒,最快的uni-app是741毫秒,最慢的mpvue是4493毫秒大家初看这个数据,可能比较疑惑,别急,下方有详细说明说明1:为何 mpvue/wepy 测试数据不完整?mpvue、wepy 诞生之初,微信小程序尚不支持自定义组件,无法进行组件化开发;mpvue、wepy 为解决这个问题,将用户编写的Vue组件,编译为WXML中的模板(template),变相实现了组件化开发能力,提高代码复用性,这在当时的技术条件下是很棒的技术方案。但如此方案,在复杂组件较多的页面,会大量增加 dom 节点,甚至超出微信的 dom 节点数限制。我们在 红米手机(Redmi 6 Pro)上实测,页面组件超过500个时,mpvue、wepy 实现的仿微博App就会报出如下异常,并停止渲染,故这两个测试框架在组件较多时,测试数据不完整。这也就意味着,当页面组件太多时,无法使用这2个框架。dom limit exceeded please check if there’s any mistake you’ve madeTips:wepy在400条列表以内,为何性能高于微信原生框架,这个跟自定义组件管理开销及业务场景有关(wepy编译为模板,不涉及组件创建及管理开销),后续对微博点赞,涉及组件数据传递时,微信原生框架的性能优势就提现出来了,详见下方测试数据。说明2:uni-app 比微信原生框架性能更好?逆天了?其实,在页面上有200条记录(200个组件)时,taro 性能数据也比微信原生框架更好。微信原生框架耗时主要在setData调用上,开发者若不单独优化,则每次都会传递大量数据;而 uni-app、taro 都在调用setData之前自动做diff计算,每次仅传递有变化的数据。例如当前页面有20条数据,触发上拉加载时,会新加载20条数据,此时原生框架通过如下代码测试时,setData会传输40条数据data: { listData: []},onReachBottom() { //上拉加载 let listData = this.data.listData; listData.push(…Api.getNews());//新增数据 this.setData({ listData }) //全量数据,发送数据到视图层}开发者使用微信原生框架,完全可以自己优化,精简传递数据,比如修改如下:data: { listData: []},onReachBottom() { //上拉加载 // 通过长度获取下一次渲染的索引 let index = this.data.listData.length; let newData = {}; //新变更数据 Api.getNews().forEach((item) => { newData[’listData[’ + (index++) + ‘]’] = item //赋值,索引递增 }) this.setData(newData) //增量数据,发送数据到视图层}经过如上优化修改后,再次测试,微信原生框架性能数据如下:组件数量微信原生框架(优化前)微信原生框架(优化后)uni-apptaro20077057264175240087668874197460011118559101250800140610551113154710001690126013211878从测试结果可看出,经过开发者手动优化,微信原生框架可达到更好的性能,但 uni-app、taro 相比微信原生,性能差距并不大。这个结果,和web开发类似,web开发也有原生js开发、vue、react框架等情况。如果不做特殊优化,原生js写的网页,性能经常还不如vue、react框架的性能。也恰恰是因为Vue、react框架的优秀,性能好,开发体验好,所以原生js开发已经逐渐减少使用了。复杂长列表加载下一页评测结论:微信原生开发手工优化,uni-app>微信原生开发未手工优化,taro > chameleon > wepy > mpvue2.2 点赞组件响应速度长列表中的某个组件,比如点赞组件,点击时是否能及时的修改未赞和已赞状态?是这项测试的评测点。测试方式:选中某微博,点击“点赞”按钮,实现点赞状态状态切换(已赞高亮、未赞灰色),点赞按钮 onclick函数开头开始计时,setData回调函数开头结束计时;在红米手机(Redmi 6 Pro)上进行多次测试,求其平均值,结果如下:列表数量微信原生wepympvuetarouni-appchameleon2009127966692931014001115011507125107145600144–152148178800176–2141812361000220–229234272说明:也就是在列表数量为400时,微信原生开发的应用,点赞按钮从点击到状态变化需要111毫秒。测试结果数据说明:wepy/mpvue 测试数据不完整的原因同上,在组件较多时,页面已经不再渲染了基于微信自定义组件实现组件开发的框架(uni-app/taro/chameleon),组件数据通讯性能接近于微信原生框架,远高于基于template实现组件开发的框架(wepy/mpvue)性能组件数据更新性能测评:微信原生开发,uni-app,taro > chameleon > wepy > mpvue综上,本性能测试做了2个测试,长列表加载和组件状态更新,综合2个实验,结论如下:微信原生开发手工优化,uni-app>微信原生开发未手工优化,taro > chameleon >> wepy > mpvue3. 学习门槛DSL语法支持度主流跨端框架基本都遵循React、Vue(类Vue)语法,其主要目的:复用工程师的现有技术栈,降低学习成本。此时,跨端框架对于原框架(React/Vue)语法的支持度就是一个重要的衡量标准,如果支持度较低、和原框架语法差异较大,则开发者无异于要学习一门新的框架,成本太高。实际开发中发现,各个多端框架,都没有完全实现vue、react在web上的所有语法:taro 对于 JSX 的语法支持是相对完善的,其文档中描述未来版本计划,更多的 JSX 语法支持,1.3 之后限制生产力的语法只有只能用 map 创造循环组件一条mpvue、uni-app 框架基于 Vue.js 核心,通过修改 Vue.js 的 runtime 和 compiler,实现了在小程序端的运行,支持绝大部分的Vue语法;uni-app 编译到微信端曾经使用过mpvue,但后来重写框架,支持了更多vue语法如filter、复杂 JavaScript 表达式等;wepy、chameleon 都是 类Vue 的实现,仅支持 Vue 的部分语法,开发时需要单独学习它们的规则;DSL语法支持评测:taro,uni-app > mpvue > wepy,chameleon学习资料完善度官方文档、搜索系统的完备度方面:uni-app文档内容丰富,示例demo完备,taro次之,其他几个框架相对要弱一些。mpvue文档虽少,但其概念不复杂,也没有支持H5、App,组件、API文档都可直接看微信的文档,学习难度倒也很低。教程方面:uni-app官方有视频教程,不少三方专业培训机构也录制的uni-app教程,包括腾讯课堂自家NEXT学院也录制了uni-app培训视频课,公开售卖;mpvue在腾讯课堂也有三方视频教程售卖;taro没有视频教程,但官方发布了掘金小册;wepy和chameleon还没有专业教程。学习资料完善度评测:uni-app > mpvue , taro > chameleon > wepy技术支持和社区活跃度开发难免遇到问题,官方技术支持和社区活跃度很重要。目前看,uni-app、taro、chameleon都有专职人员做技术支持,uni-app因交流群过多,还单独引入了智能客服机器人。活跃的社区意味着你遇到问题有人可问、或者前人会沉淀经验到文章里供你搜索。uni-app官方有30多个交流群(其中有很多千人大群),自建论坛中有大量交流帖子;taro和mpvue有9个500人微信群;wepy官网的微信已无法添加,chameleon发布较晚,用户群还较少。除uni-app外,其他框架没有自建论坛社区。本次评测demo开发期间,我们的同学(同时掌握vue和react),在学习研究各个多端框架时,切实感受到由于语法、学习资料、社区的差异带来的学习门槛,吐出了很多槽。综合评估,本项评测结论:uni-app > taro > mpvue > wepy > chameleonTips:本测评忽略React、Vue两框架自身的学习门槛4. 工具和周边生态工具所有多端框架均支持cli模式,可以在主流前端工具中开发。各框架基本都带有d.ts的语法提示库。由于mpvue、uni-app、taro直接支持vue、react语法,配套的ide工具链较丰富,着色、校验、格式化完善,chameleon针对部分编辑器推荐了插件,wepy有一些三方维护的vscode插件。工具属性维度,明显高出一截的框架是uni-app,其出品公司同时也是HBuilder的出品公司,DCloud.io。HBuilder/HBuilderX系列是国产开发工具,有300万开发者用户。HBuilderX为uni-app做了很多优化,故uni-app的开发效率、易用性非其他框架可及。当然对于不习惯HBuilderX的开发者而言,uni-app的这个优势无法体现。周边生态一个底层框架,其周边配套非常重要,比如ui库、js库、项目模板。wepy:出现时间久,开源项目多,占据一定优势。mpvue:发布时间也较早,历史积累较多。taro:官方提供了taro ui,github上有一些开源项目。uni-app:提供了插件市场,ui库、周边模板丰富chameleon:还没有形成周边生态。值得注意的是,uni-app和mpvue的插件生态是互通的,都是vue插件。所以双方还联合举办了插件大赛。这个联合生态的周边丰富度,是目前各个框架中最丰富的。顺便打个广告,欢迎有实力的同学参加 uni-app/mpvue插件开发大赛,领取iPhone Xs Max等丰厚奖品。综上比较,工具和周边生态评测结论:uni-app,mpvue > wepy > taro > chameleon其他常见评测指标github star:wepympvuetarouni-appchameleon17136166501707847284287github star 数对比:wepy > taro > mpvue > uni-app > chameleonTips:star 数采集时间:2019.03.31 21:30star 数量和产品发布时间有关,也和用户使用习惯有关;除uni-app外,其他框架的交流互动主要是github的issus,uni-app的开发者一般在uni-app的问答社区中交流反馈,github页面访问量较低。百度指数百度指数代表了开发者的搜索量和包含关键字的网页数量。如下是各跨端框架近7天(2019-03-24 ~ 2019-03-30)的百度指数:Tips:wepy未被百度指数收录,说明其搜索量和包含该关键字的网页数量都不够多。taro和chameleon 的名称取自于已存在的名称,实际指代开发框架的指数应该更低。案例仅看发布到微信小程序的案例,数量和质量综合对比,wepy > mpvue > taro , uni-app > chameleon如果看多端案例,综合对比,uni-app > taro > mpvue > wepy > chameleon除了uni-app外,其他跨端框架的出品方本身为一线开发商,其内部项目会使用这些框架,经受过实战考验。但同时鲜有其他大开发商使用这类框架。这里面有面子问题,也有兼容问题。很多开发商做的框架,可以满足其自身业务需求,但对外开放后想满足所有开发者,仍然需要投入大量工作完善产品,很多开发商主营业务不在此,并没有这么做。这也是很多开源项目被称为KPI项目的原因。客观讲,凹凸实验室投入如此大精力打磨taro,让uni-app团队也很惊讶和佩服。chameleon团队初期投入也很大,但发布时间还短,如果能长期投入下去,也是令人敬佩的。uni-app团队本身就是专业做开发者服务的,案例很多,但创业者居多。可以说整个多端框架市场仍处于起步期,距离让更多开发者接受,还需要所有框架作者的共同努力。其他补充说明1. 开源和App侧的补充说明有的友商在评测中提到uni-app的开源性不足问题。需要说明下,uni-app和其他多端框架一样,都是前端框架,是纯开源的。除了uni-app,其他框架的App端,或者使用expo(一个基于react native的封装库)、或者使用weex。做过这些开发的人都知道,原生排版引擎和web排版引擎有很多差异。而且不管react native还是weex,都只是渲染器,能力部分还需要开发者写原生代码,这就无法跨端了。expo比react native强的是多封装了一些能力,但也带来新的限制。uni-app的App端,是一个真的小程序引擎,又补充了可选的weex引擎。这也是uni-app在App端能够提供比其他跨端框架更好兼容性的原因。而这个引擎,是另一个开源项目,叫h5p,这个引擎是部分开源状态。整个业内目前还不存在一个完全开源的小程序引擎。不过uni-app的App端使用许可是完全免费,可以放心使用。其实也不用好奇为什么DCloud会有小程序引擎,因为业内第一个做小程序的并不是微信,而是DCloud。关于App端,其实可以再写出一篇很长的专业评测。后续uni-app团队会再做一篇App端与react native、weex、cordova、flutter等框架的对比。2. 转换和混写taro提供了原生小程序转换为taro工程的转换器,也支持在原生小程序里部分页面嵌入taro编写的页面,这是taro的特色,其他跨端框架没有提供。这对于降低入门门槛有不少帮助。结语真实客观的永远是实验和数据,而不是结论。不同需求的开发者,可以根据上述实验数据,自行得出自己的选型结论。但作为一篇完整的评测,我们也必须提供一份总结,虽然它可能加入了我们的主观感受:如果你想多端开发,提升效率,不想踩太多坑,uni-app相对更完善。如果你只开发微信小程序,不做多端,那么使用uni-app、微信原生开发、taro是更优的选择。如果使用微信原生开发,需要注意手动写优化代码来控制setdata如果你是react系,那就用taro如果是vue系,那就用uni-app,uni-app在性能、周边生态和开发效率上更有优势如果你主要为了微信端和H5端,那么uni-app和taro都可以。可以根据自己熟悉的技术栈选择。如果你主要需要跨App端,uni-app兼容性更好,其他框架的App端差异过大。如果你只关心App,不关心小程序和H5,那欢迎关注我们后续的评测:uni-app和cordova、react native、flutter的深度比较。如果你主要为了各家小程序,且不用复杂组件,那除了uni-app和taro,mpvue也是不错的选择。mpvue发布2.0版本后,搜索指数明显爬升,希望能持续更新,迎来二次繁荣。chameleon发布不久,提供的组件和API还很少,但其未来的规划比较令人期待,值得关注。这篇评测写完后,小编有点惴惴不安。一方面本评测不太温和,容易得罪人。但我们相信,这样的评测,会激起所有跨端框架从业者的斗志,让大家投入更多去完善产品,这对整个产业、对前端开发者,是大好事。另一方面,读者可能会以为现阶段的uni-app很完美,其实我们深知uni-app还有很多需要完善的地方。uni-app团队也将持续投入心血,为中国的前端开发者造福!如有读者认为本文中任何评测失真,欢迎在这里报issues。 ...

April 2, 2019 · 2 min · jiezi

小程序自定义导航栏适配(完美版)

1、发现问题小程序页面自定义导航栏功能已经开放有些日子了(还不知道这个功能的可以先>>了解一下),这极大的提升了小程序开发的自由度,相信不少小伙伴已经使用过这个功能,同时也相信不少小伙伴在此功能开发过程中踩过同样的一些坑:机型多如牛毛:自定义导航栏高度在不同机型始终无法达到视觉上的统一;调皮的胶囊按钮:导航栏元素(文字,图标等)怎么也对不齐那该死的胶囊按钮;各种尺寸的全面屏,奇怪的刘海屏,简直要抓狂。同样的,这些问题也是小灰经历过的。但是小灰相信,办法总比问题多,于是开始了自己的探究:2、一探究竟为了搞明白到底该怎么去适配,老规矩,我先翻了一波官方文档,还别说,官方还真有这么一段介绍了相关细节,>>详情点击:从图中分析,我们可以得到如下信息:Android跟iOS有差异,表现在顶部到胶囊按钮之间的距离差了6pt胶囊按钮高度为32pt, iOS和Android一致这。。。,好像并没有什么L用啊??这仅仅是普通屏幕为参照的,ipx, 安卓全面屏完全没介绍。沉着冷静,我们接着分析:胶囊按钮到状态栏下边缘这块距离,好像是固定的?安卓这个图,好像有点奇怪?导航栏分为 状态栏+标题栏?如果车两个条件成立,那我们的问题是不是就解决了80%了?那么我们来论证一下:第一个问题:胶囊按钮到状态栏下边缘的距离是不是固定的?很简单,我们写一个状态栏,通过wx.getSystemInfoSync().statusBarHeight设置高度为了好测量,我们设置状态栏背景色为深色js代码:var sysinfo = wx.getSystemInfoSync();this.setData({ statusBarHeight:sysinfo.statusBarHeight })wxml代码:<view class=“status-bar” style=“height:{{statusBarHeight}}px”></view>wxss代码:.status-bar{ background: rgb(141, 71, 71); }效果图(iPhone6):效果图(iPhoneX):效果图(安卓):是不是有点眉目了?是的,从截图可以看出,iOS是一致的,但是Android好像有所差别。那究竟距离是多少?我们用神器(微信截图)来量一量:Android:iOS:可以看出,iOS胶囊按钮与状态栏之间距离为:6px, Android为8px,并且经过测量,iOS各机型,Android各机型结果一致(由于篇幅原因,就不一一展示截图了,有兴趣的可以自行测量)第二个问题:导航栏分为 状态栏+标题栏?通过对第一个问题的论证,很明显能看出来确实是这样的。并且通过第一个问题的测量结果以及官方提供的数据,我们可以对标题栏高度进行计算:导航栏高度 = 胶囊按钮高度 + 状态栏到胶囊按钮间距 * 2Android导航栏高度 = 32px + 8px * 2 = 48pxiOS导航栏高度 = 32px + 6px * 2 = 44px*注:由于胶囊按钮是原生组件,为表现一直,其单位在个系统都为px,所以我们的自定义导航栏各个高度的单位都必需是px(切记不能用rpx),才能完美适配。3、解决问题通过上述分析,相信小伙伴们都能有一个解决问题的思路了,在上代码之前,小灰再给大家画一下重点:写自定义导航组件的时候,需要将组件结构一分为二:状态栏 + 标题栏状态栏高度可通过wx.getSystemInfoSync().statusBarHeight获取标题栏高度:安卓:48px,iOS:44px单位必需跟胶囊按钮一致,用px话不多说,上代码(gitHub地址):js:Component({ properties: { background: { type: String, value: ‘rgba(255, 255, 255, 1)’ }, color: { type: String, value: ‘rgba(0, 0, 0, 1)’ }, titleText: { type: String, value: ‘导航栏’ }, titleImg: { type: String, value: ’’ }, backIcon: { type: String, value: ’’ }, homeIcon: { type: String, value: ’’ }, fontSize: { type: Number, value: 16 }, iconHeight: { type: Number, value: 19 }, iconWidth: { type:Number, value: 58 } }, attached: function(){ var that = this; that.setNavSize(); that.setStyle(); }, data: { }, methods: { // 通过获取系统信息计算导航栏高度 setNavSize: function() { var that = this , sysinfo = wx.getSystemInfoSync() , statusHeight = sysinfo.statusBarHeight , isiOS = sysinfo.system.indexOf(‘iOS’) > -1 , navHeight; if (!isiOS) { navHeight = 48; } else { navHeight = 44; } that.setData({ status: statusHeight, navHeight: navHeight }) }, setStyle: function() { var that = this , containerStyle , textStyle , iconStyle; containerStyle = [ ‘background:’ + that.data.background ].join(’;’); textStyle = [ ‘color:’ + that.data.color, ‘font-size:’ + that.data.fontSize + ‘px’ ].join(’;’); iconStyle = [ ‘width: ’ + that.data.iconWidth + ‘px’, ‘height: ’ + that.data.iconHeight + ‘px’ ].join(’;’); that.setData({ containerStyle: containerStyle, textStyle: textStyle, iconStyle: iconStyle }) }, // 返回事件 back: function(){ wx.navigateBack({ delta: 1 }) this.triggerEvent(‘back’, {back: 1}) }, home: function() { this.triggerEvent(‘home’, {}); } }})wxml:<view class=‘nav’ style=‘height: {{status + navHeight}}px’> <view class=‘status’ style=‘height: {{status}}px;{{containerStyle}}’></view> <view class=‘navbar’ style=‘height:{{navHeight}}px;{{containerStyle}}’> <view class=‘back-icon’ wx:if="{{backIcon}}" bindtap=‘back’> <image src=’{{backIcon}}’></image> </view> <view class=‘home-icon’ wx:if="{{homeIcon}}" bindtap=‘home’> <image src=’{{homeIcon}}’></image> </view> [链接描述][10] <view class=‘nav-icon’ wx:if="{{titleImg}}"> <image src=’{{titleImg}}’ style=’{{iconStyle}}’></image> </view> <view class=‘nav-title’ wx:if="{{titleText && !titleImg}}"> <text style=’{{textStyle}}’>{{titleText}}</text> </view> </view> </view>wxss:.navbar{ position: relative}.back-icon, .home-icon{ width: 28px; height: 100%; position: absolute; transform: translateY(-50%); top: 50%; display: flex; }.back-icon{ left: 16px;}.home-icon{ left: 44px}.back-icon image{ width: 28px; height: 28px; margin: auto;}.home-icon image{ width: 20px; height: 20px; margin: auto;}.nav-title, .nav-icon{ position: absolute; transform: translate(-50%, -50%); left: 50%; top: 50%; font-size: 0; font-weight: bold;}运行效果图:文字标题:图片标题:4、总结经过小灰的一番论证以及实践经验,最终总结出以上最终解决方案,但希望对小伙伴们有所帮助,如果小伙伴们觉得有用,记得给颗star哦 –> 点我,后续还会更新其他组件。如果大家有更好的方案或者觉得小灰的方案有问题,欢迎大家留言。 ...

April 2, 2019 · 2 min · jiezi

微信小程序开发早知道

小程序没有跳转公众号、跳转公众号图文素材的能力。除非用户通过扫描二维码进入小程序的情景,可以显示关注公众号组件。公众号菜单、公众号图文素材可以打开小程序,网页无法直接打开小程序。小程序内嵌网页、内嵌网页中跳转链接、iframe 嵌套的页面,都必须在安全域名内,否则无法访问。如果想在小程序内加入第三方广告,要注意这点,因为安全域名修改是有次数限制的,并要求验证服务器。还要注意网页中嵌套 iframe 的情况,例如,网页内嵌了腾讯视频 iframe,由于腾讯视频不在安全域名内,会造成页面无法访问。用户信息授权、手机号码授权需要用户通过点击操作。小程序间跳转需要用户点击操作,跳转前需要用户确认,可跳转小程序数量不超过10个。小程序分为开发版、体验版、审核版、线上版:开发版是开发工具编辑过的最新版本;开发工具上传后成为体验版,具备体验权限的用户都可以查看;将开发版提交给官方审核后,成为审核版;审核成功后,才可以发布成为线上版本。官方「小程序助手」小程序可以很方便打开各版本小程序。每次发布新版本,用户都需要重新下载新版本。小程序仍在不断更新和完善,旧代码可能会因不符合新政策,在下次发布的时候无法正常运行。为避免这种情况的发生,应多关注官方公告。版本回退功能可以将线上版本回退成上一个版本小程序使用 CommonJS 规范,对 ES6 有很好的支持小程序没有官方状态管理工具,页面间通讯靠 query string 传递参数。如果有复杂状态管理的需求的话,建议引入一些设计模式或使用第三方框架。用户微信支付后,需要后台推送消息到服务器,才能确认支付成功。小程序的 DOM 操作只能查询属性,无法设置属性。小程序基础库版本与微信版本有关,基础库版本与客户端版本对应关系。小程序也存在兼容性问题,对待不愿更新微信的用户,要像对待忠实的IE6用户一样,小程序基础库版本分布。小程序页面只有 onLoad、onShow、onReady、onHide、onUnload 生命周期,没有更新视图相关的生命周期小程序不能直接渲染 HTML string,要用 rich-text 组件,但组件使用 HTML string 性能会有所下降。小程序有很多原生组件,如 Vedio、Map。原生组件位于最上层,会遮挡所有非原生组件,还存在诸多限制,如无法改变大小、无法添加动画效果等等。不过,有些组件在最新版本已经可以同层渲染了。小程序不支持摇一摇功能,但可以通过监听加速度传感器来实现。小程序有官方的广告组件,广告收入官方会抽走一部分。想到再更,欢迎补充.

April 1, 2019 · 1 min · jiezi

uni-app 引入自定义矢量图标(iconfont)

官网介绍:uni-app 是一个使用 Vue.js 开发跨平台应用的前端框架,开发者编写一套代码,可编译到iOS、Android、H5、小程序等多个平台。这个框架使用的人群并不是很广,碰到的各种坑基本都需要自己去解决,因此,入坑需谨慎!如何在uni-app中引入阿里的矢量图?上iconfont官网找到你需要用到的图标,添加至你的项目复制你的在线链接代码,建议使用这种方法,最便捷的一种方法,亲测!将这段代码拷贝至uni-app的app.vue文件下的style标签里面,因为uni-app项目中,app.vue下的style为公共样式,当然你也可以创建一个样式文件,将代码拷贝至你自定义的样式文件,最后还是要引入到app.vue的style标签下。“font-family"可以自定义为你想要的名字,我这里定义为’w-iconfont’自定义图标的大小、颜色等样式:.w-iconfont { font-family:“w-iconfont” !important; font-size:16px; color: orange; font-style:normal; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;}复制你要使用的图标的代码,在项目中使用它:<text class=“w-iconfont”>&#xe668;</text>效果如下:如果想增加新的图标项目怎么办?上官网找到新加的图标,同样添加到原来的项目里面;重复上面步骤,只需要点一下复制,然后打开app.vue,替换你刚复制的这部分代码即可:

March 31, 2019 · 1 min · jiezi

微信小程序——slot踩坑

今天在使用微信小程序 component 里的 slot 时发现,当只用一个 slot 并且将 slot 命名后,页面中调用这个 slot 并不会加载进来。研究尝试后发现,如果想要使用命名的方式调用单个 slot ,也需要像调用多个 slot 的方式 在 component/xxx.js 里开启多个 slot 的功能。下面看代码。// component<view class=‘slot’> <view>哈哈哈哈哈哈哈哈</view> <slot name=“after”></slot></view>// index 页面<d-slot> <!– 这部分内容将被放置在组件 <slot name=“after”> 的位置上 –> <view slot=“after”>这里是插入到组件slot name=“after"中的内容</view></d-slot>//结果,此时界面上不会载入 slot而当我把 slot 的name 删去时,slot 就能成功载入// component<view class=‘slot’> <view>哈哈哈哈哈哈哈哈</view> <slot></slot></view>// index 页面<d-slot> <!– 这部分内容将被放置在组件 <slot name=“after”> 的位置上 –> <view>这里是插入到组件slot name=“after"中的内容</view></d-slot>//结果,此时界面上载入 slot或者不删去 name 而是在组件js中声明启用// component.jsComponent({ options: { multipleSlots: true // 在组件定义时的选项中启用多slot支持 }, properties: { /* … / }, methods: { / … */ }})// component<view class=‘slot’> <view>哈哈哈哈哈哈哈哈</view> <slot name=“after”></slot></view>// index 页面<d-slot> <!– 这部分内容将被放置在组件 <slot name=“after”> 的位置上 –> <view slot=“after”>这里是插入到组件slot name=“after"中的内容</view></d-slot>//结果,此时界面上载入 slot ...

March 31, 2019 · 1 min · jiezi

小程序框架选择

一、小程序开发框架包括哪些wepy、mpvue、taro是目前最火的三个框架,分开介绍一下wepy:腾讯团队开源的一款类vue语法规范的小程序框架,借鉴了Vue的语法风格和功能特性,支持了Vue的诸多特征,比如父子组件、组件之间的通信、computed属性计算、wathcer监听器、props传值、slot槽分发,还有很多高级的特征支持:Mixin混合、拦截器等;WePY发布的第一个版本是2016年12月份,也就是小程序刚刚推出的时候,到目前为止,WePY已经发布了52个版本, 最新版本为1.7.2;mpvue:美团团队开源的一款使用 Vue.js 开发微信小程序的前端框架。使用此框架,开发者将得到完整的 Vue.js 开发体验,同时为 H5 和小程序提供了代码复用的能力。mpvue在发布后的几天间获得2.7k的star,上升速度飞起,截至目前为止已经有16.6k的star;taro京东凹凸实验室开源的一款使用 React.js 开发微信小程序的前端框架。它采用与 React 一致的组件化思想,组件生命周期与 React 保持一致,同时支持使用 JSX 语法,让代码具有更丰富的表现力,使用 Taro 进行开发可以获得和 React 一致的开发体验。,同时因为使用了react的原因所以除了能编译h5, 小程序外还可以编译为ReactNative;三框架对比表格三个框架目前都是相对生态完善且成熟的框架。各位开发者可根据自己的业务需要选择合适的框架使用。

March 31, 2019 · 1 min · jiezi

拓展微信小程序Component类型定义

引言和ColorUI一比,原生的导航栏简直是丑的没法看,为了不破坏框架的整体风格,我决定遵从框架的设计,也自定义导航栏。既然好多个页面都要用到,就考虑一下组件吧!原生组件原生的JavaScript组件长这样:Component({ /** * 组件的属性列表 / properties: { star: { type: Number, value: 0 } }, /* * 组件的初始数据 / data: { }, /* * 组件的方法列表 / methods: { init: function () { } }, attached: function() { this.init(); }});TypeScript组件想着使用TypeScript开始写组件,写个Component发现没有提示。咦?官方的TypeScript API里没有Component方法吗?找了一圈,也没找见。打开腾讯官方的小程序仓库,发现赫然一个大issue,1月19号提的,至今未解决。很好奇提issue的老哥最后是怎么解决的,不能官方库有bug,我就不写了吧?探究看Page源码定义Page:Page({})定义Component:Component({})通过观察,发现Component与Page两者类似,想着去看看Page是怎么定义类型的,我抄过来不就得了?.d.ts这是Page的类型声明文件,第一次点进去看,这是啥呀,啥也看不懂,一脸懵逼。最开始啥也不会,新建一个wx.extend.d.ts就开始抄代码,抄着抄着我发现我学会了。/* * 微信小程序扩展类型 组件TypeScript * @author zhangxishuo /declare namespace YunzhiComponent { /* * 组件实例对象 * Data: 组件内部属性规范 / interface ComponentInstance<Data extends IAnyObject> { /* * 组件对外属性 / properties?: object | Map<string, object>; /* * 组件内部数据 / data?: Data; /* * 组件内部方法 / methods?: object; } /* * 组件构造器 */ interface ComponentConstructor { <Data extends IAnyObject = {}, T extends IAnyObject & ComponentInstance<Data> = {}> ( options: ComponentInstance<Data> & T ): void }}declare const Component : YunzhiComponent.ComponentConstructor;总结之前也不知道.d.ts,现在写了之后,发现其实也没什么,这个文件就是写TypeScript会有代码提示,编译的时候提示提示类型,其实最终的功能,和.d.ts文件没啥关系。宝剑锋自磨砺出,梅花香自苦寒来。996.ICU要数当前最火的话题了,为什么要996呢?加班了,生产力一定提升吗?写代码是一个神奇的工作,同样一个功能,一个小时是它,三个小时也是它,如果你让他加班呢?他会怎么选呢?除非必要,永远不要加班,因为他们会把工作都留到晚上。程序员为什么不去多想想,为什么我要在这里加班?记住,世界是公平的。一句话,加班不推荐。但如果生产力低,不加班怎么办呢? ...

March 29, 2019 · 1 min · jiezi