关于微信小程序:微信小程序云开发环境搭建

https://www.jianshu.com/p/5df...

July 23, 2020 · 1 min · jiezi

关于微信小程序:微信小程序踩坑总结

一、41030: invalid page hint: [tFIkAa07161511]调用了小程序生成二维码的接口却报41030: invalid page hint: [tFIkAa07161511],查了一下起因发现了微信的限度: 1.传入page,生成指定页面的二维码必须要先把代码上传,提交审核并公布,而后在公布好的小程序里生成二维码的接口能力调用胜利,(体验版也不行,必须是公布下来的小程序,域名不能带端口号,真的好坑......) 2.传入的页面门路,pages后面不能加"/" 例如: 正确的写法:"pages/login/loign" 谬误的写法:"/pages/login/login" 3.小程序的参数不能超过32个字符 二、渠道起源统计小程序生成带参数的二维码的性能公布当天,咱们扫描二维码进行测试,却没有在微信后盾中看到相干的数据,就很奇怪,因为小程序后盾是能够统计带参数的二维码,最初在官网社区找到了问题的答案,小程序后盾的数据是在次日8:00-12:00更新,第二天数据的确更新了,依据须要,我又在小程序后盾配置了自定义事件,监听页面中指定的变量,emmmm......的确挺弱小,别弄那么多限度会更完满 三、小程序里应用webview标签跳转的H5页面链接前面不能携带参数在官网文档里阐明想要跳转内部链接就只能应用webview,然而webview竟然不容许链接前面携带参数。比方:https://xxx/xxx/xxx/#/xxx/xxx...你在小程序里跳转到这个页面,发现压根就拿不到跟在url前面的参数page和type,因为跳转过来之后参数没有了!!!没有了!!!没想到webview竟然对链接做解决,只有问号后面的局部,几乎吐血,就不能把链接残缺的给咱们吗?这太坑了,发现了这个问题后咱们只能长期写了一个截然不同的小程序页面,改成小程序的外部跳转 四、小程序图片展现1.应用<image/>标签 2.写在款式文件里: a.如果是本地图片,须要把图片转换成base64的格局; b.如果是服务器上的图片,间接应用图片链接,不须要转换成base64; 因为在款式文件里应用本地的图片url就必须把图片转成长长的base64的,太占空间,我就把图片全副上传到了服务器

July 23, 2020 · 1 min · jiezi

开源-微信育儿小程序-wechatbetababy-开源

一个基于微信的育儿小程序,开箱即用。 写在后面对于小程序的开发、部署、公布等相干问题请移步官网文档。征询问题的最好是产品自身。 外围性能宝宝模块 - 每个用户能够保护最多5个宝宝(超出的话,那要反思一下啦,哈哈)记录模块 - 用户能够记录每个宝宝的日常生活,如:吃、喝、拉、玩、学等关联宝宝 - 用户能够把宝宝分享给其它人并关联,关联后能够独特保护信息其中还包含登录、对于页面等。 部署阐明在部署前,你应该先理解小程序的申请、开发、公布流程,以及小程序的云开发性能。本文档不做介绍。 1.批改项目名称及 appid 配置下载代码后,开发者优先批改小程序的配置信息。你能够关上根目录下的 project.config.json 文件,批改 appid 和 项目名称。 { "appid": "your appid", "projectname": "your projectname"}2.应用小程序开发工具创立数据库目前小程序用到 4 个数据库汇合,开发者须要自行创立babies、posts、logs、relationship。 babies - 用于寄存宝宝数据posts - 用于寄存记录数据logs - 日志流水表relationship - 宝宝关联表3.批改数据库权限将所有数据库权限调整为所有用户可读,仅创建者可读写 4.创立 release 和 test 环境创立的时候要留神环境名称和 环境ID的区别,代码里用到的是环境ID,创立后不可批改。 release 和 test 是环境ID,不是环境名称!!!留神~~不可批改的哦。5.上传并部署云函数小程序云函数须要一个一个上传并部署,开发者能够一一上传。 在云函数上右键抉择『上传并部署』,不要上传本地 node_modules 文件6.批改云函数时区小程序云函数时区默认是 UTC+0,而北京工夫是UTC+8,须要针对每个云函数独自设置时区。 // 批改门路:云开发/云函数/版本治理/配置TZ = Asia/Shanghai小程序开发工具无奈批量批改,只能一一批改(很麻烦对吧)。7.公布你的小程序你认为就能公布了吗?并不能。因为微信审核太严格了,集体类型的小程序审核根本失败。 附录https://github.com/eyson/wech...

July 12, 2020 · 1 min · jiezi

给国企定制小程序这家云服务商-1-个月搞定

知晓云 高效、稳定的知晓云云服务 + 企业定制化服务,已成为各行业上云的首选。近期,知晓云帮助国企单位党支部顺利上线「智慧政企党建小程序」,为内部员工提供一个集「宣传、管理、教育、服务、沟通、考核」于一体的智能党建平台,打破组织内部信息壁垒、提高党务工作效率、促进党员学习与成长。党建小程序的发布,标志着该国企部门响应国家号召,顺应时代潮流,完成了数字化转型。 在过去的党务工作中,存在以下几个痛点: 没有线上交流平台,信息不对称,内部交流不足党务依赖传统的工作方式,效率低下,不智能党员教育方式和内容单一,缺乏学习积极性和教学检验 深入了解党务工作者在宣传、管理、教育各方面的复杂工作内容及工作流程,「智慧政企党建小程序」根据党务工作的实际应用场景,分为资讯、学习、工作、个人中心四个模块。群众可以及时了解最新资讯、参与组织活动,党员也可以在小程序上看到自己参与的活动与上级下达的任务。「智慧政企党建小程序」使得党务工作智能化,数据化,可追踪,可溯源,极大地提高了党建任务的落实效率。 「智慧政企党建小程序」是知晓程序团队基于旗下 serverless 服务——知晓云平台完成的又一个新的行业案例。知晓云从立项到小程序上线再到客户企业内部的大力推广使用,仅用了一个月,这得益于知晓云对小程序平台的深度定制化支持。 知晓云团队可以在梳理清楚需求及客户沟通确认执行方案后,迅速完成小程序搭建,并交由团队内的测试工程师进行灰度测试等多维度测试,保质保量按时交付。此前与默林集团合作,围绕「默林魔法游」构建的小程序矩阵、与教育部合作的各类校园导览小程序均使用知晓云进行独立开发。 △ 扫码体验「曼谷海洋世界」小程序 △ 扫码体验「参观北大」小程序 知晓云负责人表示: 不同行业之间的业务流程虽然千差万别,但是其核心功能逻辑基本上万变不离其中。知晓云作为云服务平台,致力于帮助企业在新型基础设施建设(简称:新基建)时代更好的完成上云的需求。我们提供了便捷易用的 SDK ,使得个人开发者可以使用知晓云又快又省的完成小程序开发,同时也提供了企业级定制服务,帮助各行各业完成小程序领域的战略布局。目前,知晓云已经帮助文旅、教育、电商、线下零售、社区、政务等领域的企业完成上云计划。未来,我们期待与各行业工作者一起探索新的「云作业」形态,在 5G 浪潮中寻找新的可能。

June 28, 2020 · 1 min · jiezi

小程序中的setData的使用

setData函数用于将数据从逻辑层发送到视图层(异步),同时改变对应的this.data的值(同步)。 直接修改 this.data 而不调用 this.setData 是无法改变页面的状态的,还会造成数据不一致。 单次设置的数据不能超过1024kB,请尽量避免一次设置过多的数据。 示例代码: index.wxml <view>{{name}}</view><button bindtap="changeName"> Change name data </button><view>{{num}}</view><button bindtap="changeNum"> Change normal num </button><view>{{array[0].text}}</view><button bindtap="changeItemInArray"> Change Array data </button><view>{{object.text}}</view><button bindtap="changeItemInObject"> Change Object data </button><view>{{newField.text}}</view><button bindtap="addNewField"> Add new data </button>index.js // demo.jsPage({ data: { name: 'jiqing', num: 0, array: [{text: 'init data'}], object: { text: 'init data' } }, changeName:function() { this.setData({ name:'zhangsan' }) console.log("点击了修改名称"); console.log(this.data); }, changeNum: function() { this.data.num = 1 this.setData({ num: this.data.num }) }, changeItemInArray: function() { // you can use this way to modify a danamic data path this.setData({ 'array[0].text':'changed data' }) }, changeItemInObject: function(){ this.setData({ 'object.text': 'changed data' }); }, addNewField: function() { this.setData({ 'newField.text': 'new data' }) } })这里的bindtap很有意思,绑定一个点击事件。 ...

June 16, 2020 · 1 min · jiezi

使用-React-DevTools-调试小程序是什么体验

当然,React DevTools 是没法用来直接调试小程序的。 但是利用 Remax 小程序框架,我们就可以做到利用 React DevTools 来调试了。 Remax 是一个基于真正 React 开发的小程序框架,https://remaxjs.org首先新建一个 Remax 项目(以阿里小程序为例): $ npx create-remax-app hello-remax$ cd hello-remax$ npm install安装 React DevTools 并启动: $ npm install react-devtools -g$ react-devtools使用小程序开发者工具打开 hello-remax 目录,等待小程序编译完成,就能在 React Devtools 进行调试啦。

June 16, 2020 · 1 min · jiezi

项目不同环境配置不同接口域名小程序入门与实战十二

上一章节,我们讲了小程序得模块化,怎么封装wx.request来发送请求。 这一章节我们讲的是开发项目过程中在开发环境,生产环境设置不同得请求接口域名。 新建 config.js在 src/es6 目录,新建一个config.js文件 export default { BRAND:{ name:'guojiangxiansir' }, GLOBAL: { baseUrl: process.env.NODE_ENV === 'development' ? 'https://guojiang.club/' : 'https://guojiang.club/' // 运行时自动替换变量 }, VERSION:'1.0.0'}我们在 config.js 文件定义了两个变量,一个是BRAND一个是GLOBAL process.env.NODE_ENV不懂什么意思的可以先 console.log(process.env.NODE_ENV)出来看一下,其实是你项目现在所处的环境,是为 development 开发环境,还是production 生产环境。 如果现在 process.env.NODE_ENV == 'development' 就是第一个域名,如果是生产环境就是第二个域名。 项目运行的命令: npm run dev //开发环境npm run build //生产环境想知道为什么的可以看package.json这两行代码: "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "webpack --watch --progress --colors --config webpack.dev.config.js", "build": "webpack --progress --hide-modules --config webpack.prod.config.js" },dev 运行的是 webpack.dev.config.js文件 ...

June 11, 2020 · 1 min · jiezi

前后台数据交互跟数据渲染小程序入门与实战九

4-3上一章节我们了解了小程序的页面使用 Page({}) 注册,数据 data,生命周期函数,事件处理函数都可以被接收。 先静后动,我们的首页已经是一个静态页面了,所以我们需要用数据来渲染首页。 wx.request 后台数据交互发送 HTTPS 网络请求。 wx.request({ url: 'https://guojiang.club/api/sir/card', //真实的接口地址 header: { 'content-type': 'application/json' // 默认值 }, data:{ //传入的数据为page,页数 page:1 } //HTTP 请求方法,默认值为get method:'GET', success (res) { // 接口调用成功,在这里就可以获取到数据 console.log(res.data) }, fail(rej){ //接口调用失败 console.log(rej.data) } })使用前说明在使用 wx.request 之前,我们需要注意以下两点: 服务器域名配置进入 https://mp.weixin.qq.com,输入账号密码登入在菜单栏找到 ”开发“-”开发者设置“点击”修改“按钮,在 ”request合法请求域名“ 添加,例如:https://guojiang.club 如果你的这个域名只是测试环境的域名,你并不打算拿来上线的,就需要你在微信开发者工具勾选 勾选完”不合法域名校验之后“,你可以看看你的调试基础库,是不是最新的,如果不是勾选使用人数最多的。 这些都做好之后,我们就可以在 index.js里写方法请求数据了。 代码实例分析// index.js 代码Page({//data 是页面第一次渲染使用的初始数据 data:{ //声明一个 cradList 变量,初始值为“[]”,一个空数组 cardList:[] }, onLoad(){ //调用getIndexCard()方法,this指向整个小程序实例 this.getIndexCard(1) }, //获取首页数据信息 getIndexCard(page){ wx.request({ url: 'https://guojiang.club/api/sir/card', //真实的接口地址 header: { 'content-type': 'application/json' // 默认值 }, data:{ //传入的数据为page,页数 page:page }, //HTTP 请求方法,默认值为get method:'GET', success:res=> { // 接口调用成功,在这里就可以获取到数据 res = res.data; if(res.status){ this.setData({ cardList:res.data }) } }, fail:(rej)=>{ //接口调用失败 console.log(rej.data) } }) }}) 我们上面已经已经写了 getIndexCard 这个方法,可以调用 https://guojiang.club/api/sir/card 这个接口,获取列表的数据。 ...

June 10, 2020 · 2 min · jiezi

数据分页跟小程序触底事件小程序入门与实战十

上一章节的知识真的是干货满满,学到了用 setData() 可以给数据赋值,可以使用 wx.request 发送 HTTPS 请求,使用{{}}绑定数据。 不知道大家发现没有,后端给我们的数据是分页的。 所以我们这章来学习小程序里数据分页应该怎么处理。 分页数据的处理Page({ data:{ cardList:[],//列表 page:1,//当前页数 has_more:true // 是否还能分页 }, onLoad(){ this.getIndexCard(1) }, //获取首页数据信息 getIndexCard(page){ wx.request({ url: 'https://guojiang.club/api/sir/card', //真实的接口地址 header: { 'content-type': 'application/json' // 默认值 }, data:{ //传入的数据为page,页数 page:1 }, //HTTP 请求方法,默认值为get method:'GET', success:res=>{ // 接口调用成功,在这里就可以获取到数据 console.log(res.data); res = res.data; if(res.status){ let pages = res.meta.pagination; //获取后台分页的分页数据 pagination let current_page = pages.current_page;//获取当前是那一页 let total_pages = pages.total_pages;//获取总页面数 //下面我们来赋值,这里会用到 es6 的模板字符串,有不懂得我们下面详细讲解 this.setData({ [`cardList[${page-1}]`]:res.data, page:current_page, has_more:current_page < total_pages }) } }, fail(rej){ //接口调用失败 console.log(rej.data) } }) }})我们在 data 里面声明了两个新变量 ...

June 10, 2020 · 2 min · jiezi

小程序模块化小程序入门与实战十一

上一章节我们讲了分页数据的处理, setData数据限制的解决办法,模板字符串以及触底分页获取数据。 那么这一章节我们学习小程序的模块化。 模块化可以将一些公共的代码抽离成为一个单独的js文件,作为一个模块。 模块只有通过 module.exports 或者 exports 才能对外暴露接口。通过 require方式引入 exports 是 module.exports 的一个引用,因此在模块里边随意更改 exports 的指向会造成未知的错误。所以更推荐开发者采用 module.exports 来暴露模块接口,除非你已经清晰知道这两者的关系。小程序目前不支持直接引入 node_modules , 开发者需要使用到 node_modules 时候建议拷贝出相关的代码到小程序的目录中,或者使用小程序支持的 npm 功能。同时小程序是支持 ES6 的 export 来暴露接口的,模块引入通过 import。 封装 wx.request在 src/es6目录下新建一个 sandBox.js 文件 export const sandBox = { get({api, data, header}){ return new Promise((resolve, reject) => { wx.request({ url:"https://guojiang.club/"+api, header:header, data:data, method:'GET', success:res => { resolve(res) }, fail:rej => { reject(rej) } }) }) }, post({api, data, header}){ return new Promise((resolve, reject) => { wx.request({ url:"https://guojiang.club/"+api, data:data, header:header, method:'POST', success:res => { resolve(res) }, fail:rej => { reject(rej) } }) }) }};或者第二种暴露模块的方式://module.exports.sandBox = sandBox//需要去掉 export在 src/es6 目录新建一个 myapp.js文件,主要用来放各个js模块。 ...

June 10, 2020 · 2 min · jiezi

页面配置与Page页面生命周期小程序入门与实战八

4-2在上一节,我们已经把 index.wxml 跟 index.wxss 写完了。 这一件我们来讲 index.json 页面配置跟 index.js与小程序 page 页面生命周期。 页面配置每一个小程序的页面也可以使用 .json 文件来对本页面的窗口表现进行配置。 请注意: 页面中的配置项会覆盖 app.json 的 window 中相同的配置项。 页面配置中只能设置 app.json 中 window 对应的配置项,以决定本页面的窗口表现,所以无需写 window 这个属性。# index.json{ <!--导航栏标题文字内容--> "navigationBarTitleText":"果酱先生"}我们这里的文案虽然是一样的,但是 navigationBarTitleText 还是覆盖了app.json里面的。 页面逻辑层使用 Page 构造器注册页面这也就是为什么我一开始强调 index.js 里面一定要写 Page({}) 不然会报错的原因。 # index.js 代码Page({<!----> data:{ }, onLoad(){ // 页面创建时执行 }, onShow(){ // 页面出现在前台时执行 }, onReady() { // 页面首次渲染完毕时执行 }, onHide() { // 页面从前台变为后台时执行 }, onUnload() { // 页面销毁时执行 } })我们先来讲解一下我们上面 Page({})构造函数出现的常用的属性。 ...

June 10, 2020 · 1 min · jiezi

小程序瀑布流组件支持翻页与图片懒加载

电商小程序中,用到瀑布流的地方非常多,每次都写一个瀑布流,重复一次逻辑,作为程序员,肯定是非常不愿意的。 瀑布流的形式都是大同小异,不同的是瀑布流中每个模块的内容,随业务而变化。 所以,我们把瀑布流框架抽象成组件,瀑布流的内容由业务确定。这样即可实现组件化和自定义的最大平衡,微信小程序组件源码。 首先,我们来看一下瀑布流组件在实际项目中的实际效果。 1 实际效果瀑布流组件实际效果如下图所示,左侧为用户交互效果,右侧为图片懒加载实际效果。 2 什么是瀑布流?瀑布流,又称瀑布流式布局。是比较流行的一种网站页面布局,waterfall-item宽度固定,高度不定,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部。如下图所示: 3 实现功能该瀑布流组件实现了以下几个功能: 支持图片懒加载支持上拉数据翻页支持自定义样式支持瀑布流Item间隔底层自动计算原生组件模式:即类swiper和swiper-item 组件用法组件与数据完全解耦4 实现原理4.1 waterfall 和waterfall-item实现原理第一步:在 waterfall-layout 目录下创建 waterfall 和 waterfall-item 组件,目录结构如下: .├── query-node.js├── waterfall-item.js├── waterfall-item.json├── waterfall-item.wxml├── waterfall-item.wxss├── waterfall.js├── waterfall.json├── waterfall.wxml└── waterfall.wxss第二步:分别在waterfall.js 和 waterfall-item.js的relations选项中指定组件父、子级关系: // waterfall.jsComponent({ // ... other code relations: { './waterfall-item': { type: 'child', }, // ... other code }})// waterfall-item.jsComponent({ // ... other code relations: { '././waterfall': { type: 'parent', }, // ... other code }})指定彼此的父、子组件的关系后,即可通过 this.getRelationNodes 原生 API,就能访问彼此实例对象及其属性和方法。 ...

June 9, 2020 · 3 min · jiezi

首页布局跟小程序如何配置Iconfont小程序入门与实战七

4-1经过上一章节的学习我们已经搭建了项目的整个框架,雏形已成。接下来我们只需要的往里面堆东西就可以了。 设计稿网址(14天分享有效,过期的可以找我拿):https://lanhuapp.com/url/Airvn密码: I4DA分析首页设计稿写代码一定要注意细节和结构性,拿到设计图首先分析应该怎么做,应该有哪些模块,哪些模块可以通用,一定要经过设计之后再动手去写。 从设计稿可以看出,图片是通屏的。经过与设计师沟通,而且还是轮播图,上下滑动的。上面有“HOT” 跟 “衣品圈” 两个Tab切换 。 下面是 Tabbar 标签栏,有“打卡”、“+”、“我”共 3 个标签,分别去到不同的页面。 右边有“头像”、“点赞”、“分享”。 通屏轮播图给大家介绍两个微信小程序官方组件。 view:视图容器,相当于div。swiper: 滑动视图容器。其中只可以放置swiper-item组件,常用来放轮播图。image:用来放图片的组件。下面我们用这两个组件来写通屏轮播图 # index.wxml 代码<!--一个大盒子包住所有的元素--><view class="container-fill"><!--包住 swiper 组件--> <view class="scroll-fullpage" style="height: 100%"> <!--swiper组件用法,里面只能放swiper-item组件,我们项目中需要的轮播图上下滑动,所以设置 vertical="true" 代表滑动方向为纵向。--> <swiper circular="true" vertical="true" style="height: 100%"> <!--放了两个 swiper-item,相当于有两个子项,滑两下 --> <!--第一个子项--> <swiper-item> <!--swiper-item 组件里面可以放任何的东西,我们这里放了图片--> <!--src代表图片的url,mode为图片的裁剪,缩放的模式,aspectFill保持纵横比缩放图片--> <image mode="aspectFill" src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1590745760463&di=50d76742c6cb334acdac656a930c52e7&imgtype=0&src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fitem%2F201909%2F27%2F20190927092410_yyrsn.thumb.400_0.jpg" class="slide-image"> </image> </swiper-item> <!--第二个子项--> <swiper-item> <image mode="aspectFill" src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1590747427893&di=9fa9371dfd6f8ffcd062b18eeff58ec5&imgtype=0&src=http%3A%2F%2Fpic1.win4000.com%2Fmobile%2F2019-09-11%2F5d789c0b24214_200_300.jpg" class="slide-image"> </image> </swiper-item> </swiper> </view></view>代码分析大白话(注释里面也挺详细的):view相当于 div ,是一个容器,不可以滑动。swiper是一个可以滑动的的容器,vertical = "true" 表示滑动方向为纵向,circular="true" 表示采用衔接滑动,如果不理解衔接滑动可以把这个属性先去掉,然后体验一下区别。swiper-item 是swiper 的滑块,如果加入滑动内容,那么就在swiper-item中添加,宽高自动设置为 100% 。image组件放在swiper-item 中,其中的mode属性最常用的是widthFix,表示图片宽度100%,高度自适应。我觉得有点像背景图的感觉。上面是 wxml的代码,接下来是样式。 # index.less代码<!--将大盒子通屏,这个方法请记住用固定定位的方法通屏。不会出现各个机型有白边的情况不熟悉less的同学,就去百度看一下。其实就是层层嵌套的感觉。其实这里的选择器,例如:.container-fill { .scroll-fullpage{ }}就相当于css的:.container-fill .scroll-fullpage{ }-->.container-fill{ position: fixed; top: 0; bottom: 0; left:0; right:0; overflow: hidden; z-index: 10; .scroll-fullpage { height: 100%; transition: all 0.3s; swiper { height: 100%; image { width: 100%; } } }}Tab 栏切换“HOT” | “衣品圈”Tab 栏 肯定是不属于可以滑动的轮播图那一块的。所以我们需要将 Tab 栏放在 swiper 外面,需要跟 swiper 同级。 ...

June 6, 2020 · 3 min · jiezi

微信小程序文本换行

Git项目地址 扫码体验Demo小程序 一、描述 小程序经常需要将服务器传回的数据进行换行,传回的数据经常用 \n 或 <br /> 分隔数据,小程序.wxml文件会将返回数据中的 \n 处理成字符串n, 不能得到我们想要的换行结果。所以我们需要将数据进行特殊处理。 二、解决办法 将<view>标签换成<text>标签<view class="page"> <view class="page__hd"> <text class="page__desc">{{tools.replaceLine(question.question)}}</text> </view></view>添加wxs模块(/miniprogram/tools/tools.wxs)使用replace替换n和<br/>, 匹配\n需要使用\\\\4个斜杠,因为\\匹配一个\;传入的参数需要判空,若传入的参数为空replace会报错var replaceBr = function (val) { return val ? val.replace(getRegExp("<br />", "g"), "\n") : val}var replaceLine = function (val) { return val ? val.replace(getRegExp("\\\\n", "g"), "\n") : val}module.exports.replaceBr = replaceBrmodule.exports.replaceLine = replaceLine在.wxml文件引入创建的wxs模块,并调用指定的函数<wxs src="../../tools/tools.wxs" module="tools" /><view class="page"> <view class="page__hd"> <text class="page__desc">{{tools.replaceLine(question.question)}}</text> </view></view>三、结果 { "question":"(1)小张迟到两小时 \n (2)一女同志骑车摔倒被人送往医院 \n (3)小张的奖金未被扣除还得到奖励 \n (4)办公室规定迟到扣半月奖金 \n (5)小张上班后说自己去修了一下车 \n 请按逻辑排序", "option":[{"key":"A","value":"1-5-4-2-3"},{"key":"B","value":"4-2-1-5-3"},{"key":"C","value":"2-1-4-5-3"},{"key":"D","value":"4-1-2-3-5"}], "answer":"D","analysis":"无", "status":"1", "position":106, "create_at":"2020-06-05 16:46:36", "update_at":"2020-06-05 16:46:36"}! ...

June 5, 2020 · 1 min · jiezi

GitHub-Actions和mpci助力微信小程序持续集成

使用GitHub Actions、mp-ci为Taro项目添加持续集成,让开发飞上天。 mp-cimp-ci是微信小程序(游戏)发布助手, 支持预览和上传。可以直接接入开发流程中,提高研发效率。 基于官方miniprogram-ci封装,比它的老大哥 mini-deploy 好了很多倍,再也不需要安装开发者工具,也不用考虑登录、操作系统的问题。 自动读取appid、setting上传信息(版本和备注)自动生成美化执行结果更多说明直接访问 mp-ci。 准备工作下载私钥使用前需要使用小程序管理员身份访问"微信公众平台-开发-开发设置"后下载代码上传密钥,并配置 IP 白名单。 这里需要关闭IP白名单,因为无法确定GitHub服务器的IP范围。 设置私钥到GitHubmp-ci是通过文件形式接受私钥的,但是把私钥直接放到GitHub上显然是不安全的。 这里我们使用GitHub的Secrets来存储私钥内容,然后在执行时再创建私钥文件。 打开仓库的Settings/Secrets页面设置接口,假设我们存储的名字是UPLOAD_PRIVATE_KEY。 GitHub Actions 配置新建.github/workflows/build.yaml文件。 也可以在Actions一栏,选择Node.js或者set up a workflow yourself。 使用以下内容填充: name: MP CIon: push: branches: [ master ] pull_request: branches: [ master ]jobs: build: runs-on: ubuntu-latest strategy: matrix: node-version: [10.x] steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} - name: Install Dependencies run: npm i - name: Build weapp run: npm run build:weapp # 从 secrets.UPLOAD_PRIVATE_KEY 生成私钥文件 # see Project/Settings/Secrets - name: Generate private key for upload run: echo "$UPLOAD_PRIVATE_KEY" > private.key env: UPLOAD_PRIVATE_KEY: ${{ secrets.UPLOAD_PRIVATE_KEY }} # 上传代码 - name: Upload to WeChat run: npx mp-ci upload ./ --pkp=./private.key --no-test结果 ...

June 5, 2020 · 1 min · jiezi

小程序生命周期跟全局样式小程序入门与实战六

上一章节我们构建了小程序的第一个页面。 3-6 app.js每个小程序都需要在 app.js 中调用 App 方法注册一个小程序实例。 用白话说就是,你不注册它,你就不能拥有一个小程序。 废话不多说,直接上代码。 //app.jsApp({ onLaunch (options) { // 可以写代码 }, onShow (options) { // 可以写代码 }, onHide () { // 可以写代码 }})App(Object object)注册小程序。接收一个 object 参数,来指定小程序的生命周期回调、全局任意函数、全局数据变量等。 onLaunch()小程序初始化完成时触发,全局只触发一次。 onShow() 小程序启动,或从后台进入前台显示时触发。 onHide()小程序从前台进入后台时触发。 3-7 app.wxss小程序公共样式表 定义在 app.wxss 中的样式为全局样式,作用于每一个页面。在 page 的 wxss 文件中定义的样式为局部样式,只作用在对应的页面,并会覆盖 app.wxss 中相同的选择器。 跟 CSS 相比,WXSS 扩展了两个特性。 尺寸单位 rpxrpx : 可以根据屏幕宽度进行自适应。规定屏幕宽为 750rpx 。 设备rpx换算px (屏幕宽度/750)iPhone51rpx = 0.42pxiPhone61rpx = 0.5pxiPhone6 Plus1rpx = 0.552px所以在开发小程序时,我们的设计稿都是用 iPhone6 作为视觉稿的。 ...

June 5, 2020 · 1 min · jiezi

配置小程序项目的第一个页面小程序入门与实战五

上一小节我们虽然构建了项目的目录,也配置了几个必要文件,但是我们的项目还是不能编译起来,我们还需要完善app.json、app.js、app.wxss这3个文件跟之前我们说的src/pages/index文件夹。 3-4 新建第一个页面有人会疑惑,为什么配置app.json之前需要新建第一个页面,你们忘记了吗?app.json里面有一个pages属性,是必选项。 pages数组事页面路径列表。 配置编辑器 less 自动 编译成 wxss因为我们是用 less 开发通过编辑器自动编译成 wxss,所以我们需要对编辑器进行一些配置。 下面介绍 Webstorm 跟 VScode 这两种常用编辑器的配置。 webstorm 菜单栏 “File” > “Settings” > “Editor” > “File Types”将 HTML 添加一项 .wxml 将 CSS 添加一项 .wxss 菜单栏 “File” > “Settings” > “Tools” VScode 从 VScode 商店中下载 Easy LESS 插件。配置 settings.json 文件 (文件 - 首选项 - 设置 - 搜索设置 settings.json ),加入如下代码:"less.compile": { "outExt": ".wxss" }在 index 文件夹里新建 4 个文件来搭建第一个页面新建后缀名为 .json 的文件,不能为空。 ...

June 4, 2020 · 1 min · jiezi

搭建项目框架小程序入门与实战四

上一小节,我们学习了小程序的代码构成。接下来我们就可以学习来搭果酱先生这个项目的脚手架。 之所以要自己搭建脚手架,是为了让 Webstorm 或者 VScode 可以实时编译小程序代码,提高开发效率。 3-2 项目脚手架搭建果酱先生是使用 webpack,bable,less 开发的微信小程序项目,如果你还是新手不了解这些也没有关系,你只需要按照步骤一步步来也可以搭建好的。 在搭建之前,你需要先安装以下应用程序即可: Node.js (版本需不低于 8.10,建议使用 Node.js 10.0 及以上版本)Git如果你的电脑中尚未安装所需要的程序,请根据以下安装指示完成安装。 安装 Node.jsNode.js 先前版本下载地址:https://nodejs.org/en/downloa... 注意:下载版本建议为 10.X 版本安装完成之后,打开命令提示符输入命令: # 查看 Node.js 版本node -vv10.20.1安装 GitWindows:下载并安装 下载地址:https://git-scm.com/download/winMac: 下载地址:https://sourceforge.net/projects/git-osx-installer/Mac 用户如果在编译时遇到问题,需要先到 App Store 安装 Xcode,Xcode 完成后,启动并进入 Preferences -> Download -> Command Line Tools -> Install 安装命令行工具。 全局安装 LessLess 是一门 CSS 预处理语言,让 CSS 更易维护、方便制作主题、扩充。 如果你觉得你是新手,没有接触过 Less,也不用害怕,你先安装就是的,在后面的项目中,我会手把教你的,很简单。 打开命令提示符,输入命令: npm install -g less初始化项目在 E盘 新建一个项目文件(如:mini-sir-wechat ) 然后右键 Git Bash Here ,输入命令 ...

June 3, 2020 · 2 min · jiezi

小程序环境搭建小程序入门与实战二

在学习这个小程序项目之前,黔在在碎碎念,光看不做是虚架子,你需要的是在电脑面前跟着我一步一步的实践,带你从 0 开始构建果酱先生这个项目。 2-1 申请 AppId开发小程序的第一步。 AppId 是什么我们每个人都有属于自己得身份证,AppId 就是小程序在小程序平台的身份证。也就是说,一个 AppId 只能对应一个小程序。 步骤先注册一个属于自己的小程序账号。# 网址https://mp.weixin.qq.com/wxopen/waregister?action=step1注意:每个邮箱仅能申请一个小程序,请根据申请账号的流程进行申请,申请完成之后,请务必记住自己的邮箱跟密码。 登录小程序管理平台,使用你刚刚注册的邮箱跟密码。# 网址https://mp.weixin.qq.com/点击菜单栏 “开发” - “开发设施”,就可以看到这个小程序的 AppId 了。 点击 “生成” 按钮之后,你需要记录你的小程序秘钥,因为小程序秘钥只展示一次。 2-2 下载并安装开发者工具在上一节的学习中我们已经有了 AppId 了。 为了高效的开发和调试微信小程序,我们需要安装微信开发者工具。 # 网址https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html根据电脑系统下载相对应的版本 下载安装完成之后,打开微信开发者工具,使用注册小程序账号的时候绑定的管理员微信扫码登录。 项目名称 —— 如 HelloWorld目录 —— 选择你要将这个项目放在那里AppId —— 填写我们上面申请的 AppId点击“新建”,这样我们就快速构建了一个项目名称为 HelloWorld的小程序。 总结注册的小程序账号用来登录微信后台,管理小程序的发版、成员等。AppId 跟小程序秘钥必须记录下来。每一个账号对应一个小程序,也就是说 AppId 跟 小程序一一对应。微信开发者工具是开发小程序项目的必备调试工具。 本文由博客群发一文多发等运营工具平台 OpenWrite 发布

June 2, 2020 · 1 min · jiezi

小程序的代码构成讲解小程序入门与实战三

上一章节我们已经知道如何申请小程序的AppId,并且也安装了微信开发者工具。接下来我们需要了解小程序的代码构成。 3-1 官方种子项目与小程序代码构成在上一章节我们已经利用微信开发者工具快速构建了一个名称为 HelloWorld的 小程序项目,可以借这个项目来看看。 点击菜单栏 “编辑器” ,就可以看到这个小程序的代码构成了了。 可以看出构建小程序项目,根目录下必须要有 app.js,app.json,app.wxss 这3个文件。 pages 目录是用于存放页面,每个页面就是一个文件夹,分别由.json、.wxml、 .wxss、.js 文件构成。 utils 目录主要用于存放各种工具类,全局方法等。 JSON 配置项目的根目录app.json,是小程序的全局配置。 也就是说,小程序的所有页面路径、所有界面表现、底部tab等都在这里面统一配置。 { "pages":[ "pages/index/index", "pages/logs/logs" ], "window":{ "backgroundTextStyle":"light", "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "WeChat", "navigationBarTextStyle":"black" }, "style": "v2", "sitemapLocation": "sitemap.json"}我给大家讲一下这个配置各个项的含义: pages 字段 指定小程序由哪些页面组成,每一项都对应一个页面的路径信息。文件名不需要写文件后缀,框架会自动去寻找对应位置的 .json, .js, .wxml, .wxss 四个文件进行处理。也就是说,你的小程序新增或者减少页面,都需要对pages数组进行修改 window 字段 用于设置小程序的状态栏、导航条、标题、窗口背景色。 别急,如果你不是很理解的话,我们后面会在项目中详细的讲。 WXML 模板WXML 相当于 HTML 的角色,用来描述当前页面的结构。 小程序给我们包装好了有基本能力的标签,还提供了地图、视频、音频等组件能力。 常用的有 view 、button 、text 等。相当于 HTML 中的 div、button、span。 项目中会详细讲解。 WXSS 样式WXSS 具有 CSS 大部分的特性,跟 CSS 一样用来描述页面的样子。 ...

June 2, 2020 · 1 min · jiezi

微信小程序-绝对路径-require

https://segmentfault.com/a/11...之前参照上面文章 可以实现绝对路径的引入 但是在vscode中 require函数无法自动提示路径 并且require的模块也不能自动提示 为了解决这个问题 1.根目录建立 jsconfig.json 文件 { "compilerOptions": { "target": "ES6", "baseUrl": ".", "paths": { "/*": ["./*"] } }}2.在使用 require 函数的js文件 最前面加上 const app = getApp();(function () { require = app.require; })();3.使用 const CommonApi = require("/api/common");CommonApi.CallApi1(); //可以自动提示出方法 可配合d.ts食用

May 28, 2020 · 1 min · jiezi

微信小程序踩坑指南渠道来源统计

小程序生成带参数的二维码的功能发布当天,我们扫描二维码进行测试,却没有在微信后台中看到相关的数据,就很奇怪,因为小程序后台是可以统计带参数的二维码,最后在官方社区找到了问题的答案,小程序后台的数据是在次日8:00-12:00更新,第二天数据确实更新了,根据需要,我又在小程序后台配置了自定义事件,监听页面中指定的变量,emmmm......确实挺强大,别弄那么多限制会更完美

May 27, 2020 · 1 min · jiezi

小程序-setData-修改-data-中数组内不定对象的数据

小程序 setData 修改 data 中数组内不定对象的数据 普通变量的 setData()在某些时候,我们的小程序中存在的不只是像下面这样的简单的变量: 变量值这种形式 data: { name: 'Kyle', age: 28, mail: 'kylebing@163.com'}这种形式的数据,在需要修改的时候,只需要如下形式修改就可以了 this.setData({ name: 'Tina' })数组内部的 setData()有时候,里面会有对象数组,需要修改数组内部的变量,如下面的 people 数组: people: [ { name: 'Kyle', age: 24, products: [ {name: 'iPhone', price: 4550}, {name: 'AirPods Pro', price: 1999}, ] }, { name: 'Tina', age: 26, products: [ {name: 'Dell P2415Q', price: 1800}, {name: 'Macbook Pro', price: 8500}, ] }]像这种改变数组内部属性的值,需要不同于普通变量的 setData(),格式如下:方括号里接收的是字符串 this.setData({ [ 定位数据的字符串 ]: 数据})如: 修改 Kyle 的 age ...

November 4, 2019 · 1 min · jiezi

微信小程序授权登录取消授权重新授权处理方法-附可用代码

微信小程序授权登录基本是小程序的标配了,但是官方的demo,取消授权后,就不能再重新点击登录,除非重新加载小程序才可以,这下怎么办? 我们可以先在首页引导用户点击,然后跳转到一个新的页面,在新的页面进行授权,然后新的页面授权成功,立马跳回首页,显示用户信息。 话不多说,直接上代码代码结构: index是首页login是授权页 首页代码index.wxml <!-- 未授权,只显示一个授权按钮 --><view wx:if="{{result==false}}"> <button bindtap="getinfo" class="loginbtn"> 授权登录 </button></view><!-- 授权后只显示头像和昵称 --><view elif="{{result==true}}" class="info"> <image src="{{head}}" class="headimg"></image> <text class="nickname">{{name}}</text></view>index.wxss /**index.wxss**/.loginbtn{ width: 150px; height: 45px; background: #06C05F; margin:100px auto 0; line-height: 45px; font-size: 15px; color: #fff;}.info{ width: 80px; height: 100px; margin:50px auto 0;}.info .headimg{ width: 80px; height: 80px; border-radius: 100%;}.info .nickname{ text-align: center;}index.js //index.jsPage({ data: { userInfo: {}, hasUserInfo: false }, //事件处理函数 getinfo: function () { wx.navigateTo({ url: '../login/index' }) }, onLoad: function (e) { let that = this; // 获取用户信息 wx.getSetting({ success(res) { // console.log("res", res) if (res.authSetting['scope.userInfo']) { console.log("已授权") // 已经授权,可以直接调用 getUserInfo 获取头像昵称 wx.getUserInfo({ success(res) { console.log("获取用户信息成功", res) that.setData({ name: res.userInfo.nickName, head: res.userInfo.avatarUrl, result: true }) }, fail(res) { console.log("获取用户信息失败", res) that.setData({ result: "取消授权" }) } }) } else { console.log("未授权") that.setData({ result: false }) } } }) }})授权页代码index.wxml ...

October 17, 2019 · 1 min · jiezi

你期待的微信小程序表格组件来咯

背景在做H5开发中表格table是最常见的标签,如此好用的标签在微信小程序中却没有,无奈,叹息,绝望!!! 奔着利国利猿的使命,我*开始了造轮之路。 功能主要用于展示大量结构化数据。 支持分页,自定义操作,长表格宽表格滚动等功能。 实现前言 暴露必要属性例如表头,数据。支持外部样式控制表格。手机端的列表较轻暂时不需要暴露事件。细节 通过properties暴露了三个属性官方说明 Component({ properties: { list: { // 表格数据 type: Array, value: [] }, headers: { //表头 type: Array, value: [] }, hasBorder: { // 表格中间边框 type: String, value: "no" }, height: { //table的高度 type: Number || String, value: '' }, width: { type: Number, value: 0 }, tdWidth: { type: Number, value: 35 } }})通过externalClasses支持外部样式官方说明 /*s-class-header // 外部定义表头样式s-class-row // 外部定义行数据样式*/Component({ externalClasses: ['s-class-header', 's-class-row']})index.wxml文件通过嵌套循环动态渲染表格<view class="table table-noborder"> <view class="tr thead s-class-header"> <view wx:for="{{headers}}" class="td td-{{hasBorder}}border">{{item.display}}</view> </view> <block wx:for-item='i' wx:for="{{list}}"> <view class="tr s-class-row"> <view wx:for-item='j' wx:for="{{headers}}" class="td td-{{hasBorder}}border">{{i[j['text']]}}</view> </view> </block> </view>index.wxss 使用者对于很个性的样式可以自行修改源代码index.wxss文件.table { border: 1px solid #ccc; font-size: 28rpx; background: #fff; border-right:none;}.table-noborder { border-right:1rpx solid #ccc;} .tr{ display: flex;} .td { text-align: center; border: 1px solid #ccc; display: inline-block; border-bottom: none; flex: 1; padding: 16rpx; border-left: none;}.td-noborder{ border-right: none;} .thead .td{ border-top: none; padding: 16rpx; font-weight: bold;}#### 快速上手 ...

October 16, 2019 · 1 min · jiezi

基于微信小程序云开发实现的婚礼邀请函模板可以自行定制开发

这个婚礼邀请函是之前帮别人做的,现在人家婚礼举办过了也没啥关系了,想着就修改成通用模板进行开源,方便大家尤其是小白们克隆项目之后稍微修改就能够直接使用。 当时自己开始这个项目时候也是查阅了很多教程文章,但无一列外都需要大量的小程序开发知识储备,对于当时需要快速构建一个项目的我来说真的焦急,很希望有一个可以直接使用的模板,项目完成后有深入的想法可以再学习。 扫码体验 项目展示(多图警告)首页 照片页 地图页 祝福页 留言页 项目下载https://github.com/Zuowendong/wechat-invitation 项目部署项目目录下执行 npm install进入项目执行 npm run dev在微信开发者工具中预览代码详解代码也没啥好解释的,会看的就自己看了。不愿意看的详解了也没啥意义,想要学习的话还是需要前期准备相关知识储备:mpvue,小程序开发,小程序云开发。看官方的开发文档就可以了。 定制开发AppID(小程序ID)修改成自己的main.js中初始云开发环境名修改成自己的service文件中云开发config修改成自己的云开发环境名首页的婚宴举办信息、音乐资源的引用地址的修改首页和照片页的图片资源引用 ,都在封装的组件 indexSwiper.vue、swiper.vue中地图页的导航经纬度和新人电话号码的修改消息页的祝福视频资源引用首页和祝福页的两个转发按钮自定义信息的修改关注我吧关注「前端一起学」公众号 ,看着项目进阶学习,让我们一起学前端,一起进步。

October 14, 2019 · 1 min · jiezi

uniapp开发一个小视频应用三

一、前情回顾uni-app开发一个小视频应用(一) uni-app开发一个小视频应用(二) 二、创建城市页面首页导航栏上有一个城市选择页面,点击会切换到城市页面,切换到城市页面的过程中并没有路由的跳转,而只是tab的切换,所以需要将城市页面设置为tabBar页面,即将城市页面添加到tabBar的list数组中。// components/city/city.vue <template> <view class="city"> <!--城市页面和首页是共用一个导航的tabBar的--> <index-header></index-header> <tab-bar></tab-bar> </view></template><style scoped> .city { <!--城市页面全屏显示,并且背景为黑色--> width: 100%; height: 100%; background: #000000; }</style>三、创建位置组件城市页面中需要显示当前所在城市定位信息以及城市切换按钮,即分为左右两部分,这里有一个问题,就是将位置组件加到城市页面中后,由于头部导航采用固定定位脱离文档流了,而位置组件需要放到头部导航栏的下发,所以需要给位置组件设置一个margin-top,但是由于其父元素即城市页面没有设置边框,会有外边距溢出的问题,即位置组件设置的外边距会转移到城市页面上,导致整个城市页面会有一个margin-top,要解决这个问题有多种方式,主要就是对父元素(城市页面)进行设置: 第一种就是给父元素加一个边框,这种会改变父元素布局,显然不合适,第二种是给父元素添加over-flow:hidden;对溢出部分进行隐藏,第三种是通过css为类在父元素中添加一个table元素,如:// components/location.vue <template> <view class="location"> <view class="iconfont icon-dingwei location-left"> &nbsp;自动定位: 上海 </view> <view class="location-right"> 切换 <text class="iconfont icon-dayuhao dayuhao"></text> </view> </view></template><style> .location { width: 100%; height: 40px; color: #aaaaaa; margin-top: 60px; overflow: hidden; display: flex; } .location-left { text-align: center; margin-left: 20px; height: 40px; line-height: 40px; font-size: 12px; } .location-right { flex: 1; text-align: right; padding-right: 20px; height: 40px; line-height: 40px; font-size: 12px; } .dayuhao { font-size: 12px; }</style>// pages/city/city.vue ...

October 5, 2019 · 2 min · jiezi

uniapp开发一个小视频应用二

一、前情回顾uni-app开发一个小视频应用(一) 上篇文章,我们已经实现了首页的头部导航栏组件、底部的tabBar导航栏组件、中间的视频列表组件以及视频列表组件中的视频播放组件,传入视频列表渲染后已经可以上下滑动进行视频切换和播放,接下来我们将完成首页的剩余部分,左侧信息栏组件、右侧图标栏组件,以及完善视频切换动画、播放控制等功能。二、创建左侧信息栏组件左侧的信息栏组件,主要分三块: 作者名、视频标题名、音乐名。这个左侧信息栏信息是和当前播放视频相关联的,所以应该在循环视频列表的时候,将左侧信息栏组件一起渲染出来,所以左侧信息栏组件应该加到<swiper-item>中。// components/list-left.vue <template> <view class="list-left"> <view class="author"> @祝晓晗 </view> <view class="title"> 妈呀,遇到老同学了,缘分呐! @老丈人说车 @抖音小助手 </view> <view class="music-box"> <!--该music-box主要是为了在music内容滚动的时候在超出music-box范围后能够隐藏超出部分--> <view class="music"> @祝晓晗创作的原声 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @祝晓晗创作的原声 </view> </view> </view></template><style scoped> .list-left{ width: 70%; height: 120px; color: white; } .author { height: 35px; line-height: 35px; font-size: 17px; } .title { width: 100%; line-height: 25px; font-size: 12px; word-wrap: break-word; color: #FFFAF0; } .music-box { overflow: hidden; <!--滚动的时候超出部分隐藏--> width: 70%; } .music { width: 200%; height: 35px; line-height: 35px; font-size: 12px; animation: scroll-x 5s linear 0.2s infinite; <!--应用动画--> } @keyframes scroll-x{ <!--添加文字水平滚动动画--> 0% { transform: translate3d(80%, 0, 0); <!--80%位置出现,然后向左边滚动--> } 100% { transform: translate3d(-80%, 0, 0); <!--动画结束后到达-80%位置--> } }</style>// components/video-list.vue ...

October 1, 2019 · 4 min · jiezi

微信小程序模板函数

微信小程序的视图模板的{{}} 方法并不支持直接调用js函数,比如 {{ (new Date()).toLocaleString() }}是无法编译成我们期望的结果的。 我们需要将js函数封装至wxs模块,然后便可以调用 # utils/date.wxsconst date = { now: function() { return (new Date()).toLocaleString() }}module.export = date# pages/date/date.wxml<wxs module="date" src="../../utils/date.wxs"></wxs><view>{{ date.now() }}</view>即刻。

September 8, 2019 · 1 min · jiezi

小程序自适应canvas

wxml <canvas style="width: 686rpx;height: 686rpx;background:#f1f1f1;" canvas-id="qrcCanvas"/><input value='{{qrcStr}}' bindblur="onQrcStrBlur" type="text" maxlength="255" />js data:{ qrStr:'xxx' 需要生成字段 canvasId: "qrcCanvas",//需要绘画的元素 } //适配不同屏幕大小的canvas setCanvasSize(){ var size={}; try { var res = wx.getSystemInfoSync(); var scale = 750/686;//不同屏幕下canvas的适配比例;设计稿是750宽 var width = res.windowWidth/scale; var height = width;//canvas画布为正方形 size.w = width; size.h = height; } catch (e) { // Do something when catch error console.log("获取设备信息失败"+e); } return size; //返回大小 } , createQrCode(str,canvasId,cavW,cavH){ //调用插件中的draw方法,绘制二维码图片 qrCode.api.draw(str,canvasId,cavW,cavH); }, //获取input输入的值 onQrcStrBlur(e) { this.setData({qrcStr: e.detail.value}); }, //在 onReady调用 onReady: function() { let size = this.setCanvasSize();//动态设置画布大小 this.createQrCode(this.data.qrcStr, this.canvasId, size.w, size.h); },

August 27, 2019 · 1 min · jiezi

小程序实时音视频实践

微信小程序成为当下热门话题,下面从多个方面来谈谈小程序直播功能开发过程详解 。 2017年下半年,微信6.5.21版本支持在线音视频功能。开发者可以通过两个音视频组件 <live-pusher> 和 <live-player> 实现实时地在线直播、视频通话、语音通话等功能。 本期小程序课,微信开发哥将详细为大家介绍一下音视频组件在线直播和视频通话这两个应用场景。 在线直播该怎么做? 在线直播的应用场景有哪些? 在游戏直播、远程授课、以及企业内部的培训分享等场景中,都可能会用到在线直播功能,直播的应用场景可以遍及各行各业。 比如微信电竞是一款游戏直播产品,以小程序为产品呈现方式。 比如在医疗行业,专家医师往往需要全国各地飞进行学术交流和培训,出差本身耽误了医生大量时间,在线远程授课能大大减少这里的时间耗用。 小程序中的 <live-pusher> 和 <live-player> 两个组件 ,都有一个叫做live ( <live-pusher> 中对应 mode 属性为 SD, HD, FHD)的模式,专门为在线直播而设计,通过小程序的音视频接口的live 模式,可以实现上述应用场景。 02在线直播的内部原理是什么? 主播端使用 <live-pusher> ,它在小程序的内部是一个推流引擎,它负责对手机摄像头和麦克风的数据进行采集和编码,并通过 url 参数指定的 rtmp 推流地址上传到云端。 云端的作用类似信号放大器,它负责将来自主播端的一路音视频流数据进行放大,将数据实时并且无差异的负责并扩散到全国各地,从而解决主播和观众端之间距离太远(比如,跨地区和跨运营商)的问题。 观众端使用 <live-player> 进行播放,它在小程序的内部是一个在线播放器,负责从云端实时拉取音视频数据并进行解码和渲染。由于云端的放大效应,每一个观众都能在离自己比较近的云服务器上拉取到实时且流畅的音视频流。   下面从多个方面来谈谈 微信小程序怎么做直播。     怎么用小程序实现在线直播? step1:开通一个云直播服务(比如 腾讯云 ),或者自己搭建一个rtmp服务器(例如 nginx-rtmp 服务)。step2:生成推流 url ,推流地址一般以 “rtmp://” 打头,比如  rtmp://8888.livepush.myqcloud.com/live/8888_test 就是一个典型 rtmp 推流 Url。step3:为你的小程序增加一个 <live-pusher> 标签,并将 url 参数指定为你在 step2 中生成的推流 url。同时, <live-pusher> 的 mode 参数可以指定为 HD 或者 FHD,这是在线直播场景中比较推荐的画质。 同时,你还可以通过 <live-pusher> 的 beauty 和 whiteness 等参数设定美颜和美白等级。 step4:生成推流 url 和播放地址,推流一般都是 rtmp:// 打头的 url,而播放地址则有两种选择,分别是 “rtmp://” 开头的 rtmp 播放协议,“http://” 打头和“.flv”结尾的的 http-flv 播放协议,推荐使用后者,因为这种播放地址各个云厂商都优化的比较好。step5:为你的小程序增加一个 <live-player> 标签 ,并将 src 参数指定为你在 step4 中生成的播放 url。同时, <live-player> 的 mode 参数请指定为 live, orientation  和 object-fit 属性可以用于调整画面布局, min-cache 和 max-cache 则可以用于控制观众跟主播之间的延时大小,推荐的设置是 min-cache = 2, max-cache = 5。关于在线直播 ...

August 21, 2019 · 2 min · jiezi

小程序如何在不同设备上自适应生成海报

小程序canvas的API并没有像其他的一样支持小程序独有的 rpx 自适应尺寸单位,在绘制内容时所应用的单位仍然是 px,那么如何实现不同尺寸屏幕的自适应呢? 我们的在开发中常用的参考屏幕尺寸(iPhone6)为:375*667; 那么想要适应其他尺寸的屏幕时只需按照iPhone6的绘制大小按比例进行换算即可: 获取系统屏幕尺寸先利用wx.getSystemInfo (获取系统信息)的API获取屏幕宽度,然后除iPhone6的屏幕宽度,即可得到相对单位 // 在onLoad中调用const that = thiswx.getSystemInfo({ success: function (res) { console.log(res) that.setData({ model: res.model, screen_width: res.windowWidth/375, screen_height: res.windowHeight }) }})在绘制方法中将参数乘以相对单位即可实现自适应这里的rpx是相对不同屏幕宽度的相对单位,测量出得实际宽度,就是实际测出的px像素值*rpx就可以了;之后无论实在iPhone5,iPhone6,iPhone7...都可以进行自适应。 这里的html也要动态的设置宽和高 <canvas canvas-id="PosterCanvas" style="width:{{screen_width*375+'px'}}; height:{{screen_height*1.21+'px'}}"></canvas>drawPoster(){ let ctx = wx.createCanvasContext('PosterCanvas'),that=this.data; console.log('手机型号' + that.model,'宽'+that.screen_width*375,'高'+ that.screen_height) let rpx = that.screen_width //这里的rpx是相对不同屏幕宽度的相对单位,实际的宽度测量,就是实际测出的px像素值*rpx就可以了;之后无论实在iPhone5,iPhone6,iPhone7...都可以进行自适应。 ctx.setFillStyle('#1A1A1A') ctx.fillRect(0, 0, rpx * 375, that.screen_height * 1.21) ctx.fillStyle = "#E8CDAA"; ctx.setFontSize(29*rpx) ctx.font = 'normal 400 Source Han Sans CN'; ctx.fillText('Hi 朋友', 133*rpx,66*rpx) ctx.fillText('先领礼品再买车', 84*rpx, 119*rpx) ctx.drawImage('../../img/sell_index5.png', 26*rpx, 185*rpx, 324*rpx, 314*rpx) ctx.drawImage('../../img/post_car2x.png', 66 * rpx, 222 * rpx, 243 * rpx, 145 * rpx) ctx.setFontSize(16*rpx) ctx.font = 'normal 400 Source Han Sans CN'; ctx.fillText('长按扫描获取更多优惠', 108*rpx, 545*rpx) ctx.drawImage('../../img/code_icon2x.png', 68 * rpx, 575 * rpx, 79 * rpx, 79 * rpx) ctx.drawImage('../../img/code2_icon2x.png', 229 * rpx, 575 * rpx, 79 * rpx, 79 * rpx) ctx.setStrokeStyle('#666666') ctx.setLineWidth(1*rpx) ctx.lineTo(187*rpx,602*rpx) ctx.lineTo(187*rpx, 630*rpx) ctx.stroke() ctx.fillStyle = "#fff" ctx.setFontSize(13 * rpx) ctx.fillText('xxx科技汽车销售公司', 119 * rpx, 663 * rpx) ctx.fillStyle = "#666666" ctx.fillText('朝阳区·望京xxx科技大厦', 109 * rpx, 689 * rpx) ctx.setFillStyle('#fff') ctx.draw() },如果图片是线上地址 ctx.drawImage()会出错,不能画出图片因为会访问一个get请求,是一个异步操作,还没等到get返回就执行了tx.draw()绘制画布。 解决方案 就只在 wx.downloadFile()中成功下载了图片在进行绘制画布。 ...

August 19, 2019 · 2 min · jiezi

小程序踩坑记

小程序踩坑记希望这个文章 能尽量记录下小程序的那些坑,避免开发者们浪费自己的生命来定位到底是自己代码导致的还是啥神秘的字节跳变原因 。 前记小程序大多数坑是同一套代码在不同平台上表现不一致导致的,微信开发者工具,Android,iOS。千万不要以为自己写的代码在模拟器上跑过了就完事了,一定需要在 Android 和 iOS 真机上再测一遍,否则后果不堪设想。之所以有如此坑爹的情况,也是由于小程序在不同系统下使用的底层框架不一致导致的,如下图所示。 另:小程序的视图层和 js 代码运行在不同的地方,相当于小程序的视图层运行在浏览器中,而 js 运行在原生的 js 解析引擎上。这也是为啥小程序的 js 无法获得 dom 和 bom 的原因。 坑们1,onShareAppMessage 中设置封面在 Android 和 iOS 上展示策略不一致相关文档 https://developers.weixin.qq.... 现象 当设置的 imageUrl 不是 5:4 的图片时,比如 5:3 时,就会出现下列情况,左边是在 Android 上的展示,右边是 iOS上的。两者对分享消息的封面展示策略并不一样。 版本 明显 iOS 上更合理一点,目前 Android 微信版本 6.6.7 依然会发生这种情况。 解决 像这种非 5:4 的图片,尽量也弄成 5:4 的,然后多余部分用白色进行填充。 2,wx.showToast 在 iOS 和 Android 上行为不一致相关文档 https://developers.weixin.qq.... 现象 当 showToast 后,马上返回上一个页面,在 Android 上,toast 依然存在,但 iOS 上 toast 无法显示。感觉是因为在 Android 上这个 toast 是全局的,而 iOS 上 toast 只是依附于某个页面。 ...

August 19, 2019 · 2 min · jiezi

从px到rpx了解微信小程序开发

我一直在想,我是不是有必要再写这一节,还是给大家提供一些阅读链接。因为关于单位的定义都是比较官方的。没什么好讨论的,我这里做一个汇总和简单的说明吧。首先本文只以移动设备为例说明。本文摘要:设计师以iphone6为标准出设计稿的话,1rpx=0.5px=1物理像素。Photoshop里面量出来的尺寸为物理像素点。所以可以直接使用标注尺寸数据。--------------------------------------看懂本文摘要的话,就不用阅读下面的内容了-------------------------------------【英寸Inch】英寸表示屏幕斜对角线的长度。如下图所示: 【像素Pixel】像素是图像的基本采样单位,它不是一个确定的物理量,因为像素点的物理大小是不确定的。如图: 【分辨率】分辨率是屏幕像素的数量,一般用屏幕宽度的像素点乘以屏幕高度的像素点。如描述iphone6的分辨率是750*1334.分辨率又分为【物理分辨率】和【逻辑分辨率】,值得注意的是实际工作中设计师常常给的是物理分辨率,程序中用到的是逻辑分辨率,但是都称为分辨率,容易混淆。【物理分辨率】是硬件所支持的分辨率,【逻辑分辨率】是软件可以达到的分辨率。物理分辨率和逻辑分辨率的商称为【像素倍率dpr】,也就是常说的几倍屏。如下图中所示,iphone6的分辨率写着375667,这里指的就是它的逻辑分辨率。我们上面提的7501334则是它的物理分辨率。所以iphone6的像素倍率=(7501334)/(375667)=2 理解了上述的几个概念,我们就可以接着来看下面的几个单位。【px】px就是Pixel的缩写,就是指像素。这个作为图片采样的基本单位,没什么需要特别说明的。【rem】在做移动端适配是最常用的方法就是使用rem作为单位,因为rem是根据html的fontsize去动态计算实际的px的。所以常常应用这点,做反向使用。即根据屏幕大小动态的设置fontsize.来达到不同的分辨率下有一样的效果。【rpx】rpx其实是微信对于rem的一种应用的规定,或者说一种设计的方案,官方上规定屏幕宽度为20rem,规定屏幕宽为750rpx。所以在微信小程序中1rem=750/20rpx。但是这不是我们要关注的重点。在使用rem时,我们常常让设计师根据iphone6的标准出设计稿。因为如果以iphone6为标准,并且在iphone6上将fontsize设置成62.5%。那么1rem就等于10px,我们只要将设计师标注的尺寸(一般标注的是物理分辨率)除以20就可以得到单位为rem的数值了。在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。css中的px与设备的物理像素并非绝对的一比一关系。px与物理像素的比例与设备的dpr(像素倍率)有关。rpx称为相对像素值,rpx与物理像素也并非绝对的一比一关系。wxss将设备宽定义为750rpx,是以iPhone6的分辨率(750x1334)为基准划分的。也就是说,在iPhone6上,1rpx=1物理像素=0.5px。因为设计师标注的尺寸一般是物理分辨率。所以如果以iphone6为标准出设计稿的话,那么我们就可以不需要经过换算直接标准rpx。这节课的内容就到这里结束了。感谢您的阅读。

August 19, 2019 · 1 min · jiezi

如何理解小程序系统参数屏幕宽度和窗口宽度

我们可以通过wx.getSystemInfo获取小程序的当前系统参数,那么大家对这里面的屏幕维度和窗口维度能正确区别吗? https://developers.weixin.qq.... 屏幕宽高指设备的宽高,窗口宽高指可用区域宽高,比如你用了小程序的tabbar和navigator,那,窗口高度就会被比屏幕高度小。 屏幕宽度和窗口宽度在大多数情况应该都是一样的,比如什么时候小程序只在屏幕里占一半宽了,那他们就不一样了。

August 19, 2019 · 1 min · jiezi

微信小程序实现定位及到指定位置导航

一:实现定位及到指定位置导航所需组件及API 1:组件:map(地图组件) 2:API:wx.getLocation(Object object)(获取当前的地理位置、速度),wx.openLocation(Object object)(使用微信内置地图查看位置) 二:代码实现 1:wxml <view><map id="map"longitude="{{longitude}}"latitude="{{latitude}}"scale="14"markers="{{markers}}"bindmarkertap="markertap"bindregionchange="regionchange"show-locationstyle="width: 100%; height: 300px;"></map></view><view><button type="primary" bindtap="navigate">导航</button></view>2:js //jsPage({/** * 页面的初始数据 */data: {//设置标记点markers: [{iconPath: "/images/ljx.png",id: 4,latitude: 31.938841,longitude: 118.799698,width: 30,height: 30}],//当前定位位置latitude:'',longitude: '',},navigate() {////使用微信内置地图查看标记点位置,并进行导航wx.openLocation({latitude: this.data.markers[0].latitude,//要去的纬度-地址longitude: this.data.markers[0].longitude,//要去的经度-地址})},onLoad() {//获取当前位置wx.getLocation({type: 'gcj02',success: (res) => {console.log(res)this.setData({latitude: res.latitude,longitude: res.longitude})}})}})根据如上即可实现自身定位及到指定位置的导航,如下:

August 19, 2019 · 1 min · jiezi

微信小程序使用车牌号输入法

在做小程序时,做了一个关于车的项目,然后需要添加车辆信息、添加车牌号,使用车牌键盘输入,当时我把这个需求给砍了,然后在添加车辆信息时,老大看到数据库里我乱填的车牌号,又让我把他加上了^o^1.效果图2.相关代码使用组件形式实现键盘输入组件代码index.wxml <view class="carPlate" wx:if="{{show}}"> <block wx:if="{{type==1}}"> <view class="wordList"> <view class="wordItem" wx:for="{{cityKeyword1}}" wx:key="{{item}}" bindtap="handleClick" data-type="1" data-item="{{item}}">{{item}}</view> </view> <view class="wordList"> <view class="wordItem" wx:for="{{cityKeyword2}}" wx:key="{{item}}" bindtap="handleClick" data-type="1" data-item="{{item}}">{{item}}</view> </view> <view class="wordList"> <view class="wordItem" wx:for="{{cityKeyword3}}" wx:key="{{item}}" bindtap="handleClick" data-type="1" data-item="{{item}}">{{item}}</view> </view> <view class="wordList"> <view class="wordItem" wx:for="{{cityKeyword4}}" wx:key="{{item}}" bindtap="handleClick" data-type="1" data-item="{{item}}">{{item}}</view> </view> </block> <block wx:else> <view class="wordList"> <view class="wordItem" wx:for="{{keyNumber}}" wx:key="{{item}}" bindtap="handleClick" data-type="2" data-item="{{item}}">{{item}}</view> </view> <view class="wordList"> <view class="wordItem" wx:for="{{wordList1}}" wx:key="{{item}}" bindtap="handleClick" data-type="2" data-item="{{item}}">{{item}}</view> </view> <view class="wordList"> <view class="wordItem" wx:for="{{wordList2}}" wx:key="{{item}}" bindtap="handleClick" data-type="2" data-item="{{item}}">{{item}}</view> <view class="wordItem wordClear" bindtap="handleClick" data-item="delete"> <image src="/images/input-clear.png" class="clearImg"></image> </view> </view> <view class="wordList"> <view class="wordItem" wx:for="{{wordList3}}" wx:key="{{item}}" bindtap="handleClick" data-item="{{item}}">{{item}}</view> <view class="wordItem wordConfirm" bindtap="handleClick" data-item="confirm">确定</view> </view> </block></view>index.css.carPlate{ position: fixed; padding: 12rpx 12rpx 30rpx; left: 0; bottom: 0; width: 100%; /* height: 150px; */ font-size: 30rpx; background: #fff; box-sizing: border-box; border-top: 1px solid rgb(211, 207, 207); z-index: 200;}.wordList{ display: flex; width: 100%; justify-content: space-between; align-items: center;}.wordItem{ margin: 5rpx; width: 70rpx; height: 70rpx; line-height: 70rpx; text-align: center; border: 1px solid #eee; border-radius: 10rpx;}.wordConfirm{ width: 130rpx; color: #fff; background: #473af0;}.wordClear{ width: 100rpx;}.clearImg{ width: 60rpx; height: 60rpx; vertical-align: middle;}index.jsComponent({ properties: { type: { type: Number, default: 1, }, show: { type: Boolean, default: false, } }, data: { cityKeyword1: '京沪浙苏粤鲁晋冀豫', cityKeyword2: '川渝辽吉黑皖鄂湘赣', cityKeyword3: '闽陕甘宁蒙津贵云', cityKeyword4: '桂琼青新藏港澳台', keyNumber: '1234567890', wordList1: 'QWERTYUIOP', wordList2: 'ASDFGHJKL', wordList3: 'ZXCVBNM', }, methods: { handleClick(e) { let value = e.currentTarget.dataset.item; let type = e.currentTarget.dataset.type; switch(value) { case 'confirm': this.triggerEvent('confirm'); break; case 'delete': this.triggerEvent('delete'); break; default: this.triggerEvent('change', { value, type }); } } }})3.父组件引入我想实现点击输入后有上拉的效果,开始我想使用offset来实现的,但是下班后洗衣服想了下,不太好实现,我就想到了我以前做购物车时,有用到transform,原理差不多,我就把他用上了然后就是点击键盘外实现收起键盘,开始我想到的就是在父组件的最外层定义关闭事件,父级里面的盒子都使用catch方法阻止冒泡,但想下阻止冒泡好像又有点不合情理,就又把阻止冒泡给去掉了父组件index.wxml<view class="container" bindtap="handlePlateConfirm"> <view class="translateView" style="transform: translateY({{translateSpace}}px)"> <view class="list"> <view class="item"> <view class="label">*车牌号码</view> <view class="contentBox" catchtap="handleClick"> <view class="inputBox" wx:if="{{carNo}}">{{carNo}}</view> <view class="promptText" wx:else>请输入车牌号</view> </view> </view> </view> </view></view><car-plate show="{{showPlateInput}}" bindchange="handlePlateChange" type="{{inputType}}" bindconfirm="handlePlateConfirm" binddelete="handlePlateDelete" />父组件index.jsPage({ data: { carNo: '', translateSpace: 0, inputType: 1, // 车牌输入类型,1简称,2数字或者字母, showPlateInput: false, }, /* 用于点击弹出键盘输入,space为键盘弹出后向上拉取的距离 */ handleClick(e) { /* 150为键盘的高度 */ let space = -(e.currentTarget.offsetTop - 150); /* regExp用于判断当前已输入的车牌号是否是中文,并让键盘显示中文还是英文输入 */ let regExp = /^[\u4e00-\u9fa5]+/; let inputType = 1; if(regExp.test(this.data.carNo)) { inputType = 2; } this.setData({ translateSpace: space, showPlateInput: true, inputType }) }, /* 键盘输入操作 */ handlePlateChange(e) { let value = e.detail.value; let type = e.detail.type; let carNo = this.data.carNo; carNo += value; if(type == 1) { this.setData({ inputType: 2 }) } this.setData({ carNo }) }, /* 点击键盘上的确定 */ handlePlateConfirm() { /* isCarPlate用于判断输入的车牌号是否符合规范 */ if (!this.isCarPlate(this.data.carNo)) { wx.showToast({ title: '请输入正确的车牌号', icon: 'none', duration: 2000 }) return false; } this.setData({ translateSpace: 0, showPlateInput: false, inputType: 1 }) }, /* 用于键盘输入删除 */ handlePlateDelete(e) { let carNo = this.data.carNo; carNo = carNo.substring(0, carNo.length - 1); if(carNo.length == 0) { this.setData({ inputType: 1 }) } this.setData({ carNo, }) }, /* 判断车牌号 */ isCarPlate(value) { return /^(([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z](([0-9]{5}[DF])|([DF]([A-HJ-NP-Z0-9])[0-9]{4})))|([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳使领]))$/.test(value); }})父组件index.css.container{ height: 100vh; background: #fff;}.translateView{ background: #eee;}.list{ margin-bottom: 20rpx; background: #fff;}.list:last-child{ margin: 0;}.item{ display: flex; padding: 0 26rpx; width: 100%; height: 116rpx; box-sizing: border-box; align-items: center; border-bottom: 1px solid #eee;}.item:last-child{ border: none;}.label{ margin-right: 10rpx; width: 140rpx;}.contentBox{ display: flex; width: calc(100% - 150rpx); height: 90rpx; align-items: center; justify-content: space-between;}.promptText{ color: #c7c7c7;}.inputBox{ width: 100%; height: 80rpx; line-height: 80rpx;}正在努力学习中,若对你的学习有帮助,留下你的印记呗(点个赞咯^_^)往期推荐: ...

August 19, 2019 · 3 min · jiezi

扫小程序码实现网站登陆提供源代码

使用扫小程序码登陆网站网络上关于实现本本功能的文章很多,但是给出案列的几乎没有,今天笔者实现用小程序码实现网站登陆,体验地址如下https://idea.techidea8.com/open/login.shtml 思路 关键流程建立场景sceneid和websocket的绑定关系获得sceneid场景ID可以前端生成,也可以后端生成,只需要保证sceneid的同一时间唯一性即可。前端生成可以采用随机数加时间戳的形式,也可以用uuid算法 //时间戳var sceneid ="scend-" + new Data().getTime() + Math.ceil(Math.random()*888888+1000000);建立websocketvar ws = new WebSocket("ws://192.168.0.106/websocket?clientid="+sceneid )ws.onopen=function(env){ console.log(env)} ws.onmessage=function(env){ var data = env.data; //这个data 就是后端发来的用户数据} 后端建立websocket后端采用go语言github.com/gorilla/websocket包建立websocket.因为golang 非常适合高并发场景。 func (ctrl *PushCtrl) websocket(w http.ResponseWriter, req *http.Request) { //fmt.Printf("%+v",request.Header) //todo 检验接入是否合法 //checkToken(userId int64,token string) query := req.URL.Query() clientid := query.Get("clientid") conn, err := (&websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true }, }).Upgrade(w, req, nil) if err != nil { log.Println(err.Error()) return } clientMap.Store(clientid, conn) go func(clientId string, conn *websocket.Conn) { //处理出错信息 defer func() { conn.Close() clientMap.Delete(clientid) }() for { _, _, err := conn.ReadMessage() if err != nil { log.Println(err.Error()) return } } }(clientid, conn)}我们采用sync.map建立sceneid和websocket的对应关系 ...

August 18, 2019 · 2 min · jiezi

微信小程序开发之页面分享-onShareAppMessage-分享参数用处

今天下午突然听到群里有人说微信小程序工具更新了,文档也更新了不少内容. 顾不上吃冬至的饺子.我就冲进来了. 先说分享功能,目前真机尚不能调试.开发工具上可以看看效果.后续还会更新. Page()中加上如下代码后在右上角就会出现三个小白点 title:分享的标题. desc:分享一段描述. path:这个参数有点意思.以前在微信中的分享一般都是url.这里是当前页面这里应该是pages/index?id=123这里的id目前还不知道是什么. 也就是说以后你可以在微信中像分享一个网页一样分享一个页面了. onShareAppMessage: function () { return { title: '微信小程序联盟', desc: '最具人气的小程序开发联盟!', path: '/page/user?id=123' } }分享参数用处: 我这里没有用到路径后的参数,说个场景:参数是用户昵称,A分享了XXX小程序到微信群里,B点开小程序,弹个toast,”来自A的分享”. ———————————————— 版权声明:本文为CSDN博主「dzp_coder」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/qq_3138...

August 18, 2019 · 1 min · jiezi

uniapp微信小程序接入人脸核身SDK

这几天使用uni-app开发某银行的一个微信小程序,需要集成接入腾讯云的人脸核身SDK,如上图所示,记录下整合接入过程及踩的一些坑,帮助后面需要的朋友们。关于uni-app接入人脸核身SDK有不懂的地方可以在下面提问,看到会及时回复。 申请服务不是所有的企业都能够申请的,需要符合以下行业要求的客户才能申请政务:政府机构或事业单位金融:银行、保险医疗:公立医疗机构运营商:电信运营商教育:公立教育机构交通:航空、客运、网约车、交通卡、共享交通、轨道交通、租车旅游:酒店物流:快递、邮政、物流 由于SDK会调用小程序原生的wx.startFacialRecognitionVerify方法,所以总共得申请2个服务SDK服务:申请人脸核身服务小程序:查看申请流程(需要发送邮件申请,使用该服务的小程序的appid,后面开发也是用的这个)重要的事情说3遍以上这2个服务都需要申请,缺一不可。以上这2个服务都需要申请,缺一不可。以上这2个服务都需要申请,缺一不可。 下载SDK由于不是我申请的,所以怎么下载我也不知道,听群里的人说的是SDK腾讯云下发给客户的。 SDK目录结构 SDK接入参考腾讯云文档的接入方法:https://cloud.tencent.com/document/product/1007/31071文档是针对原生小程序写的,所以页面引入的方法有所不同由于uni-app不支持直接引入小程序的原生页面,所以这里能想到的就是将它当作成一个微信小程序的组件,然后uni-app的页面引入这个组件 解压引入SDK在uni-app项目中新建wxcomponents目录,将SDK解压后放到该目录pages.json中globalStyle中全局引入小程序的组件,注意引用的路径 "usingComponents": { "verify-mpsdk": "/wxcomponents/verify_mpsdk/index/index"} 新建人脸核身页面pages中新建人脸核身的页面face(名字可以随意,根据自己的需要起名),pages.json中配置页面face页面中引入verify-mpsdk组件最终的人脸核身的页面访问就是/pages/face/face 初始化SDK在需要的页面初始化SDK,如有个页面需要点击按钮进行人脸核身,就在这个页面进行初始化。这个直接照着文档快速入门中的来就行了,这里就直接使用uni-app默认的index页面,适当修改下即可,大概代码如下: <template> <view class="content"> <button type="primary" @tap="gotoVerify"> 进入人脸核身 </button> </view></template><script> export default { data() { return { BizToken: '' } }, onLoad() { // 初始化慧眼实名核身组件 const Verify = require('@/wxcomponents/verify_mpsdk/main.js') Verify.init() }, methods: { // 单击进入人脸核身按钮时,触发该函数 gotoVerify () { this.BizToken = '' // 这里需要我们去客户后端调用DetectAuth接口获取BizToken // 调用实名核身功能 wx.startVerify({ data: { token: this.BizToken // BizToken }, success: (res) => { // 验证成功后触发 // res 包含验证成功的token, 这里需要加500ms延时,防止iOS下不执行后面的逻辑 setTimeout(() => { // 验证成功后,拿到token后的逻辑处理,具体以客户自身逻辑为准 console.log(res) }, 500) }, fail: (err) => { // 验证失败时触发 // err 包含错误码,错误信息,弹窗提示错误 setTimeout(() => { console.log(err) wx.showModal({ title: "提示", content: err.ErrorMsg, showCancel: false }) }, 500) } }) } } }</script>注意下这里的BizToken,需要调用后端服务接口来获取,需要后端的同学调用腾讯云提供的DetectAuth来返回前端需要的BizToken,调试开发阶段我们可以先通过腾讯云提供的工具API 3.0 Explorer直接来获取这个BizToken如果服务申请成功后控制台一般能找到SecretId,SecretKey,RuleId注意Endpoint和Region选择的地区得保持和申请时选择的地区一致。填写完成后点击在线调用中的发送请求按钮,如果填的都对的话返回信息里面会有BizToken拿到BizToken后就可以直接使用了,修改下上面的代码:xxxxxxxxxxxxxxxxx就是拿到的BizToken ...

August 17, 2019 · 1 min · jiezi

你Next-Idea微信小程序开发大赛启动

灯可以怎么省油? 明朝人有钱到什么程度? 古人没有冰箱,怎么存放食物? 越王勾践剑为什么会出现在楚墓中?……对历史,我们总存在多多少少的疑问,《国家宝藏》《上新了故宫》等节目展示的文物也让我们为古人的聪明才智所折服。历经几千年的变迁,古人的智慧放到现在也是超乎想象的。然而身为21世纪的你,愿意与古人来一场高智商“对话”吗? 历史文物深藏于博物馆中,看似离大众的生活很遥远,但只要借助技术,便能让更多市民民众与它们近距离接触。这也就需要你们——小程序开发者们的帮助,通过创意和开发技能,搭建微信小程序,将古人的智慧带到大众面前。 腾讯Next Idea、微信极客WeGeek联合全国九大博物馆发起Next Idea微信小程序开发大赛,鼓励青年创客们用创意激活中国传统文化。 九大博物馆向你下brief此次九大国家一级博物馆选取了众多充满古人智慧和创意的文物,并分别设置了主题,参赛队伍可参考博物馆的题目方向并贴合传统文化传承的核心进行创意构思,搭建微信小程序。 1、上海博物馆-海上风华:体现中西、传统与现代文化的交融 2、湖南省博物馆-湖湘性格:展现湖湘人民性格特色 3、河南博物院-华夏之光:寻根华夏儿女与传承华夏文明 4、陕西历史博物馆-汉唐风采:阐释汉唐盛世的开放姿态 5、湖北省博物馆-荆楚文化:体现荆楚文化的辉煌与独特魅力 6、浙江省博物馆-江南美学:从乐器书画中感知浙江的文化底蕴 7、重庆中国三峡博物馆-巴渝智慧:聚焦巴渝人民的智慧创作 8、山西博物院-晋国雄风:见证晋国在中原的百年霸业 9、首都博物馆-京城古韵:(不作为题目)展现北京城的历史和文化传承 为界定创意小程序方向,WeGeek官方提前特邀一支创客团队为首都博物馆推出了一个小程序作品,参赛选手可以从其他八个博物馆中任选一个作为作品主体。 什么小程序形式会加分?✗ 不建议导览购票等工具类小程序作品。✓ 建议结合更多有趣新颖的玩法,或者结合文物的亮点开发小程序。 如本次大赛的打样作品,首都博物馆的小程序,结合AI模式识别能力,链接现实与历史,用户可以将点亮的文物收于自己的“展馆”中并分享,在互动的过程中,了解文物。 (大家可以扫描下方二维码进行体验) 此次大赛是考验大家想象力的时候,记得好好表现哦~最后我们会针对八个博物馆评出八支优秀团队,分别给予4万元(税前)奖励支持, 优秀团队还有机会得到各省博物馆小程序后续的运营合作机会,小程序作品也会在对应博物馆正式上线与民众互动。 怎么参加比赛?只要你是18-35岁的青年群体,可选择单人或自由组队,队伍人数不超过8人。 赛事采用网络投递方式(截止时间:8月28日),需将产品设计稿,APPID,及小程序demo体验二维码投递到邮箱Wegeek@tencent.com。 投递要求:1、投递到邮箱的附件仅有一个文件(PPT或者PDF格式) 2、各个参赛团队需将自己的demo作品绑定官方WeGeek测试账号,将WeGeek测试账号作为参赛demo小程序作品的项目成员之一,以便评委海选时扫码评审作品。 测试账号:Wegeektest00,Wegeektest01,Wegeektest02,Wegeektest03,Wegeektest04,Wegeektest05,Wegeektest06,Wegeektest07,Wegeektest08,Wegeektest09。选手可先优先选择前面的账号绑定作品。3、文件中包含团队背景介绍,作品设计描述,最后一页附上所选的绑定测试账号,作品demo二维码,及作品APPID,总体篇幅不超过10页PPT。 大赛流程7.23-8.28参加选手或参赛团队组队,根据博物馆题目进行作品创作并提交demo,不需与博物馆建立素材或接口上的对接 8.28-9.6由评委会评选出八支优秀参赛队伍创意 9月至10月底八家博物馆提供素材,团队进行对接,并开始作品落地打磨 11月底各大博物馆小程序上线联合发布 欢迎各位开发者们到官网了解大赛详情,为传承中华文化贡献自己的力量。

July 26, 2019 · 1 min · jiezi

讲case-电商直播趋势下小程序可以做什么

要说最近火爆的电商模式,非直播莫属。年初一个李佳琦的“OMG”引爆网络,618各大电商又纷纷直播卖货,成交量大幅增长。显而易见,直播电商已成为最强带货王。 “直播+电商”模式的优势“直播+电商”模式是主播直播卖货,多维度地向消费者展示商品信息。像是蘑菇街,在今年618期间,直播GMV(销售额)同比2018年618期间增长600%,利用直播打了一场翻身仗。 在以往的图文模式中,商品的图片往往是经过美化,有时候消费者发现真实货物与心里预期相差甚远,产生上当的感受。所以“直播电商”模式是为消费者提供了一个更加直接了解商品的途径。网红张大奕之前就在她的电商直播间内直播了服装的仓库、打板房等,在一定程度上消除消费者对商品的顾虑,建立信赖感。 传统的线上购物流程更多是消费者自主选购的过程,除非对商品有疑问,才会打开客服页面进行文字咨询。电商直播则可以在消费者选购过程中进行干预,当消费者对商品有疑问时,可以发弹幕提问,主播在直播中展示式解答。这一互动形式也算是一个和消费者建立沟通的入口,提升他们的购物体验。另外,主播能够通过导购增强消费者对该商品的购买冲动,完成交易。 背后是消费者消费心理的变化据《2019中国网络视听发展研究报告》显示,短视频用户、网络直播用户规模分别为6.48亿、3.97亿。这也反映了消费者对视频的兴趣浓厚,为电商直播提供了庞大的用户群体。同时,消费者的购物需求也随着收入水平的提高产生了变化,从“需要什么”到“想要什么”,消费者更容易被“种草”,并下单购买。而电商直播就是种草机,通过主播的亲身展示,引导消费者购物。 电商直播一般分为两种形式:中心化流量和自主流量。蘑菇街就是中心化流量,借助知名主播自带的粉丝流量卖货,大多消费者也是冲着对主播的信任去下单。目前主播卖货主要集中在珠宝、美妆、服装三种品类,因为延伸内容可操作性较大,主播通过分享珠宝鉴定、化妆、服装搭配等干货,既能满足消费者的求知欲,又能合理地引导下单。蘑菇街的主播小甜心_呢在讲解眼线笔时,就分享了大眼和小眼画眼线的技巧,在工作日中午时段在线观看人数也有25万。 自主流量则是卖家现身种草,可适用于农副产品。卖家通常以淳朴的形象出镜,为消费者直播制作过程或者介绍自家商品的美味。卖家的农民形象能够降低消费者的防备心理,也抓住了他们对乡村的向往情绪,“纯天然”“纯手工”是最大的卖点。 小程序在电商直播中的应用除了APP,蘑菇街上线了专做电商直播的蘑菇街购物台小程序,主播和用户均能在微信里分享小程序,扩大直播的传播范围。社交分享是小程序用户裂变的主要途径,当朋友分享了小程序给你,你打开了解时,你已经成为了该小程序的用户。 这种小程序也可以搭配社群运营,在主播的粉丝群内分享直播,直播前提醒粉丝观看,直播后获取粉丝观看反馈,方便主播们在微信里建立私域流量,积累客源。 如果你也想通过直播为自己的电商小程序带货,但又没有直播资质,其实可以借助腾讯官方平台。方式包括以下两种: 第一种:腾讯直播使用腾讯直播创建直播间,并且实现直播预约、提醒的通知服务。目前这项功能正在内测中,可到订阅号【腾讯直播助手】点击底部菜单栏,完成电商内测申请问卷,审核通过即可使用小程序跳转模式开启电商直播。 第二种:移动直播SDK移动直播SDK是基于腾讯云 LiteAV 音视频框架实现的一套推拉流和连麦组件,提供包括小程序等多种接入方式。它经过微信官方认证,能够帮助开发者快速合规上线含有电商直播业务的小程序。 接入步骤 1 开通标签使用权限出于政策和合规的考虑,非个人主体才有使用权限,而目前也仅支持社交、教育、医疗、政府主体账号、金融、汽车、工具类目。 符合类目要求的小程序,在小程序管理后台的【开发】-【接口设置】中自助开通推拉流标签的使用权限。 2 开通腾讯云直播服务进入云直播管理控制台(https://console.cloud.tencent...)开通云直播服务,添加至少2个自有域名,一个作为推流域名,一个作为播放域名,并进行域名 CNAME 。 3 开通腾讯云通信服务进入云通信管理控制台(https://console.cloud.tencent...)开通云通信。 4 开通房间管理服务进入云直播控制台的【直播SDK】-【房间管理】,单击【创建应用】填写信息。在目标应用详情中下载公私钥,获取直播服务配置信息。 5 下载并跑通Demo到github(https://github.com/tencentyun...)下载Demo源码,打开微信开发者工具导入项目,并进行调试。 6 替换云服务账号由于Demo默认使用的是腾讯云提供的测试账号,所以还需要替换成自己的账号体系。 接入的详细步骤可点击https://github.com/tencentyun...。 电商直播借助主播这一媒介,能够有效降低商家和消费者的沟通成本,从而提高销售量。它对商品销售有高效转化能力也在618得到了验证,但它现在仍不是电商的主流模式,也许还有一大片市场可以让我们去挖掘。 如果你想学习开发电商小程序,欢迎扫码进群,这周四晚将进行《小程序·云开发实战:从0到1快速开发电商小程序》的免费直播课程分享。

July 16, 2019 · 1 min · jiezi

前端知识总结

前端知识总结vuejsvue实现双向绑定原理1、Object.defineProperty()中的set/get设置属性值/获取属性值2、过程 Observer劫持并监听所有属性 发生变化,通知Dep观察者(update函数)Watcher负责向观察者列表添加对应更新函数Compile编译解析初始化/更新vue生命周期beforeCreate data和methods中的数据和方法还没初始化created data和methods初始化完成beforeMount 模板已经在内存编译好了,尚未挂载到页面mounted 页面挂载完成,可以操作DOMbeforeUpdate 页面数据是旧的,data数据是新的,页面和最新数据还没同步updated 页面和data已经保持最新beforeDestory 进入销毁阶段,data、methodes...还可用destroyed 组件已经完全销毁,data、methods以及过滤器,指令不可用vue组件通信父子通信 父组件绑定属性“:data-attr”数据子组件在props接收驼峰式dataAttr数据子与父通信 子组件$emit('to-parent',newMsg)绑定属性传输数据父组件绑定@to-parent="getChildren(e)"属性接收数据兄弟通信 在main.js建立一个Vue.prototype.bus事件总线(中间层)在borther1,this.bus.$emit('属性toborther2',值)在borther2接收,this.bus.$on('toborther2',function(val){ that.msg = val })vue的虚拟DOM虚拟DOM出现是为了减少频繁大面积的重绘引发的性能问题虚拟dom和真实dom的区别 1、虚拟dom不会排版与重绘 2、真实dom频繁排版与重绘效率相当低 3、虚拟dom进行频繁修改,然后一次性比较并修改真实dom中需要改的部分,最后并在真实dom中进行排版与重绘,减少过多dom节点排版与重绘损耗 4、虚拟dom有效降低大面积的重绘与排版,因为最终与真实dom比较差异,可以只渲染局部DOM Diff 指的是通过Diff算法去比较虚拟DOM的变化vue怎么更新节点 1、先根据真实DOM生成virtual DOM 2、当virtual DOM某个节点的数据改变后会生成一个新的Vnode 3、Vnode和oldVnode作对比,发现有不一样的就直接修改在真实的DOM,然后使oldVnode的值为Vnode路由全局路由拦截(路由守卫) router.beforeEach(( to, from, next )=>{}) //跳转前 to: 即将进入的目标(路由对象)from:当前导航正要离开的路由next()进行下一个钩子,next(false)中断当前导航,如果此时URL改变,则会重置为from后的路由地址, next('/') next(path: '/')终止当前导航,跳转到一个不同的地址,next(error)如果参数为一个error实例,则会终止导航beforeResolve(( to, from, next )=>{}) //跳转成功afterEach(( to, from, next )=>{}) //跳转后局部路由拦截 路由内部钩子: beforeEnter(( to, from, next )=>{})组件内部钩子 beforeRouteEnter(( to, from, next )=>{}) //从另外的组件进入该组件前触发该钩子beforeRouteUpdate(( to, from, next )=>{}) //同一个组件,参数不一样,不一样数据beforeRouteLeave(( to, from, next )=>{}) //该组件离开跳转到另外的组件时触发该钩子路由传参 ...

July 16, 2019 · 2 min · jiezi

基于SpringBoot的开源微信开发平台JeewxBoot-10-版本发布

项目介绍Jeewx-Boot 是一款基于SpringBoot的免费微信开发平台。支持微信公众号、微信活动、小程序官网。Jeewx-Boot实现了微信公众号管理、小程序CMS、微信活动等基础功能,便于用户二次开发,快速搭建微信应用。源码下载https://github.com/zhangdaisc...https://gitee.com/jeecg/jeewx...技术交流QQ交流群 : 97460170在线文档:http://jeewx-boot.mydoc.io小程序文档: http://shop.jeewx.com/#/doc/r...技术论坛 :www.jeecg.org演示地址:https://app.jeewx.com/jeewx项目说明项目名中文名备注jeewx-boot-base-system系统用户管理含项目启动类jeewx-boot-module-cmsCMS管理后台 jeewx-boot-module-weixin微信公众号管理 jeewx-app-cms小程序官网源码采用wepy语言系统模块├─系统管理│ ├─用户管理│ ├─角色管理│ ├─菜单管理│ └─首页设置│ └─项目管理(插件)├─公众号运营│ ├─基础配置│ │ ├─公众号管理│ │ ├─关注欢迎语│ │ ├─未识别回复语│ │ ├─关键字设置│ │ ├─自定义菜单│ │ ├─菜单支持小程序链接│ │ ├─Oauth2.0链接机制│ ├─素材管理│ │ ├─文本素材│ │ ├─图文素材│ │ ├─超强图文编辑器│ │ ├─图文预览功能│ ├─用户管理│ │ ├─粉丝管理│ │ ├─粉丝标签管理│ │ ├─超强图文编辑器│ │ ├─接受消息管理│ │ ├─粉丝消息回复├─小程序官网│ ├─站点管理│ ├─广告管理│ ├─栏目管理│ ├─文章管理│ ├─后台管理代码│ ├─小程序前端代码├─微信抽奖活动(即将开源)│ ├─砸金蛋│ ├─摇一摇│ ├─微信砍价├─高级功能(尚未开源)│ ├─小程序商城│ ├─微信投票│ ├─分销商城│ ├─。。。└─其他插件 └─更多功能陆续开源。。系统特点采用最新主流技术架构(Springboot+Mybatis+Velicity)强大的代码生成器,代码一键生成微信公众号管理,基础功能无需开发,直接使用支持微信小程序,已经提供小程序CMS供大家学习和使用采用插件开发机制,后续更多插件提供系统截图PC端 小程序端 手机端 欢迎吐槽,欢迎star~

July 15, 2019 · 1 min · jiezi

基于Taro的微信小程序分享图片功能实践

前言在各种小程序(微信、百度、支付宝)、H5、NativeApp 纷纷扰扰的当下,给大家强烈安利一款基于React的多终端开发利器:京东Taro(泰罗·奥特曼),Taro致力于多终端统一解决方案,一处代码,多处运行。 Taro支持以React语言开发小程序,支持CSS预处理器,支持实时编译更新,支持NPM,等等等等,简直不要太爽!微信小程序分享图片功能是经常在小程序业务中出现的,比如学习打卡分享,推广会员分享,推广商品分享等等。因为小程序是不支持直接分享图片到朋友圈的,一般操作为: 生成包含小程序码(当前也可以是其他特定的信息)的图片;用户点击保存图片,下载到本地,再发布到朋友圈;其他用户长按识别该小程序码,进入当前小程序。今天胡哥给大家分享下,基于Taro框架实现微信小程序分享图片功能的实践。 一、搭建Taro项目框架,创建微信小程序1. 安装taro脚手架工具npm install -g @tarojs/cli2. 初始化taro项目taro init taro-img-share3. 编译项目,开启Dev模式,生成小程序 -- dist目录npm run dev:weapp4. 微信开发者工具,创建小程序,选择项目根目录为taro-img-share下的dist目录二、小程序分享图片功能实践 --- 打卡图片分享功能先上图,再说话 这是重点:使用Canvas绘制图片并展示,保存图片到相册drawImage()方法负责绘制展示,saveCard()方法负责下载图片到相册src/pages/index/index.js import Taro, { Component } from '@tarojs/taro'// 引入对应的组件import { View, Text, Button, Canvas } from '@tarojs/components'import './index.scss'export default class Index extends Component { config = { navigationBarTitleText: '首页' } /** * 初始化信息 */ constructor () { this.state = { // 用户信息 userInfo: {}, // 是否展示canvas isShowCanvas: false } } /** * getUserInfo() 获取用户信息 */ getUserInfo (e) { if (!e.detail.userInfo) { Taro.showToast({ title: '获取用户信息失败,请授权', icon: 'none' }) return } this.setState({ isShowCanvas: true, userInfo: e.detail.userInfo }, () => { // 调用绘制图片方法 this.drawImage() }) } /** * drawImage() 定义绘制图片的方法 */ async drawImage () { // 创建canvas对象 let ctx = Taro.createCanvasContext('cardCanvas') // 填充背景色 let grd = ctx.createLinearGradient(0, 0, 1, 500) grd.addColorStop(0, '#1452d0') grd.addColorStop(0.5, '#FFF') ctx.setFillStyle(grd) ctx.fillRect(0, 0, 400, 500) // // 绘制圆形用户头像 let { userInfo } = this.state let res = await Taro.downloadFile({ url: userInfo.avatarUrl }) ctx.save() ctx.beginPath() // ctx.arc(160, 86, 66, 0, Math.PI * 2, false) ctx.arc(160, 88, 66, 0, Math.PI * 2) ctx.closePath() ctx.clip() ctx.stroke() ctx.translate(160, 88) ctx.drawImage(res.tempFilePath, -66, -66, 132, 132) ctx.restore() // 绘制文字 ctx.save() ctx.setFontSize(20) ctx.setFillStyle('#FFF') ctx.fillText(userInfo.nickName, 100, 200) ctx.setFontSize(16) ctx.setFillStyle('black') ctx.fillText('已在胡哥有话说公众号打卡20天', 50, 240) ctx.restore() // 绘制二维码 let qrcode = await Taro.downloadFile({ url: 'https://upload-images.jianshu.io/upload_images/3091895-f0b4b900390aec73.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/258/format/webp.jpg' }) ctx.drawImage(qrcode.tempFilePath, 70, 260, 180, 180) // 将以上绘画操作进行渲染 ctx.draw() } /** * saveCard() 保存图片到本地 */ async saveCard () { // 将Canvas图片内容导出指定大小的图片 let res = await Taro.canvasToTempFilePath({ x: 0, y: 0, width: 400, height: 500, destWidth: 360, destHeight: 450, canvasId: 'cardCanvas', fileType: 'png' }) let saveRes = await Taro.saveImageToPhotosAlbum({ filePath: res.tempFilePath }) if (saveRes.errMsg === 'saveImageToPhotosAlbum:ok') { Taro.showModal({ title: '图片保存成功', content: '图片成功保存到相册了,快去发朋友圈吧~', showCancel: false, confirmText: '确认' }) } else { Taro.showModal({ title: '图片保存失败', content: '请重新尝试!', showCancel: false, confirmText: '确认' }) } } render () { let { isShowCanvas } = this.state return ( <View className='index'> <Button onGetUserInfo={this.getUserInfo} openType="getUserInfo" type="primary" size="mini">打卡</Button> {/* 使用Canvas绘制分享图片 */} { isShowCanvas && <View className="canvas-wrap"> <Canvas id="card-canvas" className="card-canvas" style="width: 320px; height: 450px" canvasId="cardCanvas" > </Canvas> <Button onClick={this.saveCard} className="btn-save" type="primary" size="mini">保存到相册</Button> </View> } </View> ) }}src/pages/index/index.sass ...

July 15, 2019 · 2 min · jiezi

微信小程序开发基本一

一、预备知识: 页面布局:WXML,类似HTML页面样式:WXSS,几乎就是CSS(某些不支持,某些进行了增强)页面脚本:javaScript+WXS也就是需要具备一些基本的前端知识,如果使用过一些WMVM架构的框架(vue、React),那么更有利于对它的学习。 二、开发前的准备: 申请AppID参考 https://developers.weixin.qq.... 下载小程序开发者工具

July 15, 2019 · 1 min · jiezi

JavaScript技巧分享纯数字带小数点过滤

应用场景在编写输入金额的输入组件input时,虽然能够设置type为number,但却不能够自动检验用户输入的值是否符合金额的格式。比如,用户能够同时输入两个小数点。本文章以此为大前提展开略浅的技巧。 过程解析原始状态说到校验,第一个想到的就是用正则表达式。以微信小程序为例。 DOM结构...<input type='digit' value='{{value}}' bindinput='numChange' />...JavaScript逻辑...numChange(e) { // 修改单次金额 const NEXT = e.detail.value; let currentValue = this.data.value; const NEW_VALUE = this.numCheck(currentValue, NEXT); this.setData({ value: NEW_VALUE || currentValue; })},numCheck(prev, next) { // 数据过滤 // 只保留两位小数 if (next && !/^(([1-9]\d*)|0)(\.\d{0,2}?)?$/.test(next)) { if (next === '.') return '0.'; return prev; } return next;}...获取非空数据并且转换数据类型因为经过过滤后,返回的数据类型是字符串,在使用时,需要再转换一下数据类型。 ...getPureMoney() { // 获取干净的数据(非空) const { value } = this.data; const PARSE_VALUE = parseFloat(value); return !isNaN(PARSE_VALUE) ? PARSE_VALUE : '';},...用过都说好!最后,嘻嘻! ...

July 14, 2019 · 1 min · jiezi

将前后端交互同步化本篇封装了一下微信小程序的请求

今天自己写小程序的时候,近乎被异步搞到崩溃,不停地嵌套回调(我知道 await 和 promise,但是我嫌promise写起来跟裹脚布似的,而await我怕有兼容性问题也从来没有试过)言归正传,将小程序的异步调用变为同步(以下教程适用于所有异步,只是给小程序做了一下封装)。原理:增加事件队列,采用事件回调来完成同步化 以下代码复制粘贴到控制台即可测试效果;这里直接写es6代码了,先写个定时器版本的方便测试与理解先写个无注释版本的,方便直接看代码 class Async{ constructor() { this.list = []; this.sock = false; } request(obj) { setTimeout(() => { console.log(obj); this.sock = false; if(this.list[0]) this.do(this.list.shift()); }, 1000) } do(requestObj, async) { if(!async) { return this.request(requestObj); } if(this.sock) { this.list.push(requestObj); }else { this.sock = true; this.request(requestObj); } } }-----------以下为注释版本----------- class Async{ constructor() { this.list = []; // 定义 执行队列 this.sock = false; // 判断是否有任务正在执行 } request(obj) { setTimeout(() => { console.log(obj); this.sock = false; // 重置为没有任务正在执行 if(this.list[0]) // 如果队列中还有任务,执行下一个任务 this.do(this.list.shift()); }, 1000) // 模拟一个异步,一秒后执行任务,执行完成后执行下一个异步任务 } do(requestObj) { if(this.sock) // 如果有任务在执行 this.list.push(requestObj); // 将当前任务其增加到任务队列 else { this.sock = true; // 否则开始执行当前任务并设定'有任务在执行' this.request(requestObj); } } } var x = new Async(); x.do({url: 1}); // 一秒后打印 url: 1 x.do({url: 2}); // 两秒后打印 url: 2但是同步只是异步无可奈何的选择,所以不能全部否决掉异步 ...

July 14, 2019 · 2 min · jiezi

行业log-零售业内容电商新玩法你准备种草了吗

现在,跟着达人种草是许多人剁手的新趋势。在公众号【黎贝卡的异想世界】中,时尚达人黎贝卡每天分享搭配心得、盘点各类潮流单品,凭借优质的内容,累积超过500W粉丝。如果粉丝对某期推送中出现的好物感兴趣,只需在菜单页面打开黎贝卡official小程序便能选择购买。 在微信体系中成长起来的自媒体们,通过稳定的内容在受众心中建立起信任,用户更愿意进行消费。在强调个人IP的移动互联网时代,意见领袖们不再是局限于某个领域,在其他方面依然具有同等的话语权。仿佛只要生产了靠谱的内容,他们的种草自然也是靠谱的。 什么是“内容电商”?自去年以来,“内容电商”这个词被越来越频繁地讨论,内容电商实际可以理解为【内容+电商】,在生产优质内容同时,也在小程序等线上平台提供相应零售商品。上文提到的黎贝卡就是典型的内容电商。 在不少媒体从业者眼里,内容电商成为一种内容变现方式,即通过电商支撑内容输出。但随着内容和电商的结合越来越紧密,内容也可以是电商的一种方式。而内容和电商的连接,实际上是通过社交关系链完成的。创作者们通过社交裂变扩大内容影响力,然后提供符合调性的商品,提高了转化率和ROI。 搭配小程序,如何玩转内容电商?从公众号到小程序:调动公众号私域流量公众号作为微信生态主要内容渠道,积累了巨大的流量,各类自媒体大号培养了一批忠诚用户,形成固定的阅读习惯。随着小程序开放入口的扩展,公众号成为了其中的重要入口之一。现在公众号的底部菜单栏可以提供小程序商城链接,成为电商平台的入口,真正实现“内容+电商”的连接。(公众号“一条”底部菜单栏,植入自营好物小程序链接,提供推荐入口) 另外,种草达人们还可以在公众号图文中插入小程序卡片,读者便能点击进入小程序商城进行购买,自然而然地完成“种草--购物”的流程。缩短了购买路径,减少重复跳转带来的流失。 从小程序到公众号:提高用户粘性,实现持续性消费结合线下生活场景的小程序,具有一个巨大优势,就是它大量的线下流量入口。当用户使用小程序享受生活服务或进行商品购买时,引导用户关注公众号,通过优质内容供给,实现自身IP沉淀。进而将个人品牌形象渗透到用户心智,提高用户对品牌的依赖,提高后续消费能力。(屈臣氏线上商城设置公众号关注组件,引导用户关注公众号,及时了解商品信息) 对比交易电商,内容电商不仅是商品展示和推荐,而且以内容为核心,更重视场景引导和情感体验、利用情感维系实现留存。 小程序+好物圈:UGC分享形成社群效应通过微信社交关系链,用户自发传播有口碑的内容和商品,形成裂变效应,为电商注入流量。小程序背靠社交生态,为商品提供导购入口。现在微信社交电商还有一项不可忽视的新能力——好物圈。达人或商家加入好物圈后,便能引导用户在圈内推荐和讨论他们的好物。 好物圈分享形成优质的UGC,借助熟人口碑为商家做“代言”,进一步提高购买率。具体方式既可以是将小程序内商品信息同步至好物圈供搜索和提高曝光,也可以是在小程序中使用推荐接口,让用户将物品推荐至好物圈。(每日优鲜小程序选购页面,增加“推荐好物”按钮,鼓励用户分享交流) 用户在圈子内进行互相推荐和讨论,是对自媒体内容生产的一种补充。在这里,用户消费的不仅是商品本身,更是消费着社群带来的意义:一种社交和“炫耀”资本、或者个人情感寄托。 内容电商,本质上还是一种社交电商,依托社交关系链形成各类圈子,实现精准营销。不过,内容电商中“内容”不仅限于文章图片视频,还涉及小程序的交互方式、物品的选购等。这意味着,内容电商不仅仅是“写而优则卖”,更重要的是如何让内容和商品贩卖达到较高契合度,使两者呈现出共同的理念来维持这个圈子。 我们最近新建了个WeGeek技术交流群,欢迎小程序开发同好者进群交流,调戏勾搭群里的云开发大神~到微信公众号回复关键词【进群】即可获取进群方式。

July 11, 2019 · 1 min · jiezi

上线一个月做-QQ-小程序的情况如何

QQ 小程序平台的出现是必然。 2017 年微信推出并定义小程序,一年后支付宝、淘宝、百度、今日头条、十大手机厂商上线了各自的小程序平台,紧随其后的还有、抖音、快手、虎牙、Bilibili、360。短短两年,小程序平台已然成为了各大国民应用标配,甚至是巨头们渠道与投资布局的重点。如今各家纷纷入场,要用小程序打造多元化生态,曾经的社交之王 QQ 此时起步已经算晚,要满足更多年轻用户需求,只能加快小程序发展,进而更加扩大平台的服务边界和商业价值。 微信的成功,让各大应用学会了如何去做小程序;同样因为微信小程序的成功,让我们在谈到 QQ 小程序,或是其他任何小程序平台时,总是无法绕过一个问题:与微信小程序有什么不一样? QQ 小程序现状5 月 31 日,QQ 小程序正式上线,我们曾围绕这个问题进行过一个大致梳理。除开界面及部分功能的不同,二者差异主要体现在以下几个方面: 微信讲究「去中心化」,QQ 内设置了特定页面进行小程序推荐,更为「中心化」;微信小程序无法直接分享到朋友圈,QQ 小程序支持一键分享到 QQ 空间;微信更推崇工具、服务型小程序及休闲益智类小游戏,QQ 倾向于及更为费时的角色扮演类小游戏;QQ 小程序用户更年轻。时隔一个月,我们再次提起了这个话题,并邀请到了「墨迹天气」、「青团社兼职」、「小鸡词典」三个小程序的负责人一起讨论。这三款小程序,分别代表了在各自领域最头部的公司(「墨迹天气」和「青团社兼职」),以及最具创新性的团队(「小鸡词典」)。 从此次谈话(????采访实录)中我们可以得出简单的结论: 中心化的小程序推荐位和首页下拉为主要流量入口;微信小程序迁移到 QQ 上非常快捷;目前的 QQ 小程序广告能力还未全面开放,想以此获得收益时候尚早。三款小程序在 QQ 上的表现让我们更加确认,「年轻化」才是做一款 QQ 小程序的必备要素。微信想用小程序去「连接一切」,用「去中心化」的方式扩展自身成为一个强大的工具,不同的人可以在其中各取所需。但年轻人更强调「归属感」,他们并不需要那么多商业服务、内容资讯工具,他们更乐于接受推荐,也更偏爱娱乐化的产品,以此来获得社交的乐趣。 现在的 QQ 小程序新建,正是流量红利期,再加上切合的用户群体,尝到甜头的「先行者」们对 QQ 小程序平台未来发展保持着乐观。 知晓云支持 QQ 小程序知晓云已全面开放对 QQ 小程序的支持。即日起正式对外招募 50 名公测用户。公测期间你将有机会与知晓云的核心工程师直接交流,并获得 ¥200 元小程序开发补助。 我们希望你是这样的: 已经获得 QQ 小程序内测邀请码。本人或团队有小程序开发经验。了解 QQ 生态,对 QQ 小程序有自己的理解。有上线的小程序开发案例者优先。期待你的参与,赶快????提交申请????吧~ 同时,基于知晓云开发的小程序「糖纸 | 好产品就是一颗糖」也已经正式上线啦~大家可以用 QQ 扫描下方????二维码体验,或者在 QQ 中搜索「糖纸」小程序体验。 PS:如果大家感兴趣,请在文末留言,我们将邀请糖纸开发者分享从微信迁移到 QQ 小程序的宝贵经验。 ...

July 11, 2019 · 1 min · jiezi

做了一个垃圾分类小程序几个知识点介绍下代码可以分享

上海7月1号就开始执行垃圾分类了,在6月底注册了个小程序,小编我快马加鞭赶了一版,具体实现以下功能 1、垃圾分类查询2、垃圾分类介绍3、垃圾分类答题活动4、垃圾分类UGC5、垃圾分类答题活动生成海报,待审核发布中 目前分类数据已经把日常生活中最常用的维护进去了,还在一步一步完善中,由于白天还要上班,每天晚上会提交200条,请各位大大们不要嫌弃 具体如下图所示 接下来几天我会把在这两星期遇到的一些问题,跟大家分享整个实现的技术栈以及介绍几个技术细节,比如如何生成海报,如何前后端联调 如果对代码感兴趣,请在评论区留言,留下邮箱,我会第一时间把代码发过去。

July 10, 2019 · 1 min · jiezi

讲case-DAU环比增100墨迹天气做到了

如何做好小程序,总绕不开留存和变现两个难题。关于工具类小程序的发展分析,我们在前两期分享了抽奖助手的变现方法、三款小程序的留存促活模式,今天我们将以墨迹天气为例,分析其实现DAU环比增100%的留存方式。 小程序功能升级,增加留存墨迹天气是一款天气预报的应用工具,其主要功能原先在APP上已经发展成熟。所以小程序搬运了24小时预报、15天预报和生活指数等基础功能,天气预报也采用了折线图,用户可以直接感知温度的变化。 同时,墨迹天气根据小程序“用完即走”的特性,为了能够让用户坚持使用,通过设置记录用户行为轨迹的功能增强留存,新增早起日记、城市足迹两个功能。用户在“足迹”页,能一目了然自己打开小程序的时间以及查看过哪些城市的天气使用记录。 早起打卡是墨迹天气主推的新功能,只要用户在早上4:30-10:30期间打开小程序,系统便会自动记录早起打卡,坚持的天数形成可视化的维度并进行排行以及勋章奖励。 签到,是大多数小程序提高留存的方法,但如果设置的签到场景不适合,收获的效果微乎其微。刚好墨迹天气用户主要是白领群体,习惯于早上出门上班前看天气,这便与早起签到的设置相对应。而且用户打开小程序即签到,无需再进行其他操作,在一定程度上降低签到完成门槛,也能激发用户每日打开小程序的欲望,增强用户黏度。 立足社交,分享也要有包装墨迹天气作为工具类小程序,与APP一样,在功能上已经解决用户了解天气情况的刚需。但在微信生态中,它还可以利用这个社交环境,将自己扩散至更广的范围。 当用户想要将天气预报分享给他人时,以往操作是通过发送天气预报的截图,而在小程序中,可实现直接分享。在首页右下方有个分享的按钮,墨迹天气通过文案的包装“提醒他注意天气变化”,从单纯的分享变身为他人贴心提醒,赋予分享行为感性的内涵。这种走心方式让用户也乐于分享,大大提高了分享率。 除此之外,墨迹天气结合天气推出的海报也具有特色。一般会有三款不同类型的海报满足用户的分享需求,包括卡通形象的预警海报、古风诗词类的天气海报、情感类的天气海报。 预警海报一般传递的是天气预警的专业信息,也便于用户了解预警详情和防护方法,但画面添加了卡通形象,又给予用户个性化特征。古风诗词类和情感类的海报则是贴合当时天气,借由走心文案帮助用户传递其情绪。当连续阴雨过后天空终于放晴,用户可以通过分享“不曾想雨后的天空会有更多的色彩”的海报文案,表达自己对晴天到来的欣喜。 很多用户,喜欢每天在朋友圈里与好友做一次联系沟通,一张内容普适精致美观的图片就是最好的素材。据墨迹天气的高级产品经理余艳霞称:“类似海报传播的拉新效果较平时提升超过600%。” 这也能归功于分享上的“小心机”,利用走心文案的包装,让用户产生“你懂我”的感觉,从而触发“分享”的行为。 墨迹天气与之前分享的案例不同,它原先就是发展成熟的APP,但它搭建小程序并没有简单地搬迁功能,而是更多地考量小程序所处的微信环境,从而去挖掘用户深层次的需求,包括记录生活、分享给朋友等。 工具类小程序并不适合“闭门造车”,它需要与用户搭建沟通的桥梁,从数据中了解用户的需求,通过功能设置或者文案包装给予用户回应。这样才能占领用户心智,让他们心甘情愿使用你的小程序并将其分享出去。 我们最近新建了个WeGeek技术交流群,欢迎小程序开发同好者进群交流,调戏勾搭群里的云开发大神~

July 4, 2019 · 1 min · jiezi

马蜂窝旅游小程序

前言前段时间学习了关于微信小程序的开发,光说不练假把式,所以就打算自己手撸一个微信小程序,而网上电商类小程序太多了,所以就选择了旅游攻略类小程序来练手。这是我第一次写小程序和第一次写文章,不足之处请多包涵,谢谢。下面我会分享我在写小程序的时候遇到的问题和获得的经验,希望能给你带来帮助,也欢迎大佬指正。最后,我要感谢我在写小程序的时候给我帮助的老师和同学,还有百度上所有给过我帮助的有名的无名的作者。我的废话说完了,先上项目效果图。 开发前的准备微信开发者工具VsCodeEasy Mock项目的所有页面自定义顶部导航栏组件 微信小程序自带的 [顶部导航栏](https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/page.html) 满足不了实际的需求所以就自己写了一个组件,顶部导航栏要想使用 [自定义组件](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/)(链接中详细介绍了关于自定义组件的使用方法)必须把app.json中window属性设置为:"window": { "navigationBarTextStyle": "black",//导航栏标题颜色,仅支持 black / white "navigationStyle": "custom" //导航栏样式,仅支持以下值:default 默认样式custom 自定义导航栏,只保留右上角胶囊按钮 }wxml <view class='nav-wrap' style='height: {{height*2 + 20}}px; background-color:{{navbarData.backgroundColor}};opacity:{{navbarData.opacity}}'> <view style="width:100%;height:100%;"> <!--城市名--> <navigator url="/pages/destination/destination" hover-class="none"> <view class="nav-city" style='margin-top:{{height*2 + 20-36}}px;' wx:if='{{navbarData.showMain}}'> <text>{{navbarData.cityName}}</text> <view class="downtips"></view> </view> </navigator> <navigator url="/pages/search/search" hover-class="none"> <!--搜索框--> <view class="section" style='top:{{height*2 + 20-34}}px;' wx:if='{{navbarData.showMain}}'> // 这里的搜索框不是一个input组件,只是一个view可供点击然后跳到搜索页 <view class='search_icon'> <icon type='search' size='14px'></icon> </view> <view class='placehold'>搜索目的地/景点/攻略</view> </view> </navigator> </view> <!-- 标题 --> <view wx:if="{{navbarData.title!=''}}" class='nav-title' style='line-height: {{height*2 + 44}}px;'> {{navbarData.title}} </view> <!-- 返回上一级按钮 和 返回主页按钮--> <block wx:if="{{navbarData.showCapsule===1}}"> <view class='nav'> <view class='nav_back' bindtap="_navback"> <image src='/images/back.png'></image> </view> <view class="line"></view> <view class='nav_home' bindtap="_backhome"> <image src='/images/home.png'></image> </view> </view> </block></view>组件中的元素都可以通过当前页面传入组件的数据控制显示与否 ...

July 3, 2019 · 8 min · jiezi

微信开发SDK支持小程序让你拥有更简易的API-JeewxApi-131-版本发布

JEEWX-API 是一款JAVA版的微信开发SDK,支持微信公众号、小程序、微信企业号、支付宝生活号SDK和微博SDK。你可以基于她 快速的傻瓜化的进行微信开发、支付窗开发和微博开发。 基于jeewx-api开发,可以立即拥有简单易用的API,让开发更加轻松自如,节省更多时间。一、JEEWX-API 快速集成 引入 Maven 依赖, 在pom.xml 添加jeewx-api 依赖 <dependency> <groupId>org.jeecgframework</groupId> <artifactId>jeewx-api</artifactId> <version>1.3.1</version></dependency>二、升级日志 增加微信图文评论接口增加微信获取接口分析数据接口微信第三方平台接口URL去除空格微信上传其他媒体素材接口修改,兼容缩略图重构maven pom依赖,精简依赖引用Logger日志统一改成slf4j升级依赖版本号 jdom、junit、alipay-sdk-java三、源码下载 https://gitee.com/jeecg/jeewx...https://github.com/zhangdaisc...四、技术交流 快速文档详细API技术官网

July 3, 2019 · 1 min · jiezi

从入门到提高失物招领小程序云开发即时通讯

写在前面本文主要聊聊该项目的云开发技术点和js逻辑,IM即时通讯之后会写。通过本文你将学习微信小程序云函数的使用、组件间通信的各种方法、根据功能需求设计js逻辑、promise相关用法、页面分页加载等。github项目地址 完整效果展示 项目分析本校内已有三个失物招领QQ群,每个群1900+人(包括重复加群),上课期间,每天每个群的信息数99+(包括重复发、图片文字分开发等)。另外,据管理员称,群内虽然少有闲话,但失物的找回率不高,很多同学不知道有信息公告或者因为信息太多而错过了。微信上可搜索到的失物招领小程序有不少,考虑到用户的心理,好心人和失主之间的联系功能,很多平台都是直接展示联系方式,即使有通过学号登录才可查看信息,那也是对用户信息的不负责。基于上述分析,这款小程序的需求:有分类,能搜索,快速发布,即时联系,不用加一堆的群,也不担心错过了信息。明确了需求,我们才能更好的设计代码逻辑,下面开始!发布功能(本地代码)思路分析功能:发表前提醒授权;表单为空不可提交;能多选图片并上传相关内容。困难点:使用promise.all实现先上传图片,拿到图片的云路径后,再将用户输入的发布信息全部上传。实现: 点击"立即发布"按钮后,调用组件inputDetail中的方法checkUploadForm(带参数releaseType,方便后面上传数据是添加到失物招领的found集合还是寻物启事的lost集合),表单内容不为空开始上传;对上传图片的缓存路径执行forEach,将每张图片的缓存路径传递给promise函数promiseUplodImg(函数resolve上传完成后每张图片的云路径)上传图片;同时将每张图片执行的该函数push进一个数组中,再执行promise.all(该方法接收一个每一项都是promise函数的数组);最后,通过.then(接收一个数组,包含所有图片的云路径)将用户输入的信息上传。代码实现// miniprogram/pages/release/release.jsdata: { clickStatus: 0, releaseTypes: ['found', 'lost'], }//立即发布按钮上绑定该方法checkUploadForm: function () { let that = this this.setData({ isUpload: true }) // 声明上传状态 this.inputDetail = this.selectComponent('#inputDetail') this.inputDetail.checkUploadForm(that.data.releaseTypes[that.data.clickStatus])//调用组件inputDetail上的checkUploadForm方法,传参found || lost}// // components/inputDetail/inputDetail.jscheckUploadForm(releaseType) { //releaseType 根据参数确定发布的类型是失物招领还是寻物启事 let that = this let promises = [] if (that.data.releaseText && that.data.thingsType) { that.setData({ releaseType, }) if (that.data.imgLocalPath.length > 0) { wx.showLoading({ title: '正在发布...' }); that.data.imgLocalPath.forEach(element => { promises.push(that.promiseUplodImg(element)) }) // 遍历缓存图片路径,将多个promise函数放入数组promises中 // 拿到所有图片的云路径 Promise.all(promises) .then((imgCloudPath) => { console.log(imgCloudPath); that.uploadRelease(imgCloudPath) }) .catch((err) => { console.log(err); }) } else { //用户没有选择图片,则直接上传发布信息 that.uploadRelease() } } else { wx.showToast({ title: '内容或分类为空', image: '../../asserts/icons/my_icon_still@2x.png', duration: 1800 }) } }, promiseUplodImg(element) { return new Promise((resolve, reject) => { //一次只能上传一张图片到数据库 const filePath = element; let a = filePath.lastIndexOf('.'); let b = filePath.lastIndexOf('.', a - 1); let c = filePath.substring(b + 1, a); const cloudPath = c + filePath.match(/\.[^.]+?$/); wx.cloud.uploadFile({ filePath, cloudPath, success: (res) => { console.log('上传成功', res) resolve(res.fileID) //每张图片的云路径 }, fail: (err) => { console.log('上传失败', err) } }); }) }, uploadRelease(imgCloudPath) { let that = this wx.cloud.callFunction({ name: "uploadInput", data: { releaseType: that.data.releaseType, releaseImg: imgCloudPath, releaseText: that.data.releaseText, thingsType: that.data.thingsType, releaseCall: that.data.releaseCall, releaseRemind: that.data.releaseRemind, //用户输入的全部信息 }, success: () => { wx.hideLoading(); const releaseType = that.data.releaseType wx.switchTab({ url: `/pages/${releaseType}/${releaseType}` }) // 跳转到发布类型对应的页面 wx.hideNavigationBarLoading() }, fail: (err) => { console.log(err); }, complete: () => { that.setData({ releaseText: '', imgLocalPath: [], thingsType: '', releaseCall: '', releaseRemind: false, releaseType: 'found', typeIndex: 0, }) } }) },发布功能(云函数)思路分析功能:调用云函数,将发布内容上传。实现: 使用promise先将发布的信息上传至对应的集合,再将发布记录的id和发布者的openId上传至集合user-release。这样存储便于后面读取数据渲染界面,每一条发布记录的id通过user-release集合与发布者信息绑定在一起。(id是云开发数据库中给每条记录自动生成的_id)数据库记录示例 ...

July 2, 2019 · 4 min · jiezi

微信小程序-乒乓圈-云开发

乒乓圈小程序和朋友合伙写了一个小程序,写了一个以共享乒乓信息和交流的平台———乒乓圈。我们使用了微信的云开发来完成数据和后台的作用。免去了租赁服务器。 首先将github仓库发一份产品源码 我主要负责的是数据库的设计和云函数实现数据获取和触发器的功能和简单的两个页面。 正文功能展示 页面分析引导页当用户未授权则会弹出,点击下方指纹图片,则会弹出授权框,授权后,如果未注册则会注册完毕后进入首页 tabbar中的三个模块三个模块分别为 首页、圈友、个人 模块。 首页的三个功能同城圈-- 同城圈可以看到共享的球馆,点击加号就可共享球馆签到-- 签到规则可以增加积分排行榜-- 可以看积分排行榜 页面流程大致分为 - 引导页 - 首页 - 同城圈 - 打卡 - 榜单 - 圈友页 - 同城圈友 - 留言列表 - 个人页 - 个人资料数据库从以上的功能出发我的数据库设计思路如此对象有以下几个: 个人球馆对话对象就只有大致三个,但是为了数据操作的简便性我将个人的信息分成两个对象表,将留言中的对话又单独放出一张表,所以最后的表有为一下几个: 个人基础信息个人详细信息(乒乓球相关)球馆对话留言信息对象属性的类型选择 首先,小程序提供的数据库是基于mangoDB的面向对象数据库,区别于一般的关系数据库如:mysql等。二者之间的区别和我的理解会写在总结中。 信息是反映对象状态的一种 我认为数据库存储的属性大致可分为三种 基础信息数据-- 是需要存储的基础数据,无需任何处理可直接输出的数据,例如:姓名等功能性数据-- 是可能需要一定处理转变,表示的数据,例如:会员等级(vip,svip)标记型数据-- 是一种特殊的标记,例如:唯一标识符(openId)等但是很多信息都兼顾以上的几种,例如:学号(即是标记型,又是基础信息) 确认完对象基础属性后就要考虑对象之间的关系,例如人和对话,留言和对话信息。关系种类有 一对一(1-1),一对多(1-n),多对多(m-n)。 在 关系数据库 中,一对一的关系只要在一条记录中添加一个属性即可,例如:个人信息和个人详情,在个人详情中添加个人的唯一表示符字段;一对多的关系中需要在多数的记录中添加一个属性,或者单独建立一张表来存储关系,例如:个人和物品,第一种在物品对象中添加一个所有者对象,或者建立一个所属关系表;多对多的关系则只能通过单独一张关系表来完成,例如:学生和课程,需要单独一张选课表来表示关系。 在 面向对象数据库中一对多和多对多的关系可以通过对象中的一个数组字段来完成,例如:学生和课程,在学生对象中添加一个所选课程字段存储课程 ID ,在课程中添加选课学生字段存储学号,就完成了多对多的关系链接。 对象结构如下所示个人基础信息:openId:{type:String}//openId主键name:{type:String}//名字,默认为微信名avatarUrl:{type:String}//头像,默认微信头像context:{type:String,default:"这个人很懒什么都没留下"}//个人简介//以下几项应为流水数据应但对放一张表,在此为图简便放入基础信息表intergal:{type:Number,default:0}//积分 用来排名和升级level:{type:String,default:"新人"}//等级sign:{type:Array,default:[]}//记录打卡签到的日期month:{type:Number}//记录上次打卡签到的月份,用于每月清空签到表个人详情(乒乓球相关)openId:{type:String}//openId主键years:{type:String}//球龄phone:{type:Array}//电话bat:{type:String}//球拍board:{type:String}//底板context:{type:String}//正面胶皮intergal:{type:Number,default:0}//反面胶皮球馆id:{type:String}//主键,由数据库自动生成address:{type:String}//地址arena:{type:String}//所在区域,例如球馆名persons:{type:Array}//球馆的活动者,需求更改数据库中的字段为circlecity:{type:String}//球馆所在的城市img:{type:String}//球馆图片地址latitude:{type:Number}//经度longitude{type:Number}//纬度table:{type:Number}//球桌数time:{type:String}//开放时间对话message:{type:Array,default:[]}//留言内容数组,存储留言的idmy_id:{type:String}//创建者的openIdother_id:{type:String}//接收者的openId留言信息id:{type:String}//主键,由数据库自动生成msg:{type:String}//留言内容my_id:{type:String}//创建者的openIdother_id:{type:String}//接收者的openIdtime:{type:Date}//时间戳云函数读取数据库和部分前端实现1. 引导页当第一次登陆进区就是如上所示,登陆进去后通过 openId 进行云函数获取数据库中个人信息,如果没有则默认进行注册流程。默认昵称为微信昵称(可在个人页更改),头像为微信头像(暂不提供更改),余下都为默认值。引导页 js const QQMapWX = require('../../libs/qqmap-wx-jssdk.js');// 连接腾讯地图const qqmapsdk = new QQMapWX({ key: 'HMGBZ-U5XCX-TUX4Y-ZPUH3-7RRX5-BZBCW'});const app = getApp()Page({ data: { login: false }, getUserInfo(e) { if (e.detail.userInfo && !this.data.login) { console.log('登录中') let the_first = false; // 掉用获取用户信息函数,用openId作为唯一标识符 wx.cloud.callFunction({ name: "getPersonInfo", }) .then(res => { // 判断是否为空,空则代表第一次进入 if (res.result.data.length == 0) { the_first = true } else { // 已经注册过,获取到信息放入 app.globalData 全局数据中。 app.globalData.personInfo = res.result.data[0]; console.log(app.globalData.personInfo); wx.cloud.callFunction({ name: "getpingpang_info", success: res => { console.log('登录成功') // console.log(res.result.data) app.globalData.ping_personInfo = res.result.data[0] wx.setStorage({ key: 'login', data: true }) wx.switchTab({ url: '../home/home', }) } }) } }).then(() => { // 进入注册流程, return new Promise((resolve, reject) => { if (the_first) { // 获取用户的信息 wx.getUserInfo({ lang: "zh_CN", success: res => { app.globalData.userInfo = res.userInfo; resolve(); }, }) } }) }) .then(() => { if (the_first) { // 用户注册所需昵称和头像 const data = { name: app.globalData.userInfo.nickName, avatarUrl: app.globalData.userInfo.avatarUrl, }; // 显示加载 wx.showLoading({ title: '授权登录中', }) // 用户注册函数,除了昵称和头像,全置为最低或空 wx.cloud.callFunction({ name: "pingpang_init", data: data }).then(res => { // 数据库已经注册完成 console.log("注册完成") }) .then(() => { // 注册完成后获取一遍用户信息 wx.cloud.callFunction({ name: "getPersonInfo" }).then(res => { app.globalData.personInfo = res.result.data[0]; console.log(res.result.data[0]) // 隐藏加载 app.globalData.ping_personInfo = { openId: app.globalData.personInfo.openId, phone: '***********', years: '0年', bat: '右手横拍', board: '新手用具', infront_rubber: '新手用具', behind_rubber: '新手用具' } wx.hideLoading(); // 提示注册完成 // wx.showModal({ // title: '注册', // content: '注册完成', // }) wx.setStorage({ key: 'login', data: true }) wx.switchTab({ url: '../home/home', }) }) }) } }) } }, onLoad() { wx.getStorage({ key: 'login', success: (res) => { if (res.data) { this.setData({ login: true }) app.timeout = setTimeout(() => { wx.showLoading({ title: 'lodaing', }) }, 3000) app.neterror = setTimeout(() => { wx.hideLoading() wx.showModal({ title: '伤心提示', content: '网络走丢了...', showCancel: false }) }, 20000) } } }) }})以上流程可分为以下几步。 ...

July 2, 2019 · 7 min · jiezi

码code-9款小程序开源框架和组件库值得收藏

作为一名小程序开发者,面对复杂的代码和运行逻辑,也有更多的需求: 想要一套代码直接跑多端!想要直接套用框架实现开发!想要在小程序内拥有微信同款UI!那就不妨试试小程序开源框架和组件库,开发小程序项目也能变得更加简单,高效。 今天我们收集了些实用的开发框架、组件库以及腾讯官方插件,大家可以了解一下。 开发框架WePy WePy是一款让小程序支持组件化开发的框架,通过预编译的手段让开发者可以选择自己喜欢的开发风格去开发小程序。 特点:相对应的组件库、工具库丰富,也是应用广泛的开发框架。注意一点,由于运行机制的问题,WePy在使用原生小程序组件/库时需要对文档/demo里的源码进行调整。 出品方:微信 案例:腾讯翻译君 腾讯地图+ Github:https://github.com/Tencent/wepy Taro Taro是一套遵循React语法规范的多端开发解决方案,用户可以通过 Taro 的编译工具,将源代码分别编译出可以在不同端运行的代码。 特点:支持包括H5、移动端以及包括微信等4种小程序端,并且有官方维护的跨端 UI 库 和工具库,满足开发者的需求。 出品方:京东 案例:京东购物 程序员英语 Github:https://github.com/NervJS/taro mpvuempvue是一个使用 Vue.js 开发小程序的前端框架。框架基于 Vue.js 核心,mpvue 修改了 Vue.js 的 runtime 和 compiler 实现,使其可以运行在小程序环境中,从而为小程序开发引入了整套 Vue.js 开发体验。 特点:支持vue页转化为包括微信等4种小程序,熟悉 Vue.js 基本语法的开发者便可以简易上手小程序开发,不过目前没有官方的UI组件库。 出品方:美团 案例:美团外卖 享物说 Github:https://github.com/Meituan-Di... Omi Omi 框架是微信支付线研发部研发的下一代前端框架, 基于 Web Components 规范设计的组件化框架,可以开发 PC Web、移动端 H5,也可以直接使用 Omi 开发小程序。 特点:打通小程序端和web端,在小程序也能实现web页面。除了一些平台特有的API,代码几乎不用改动,就能跑在安卓/IOS的小程序里。 出品方:微信 案例:markdown 内容发布系统 Github:https://github.com/Tencent/omi UI组件库WeUI WeUI 是一套同微信原生视觉体验一致的基础样式库,由微信官方设计团队为微信内网页和微信小程序量身设计,令用户的使用感知更加统一。 适用场景:简洁风格的小程序 出品方:微信 案例:微信指数 ...

July 2, 2019 · 1 min · jiezi

微信小程序的jenkins发布构建

原文地址 环境准备微信开发者工具只支持macOS和Windows平台,所以jenkins也只能运行在这两个环境中。现在假设我们已经安装了jenkins,并且配置好了任务,大家可以参考微信小程序集成 Jenkins中的配置教程 配置mini-deploy插件在任务配置页面的 “构建” 中,选择 “执行 shell” ,贴入如下代码。 # 设置yarn源yarn config set registry https://registry.npm.taobao.orgyarn install # 删除构建文件并执行对应scriptsrm -rf dist && yarn run $build_type# 切换为jenkins帐号身份,这样写的原因是机器配置问题,可以忽略su jenkins <<'EOF' if [ "$build_type" == "prod" ] || [ "$build_type" == "build" ] then yarn run deploy --mode=upload --ver=$upload_version --desc=$upload_desc let "result |= $?" if [ "$result" == "0" ] then yarn run notify fielse yarn run deploy --mode=previewfiEOFyarn run notify为内部推送通知脚本yarn run deploy为mini-deploy的脚本,是本地安装调用方式mini-deploy同时也支持全局mini-deploy --workspace=/Users/xxx/WorkSpace/mini --mode=upload,执行时会检查project.config.json文件是否存在。 ...

July 2, 2019 · 1 min · jiezi

微信小程序之列表左滑删除功能

介绍第一次写小程序,记录一下遇到的需求以及解决方法。可能功能不是很难,主要是做下记录。为以后遇到相同的需求做铺垫。什么是左滑删除用过QQ的人都知道,消息列表内,左滑单个聊天可以删除、置顶的操作。对于移动端窄小的屏幕来说,这种交互可以说是非常的节省地方。故受到了众多产品狗的喜爱。 实现原理最外层一个view水平方向排列,里面包含一个内容区view,一个操作区view让你要展示的布局充满屏幕,通过css样式让超出的删除按钮隐藏监听touch事件,平移布局显示和隐藏删除按钮(列表每一项中有一个isTouchMove属性,通过监听touch改变该属性给列表不同的样式将隐藏的按钮显示出来) 直接上代码wxml<view class="list-page"> <view class="list-item {{user.isTouchMove?'list-item-touch-active':''}}" wx:for="{{list}}" wx:for-item="user" wx:for-index="index" wx:key="user.id" bindtouchstart="touchstart" bindtouchmove="touchmove" data-id="{{user.id}}"> <view class="item-content"> <view class="content-name">{{user.name}}</view> <view class="content-info"> <text>{{user.phone}}</text> <text>{{user.sex}}</text> </view> </view> <view class="item-delete">删除</view> </view></view>wxss.list-page{ display: flex; flex-direction: column; border-top: 2rpx solid #f0f0f0}.list-item{ height: 160rpx; width: 100%; display: flex; justify-content: space-between; align-items: center; border-bottom: 2rpx solid #f0f0f0;}.item-content{ width: 100%; height: 100%; display: flex; flex-direction: column; justify-content: center; padding: 0 20rpx 0 20rpx; -webkit-transition: all 0.4s; transition: all 0.4s; -webkit-transform: translateX(180rpx); transform: translateX(180rpx); margin-left: -200rpx;}.content-info{ display: flex; width: 100%; justify-content: space-between; font-size: 32rpx; color: #999}.content-name{ width: 100%;}.list-item-touch-active .item-content{ margin-left: -100rpx;}.list-item-touch-active .item-content, .list-item-touch-active .item-delete { -webkit-transform: translateX(0) !important; transform: translateX(0) !important;}.item-delete{ width: 100rpx; height: 160rpx; display: flex; justify-content: center; align-items: center; background: red; color: #fff; font-size: 32rpx; -webkit-transform: translateX(180rpx); transform: translateX(180rpx); -webkit-transition: all 0.4s; transition: all 0.4s;}js// pages/list/list.jsconst App = getApp()Page({ /** * 页面的初始数据 */ data: { list:[ { id:1, name:'张三', phone:'15955040222', sex:'男', isTouchMove:false, }, { id: 2, name: '张三', phone: '15955040222', sex: '男', isTouchMove: false, }, { id: 3, name: '张三', phone: '15955040222', sex: '男', isTouchMove: false, }, { id: 4, name: '张三', phone: '15955040222', sex: '男', isTouchMove: false, }, { id: 5, name: '张三', phone: '15955040222', sex: '男', isTouchMove: false, }, { id: 6, name: '张三', phone: '15955040222', sex: '男', isTouchMove: false, }, { id: 7, name: '张三', phone: '15955040222', sex: '男', isTouchMove: false, }, ] }, touchstart: function (e) { //开始触摸时 重置所有删除 let data = App.touch._touchstart(e, this.data.list) //将修改过的list setData this.setData({ list: data }) }, //滑动事件处理 touchmove: function (e) { let data = App.touch._touchmove(e, this.data.list,'id')//将修改过的list setData this.setData({ list: data }) },})对于滑动事件的处理专门封装了一个.js文件,防止以后还会用到。var startXvar startYclass touch { constructor() { } _touchstart(e, items) { //开始触摸时 重置所有删除 items.forEach(function (v, i) { if (v.isTouchMove) //只操作为true的 v.isTouchMove = false; }) startX = e.changedTouches[0].clientX startY = e.changedTouches[0].clientY return items } _touchmove(e, items,key) { const id = e.currentTarget.dataset.id, //获取列表中每一项的唯一值,可以取id touchMoveX = e.changedTouches[0].clientX, //滑动变化坐标 touchMoveY = e.changedTouches[0].clientY, //滑动变化坐标 //获取滑动角度 angle = this._angle({ X: startX, Y: startY }, { X: touchMoveX, Y: touchMoveY }); items.forEach(function (v, i) { v.isTouchMove = false //滑动超过30度角 return if (Math.abs(angle) > 30) return; if (v[key] == id) { //判断滑动的id与列表中的id是否一致,如果是的话,改变滑动这一项的isTouchMove属性 if (touchMoveX > startX) //右滑 v.isTouchMove = false else //左滑 v.isTouchMove = true } }) return items } _angle(start, end) { var _X = end.X - start.X, _Y = end.Y - start.Y //返回角度 /Math.atan()返回数字的反正切值 return 360 * Math.atan(_Y / _X) / (2 * Math.PI); }}export default touch然后去引用这个touch.js文件,在app.js文件中//app.jsimport touch from './utils/touch.js'//新加App({ globalData: { userInfo: null }, touch: new touch() //实例化这个touch对象})末尾到这里左滑删除就告一段落了,主要就是先使用css将删除按钮隐藏起来,然后通过监听touch事件去改变列表中每一项的一个属性,间接修改这个条目的样式将删除按钮显示出来源码上传至github 微信小程序之列表左滑删除功能原文地址 微信小程序之列表左滑删除功能

July 1, 2019 · 2 min · jiezi

微信小程序版本自动更新

说明1: 当用户点击左上角关闭,或者按了设备Home 键离开微信,小程序并没有直接销毁,而是进入了后台;当再次进入微信或再次打开小程序,又会从后台进入前台,只有当小程序进入后台一定时间,或者系统资源占用过高,才会被真正的销毁。 2: 小程序的启动分为"冷启动" 和 "热启动".热启动是指: 小程序打开后,在一段时间内(目前:5分钟)再次被打开,此时会将后台的小程序切换到前台。冷启动是指: 小程序首次打开或销毁后再次被打开 3: 更新版本冷启动时, 如果发现有新版本,将会异步下载新版本的代码包,并同时用客户端本地的包进行启动,即新版本的小程序需要等下一次冷启动才会应用上。如果要马上应用最新版本,使用 wx.getUpdateManager API 进行处理。。 完整代码onLaunch(){ if (wx.canIUse('getUpdateManager')) { const updateManager = wx.getUpdateManager() updateManager.onCheckForUpdate(function (res) { if (res.hasUpdate) { updateManager.onUpdateReady(function () { wx.showModal({ title: '更新提示', content: '新版本已经准备好,是否重启应用?', success: function (res) { if (res.confirm) { updateManager.applyUpdate() } } }) }) updateManager.onUpdateFailed(function () { wx.showModal({ title: '已经有新版本了哟~', content: '新版本已经上线啦~,请您删除当前小程序,重新搜索打开哟~' }) }) } }) } else { wx.showModal({ title: '提示', content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。' }) } }补充文章首发于微信小程序版本自动更新

July 1, 2019 · 1 min · jiezi

监控微信小程序wxrequest请求失败

在微信小程序里,与后台服务器交互的主要接口函数是wx.request(),用于发起 HTTPS 网络请求。其重要性不言而喻。然而,却经常遇到请求失败的问题,笔者特意谷歌"wx.request 请求失败",可以搜索到很多相关的文章,下面列出一些: wx.request 失败| 微信开放社区微信小程序 wx.request 请求失败- SegmentFault 思否小程序部分机型小程序用户无法发起 wx.request 请求,网络错误问题 ...wx.request()失败,request:fail。_微信小程序开发request:fail 合集(各种 request:fail 问题)微信小程序之 wx.request:fail 错误排查- 简书有些事开发时候遇到,有些是产品上线后遇到。线上的情况比开发和测试的时候复杂的多,失败的原因可能各种各样。既然测试无法 100%保证上线不会出问题,我们唯一要做的就是及时发现和快速响应。 微信小程序运维中心提供了错误日志记录,但功能还是比较有限。只有简单的统计和错误展示功能,而往往仅仅靠报错信息是无法清晰理解错误成因的。这个时候使用强大的第三方监控服务就很有必要了。 小程序 Demo我们使用一款由jectychen开发的wechat-v2ex来做演示,v2ex 数据 api 基本上使用了 samuel1112 的仓库v2er里封装的方法。 其运行效果如下: 最左侧本来应该有头像的,可能由于防盗链的原因没有显示出来。 有时候一个微信小程序可能会用到多个第三方服务,从多个域名获取数据。以下两种情况都值得注意: 某些接口做了更新没有及时推送通知,该接口的调用就会失败;服务不够稳定,接口的返回某一时段特别慢;某些终端用户的数据不符合导致接口失败。因此产品上线以后,对接口的调用进行监控是很有必要的。 接入监控Fundebug 的微信小程序错误监控插件支持监控 HTTP 请求错误: 当请求返回的 statusCode 不是 2xx 或者 fail 回调函数被触发的时候,Fundebug 的小程序监控插件会捕获该错误并发送到服务器。如果接口请求耗时过长,我们也可以配置httpTimeout来监控。要使用 Fundebug 监控,你需要去Fundebug网站注册账号并创建一个微信小程序监控项目,然后按照提示接入插件。你需要下载微信小程序监控的 JS 脚本放入到自己的项目中,然后引入并通过fundebug.init()函数作必要的配置。 var fundebug = require("./utils/fundebug.1.3.1.min.js");fundebug.init({ apikey: "YOUR-API-KEY", monitorHttpData: true, httpTimeout: 2000, monitorMethodCall: true, monitorMethodArguments: true, setSystemInfo: true, setUserInfo: true, setLocation: true});插件默认会监控 HTTP 请求错误,并上报 Header 部分的信息,我们无需做配置。为了方便 Debug,我们配置monitorHttpData来记录 body 部分的信息;我们将httpTimeout设置为 2000 毫秒,超过该时长的请求会被上报到服务器。 ...

July 1, 2019 · 1 min · jiezi

微信小程序之自定义倒计时组件

开头最近写小程序写上瘾了,业务上需要实现一个倒计时的功能,考虑到可拓展以及使用方便,便将其封装成组件(写习惯了JSX不得不吐槽小程序自定义组件的繁琐)需求可配置倒计时的时间倒计时结束后执行事件可配置倒计时时间的格式步骤先定义自定义组件的properties,这里有两个父组件传给该倒计时组件的参数target倒计时的时间,format倒计时时间的格式properties: { target: { type: String, }, format: { type: Function, default: null }},定义组件生命周期函数lifetimes: { attached() { //组件创建时 this.setData({ lastTime: this.initTime(this.properties).lastTime, //根据 target 初始化组件的lastTime属性 }, () => { //开启定时器 this.tick(); //判断是否有format属性 如果设置按照自定义format处理页面上显示的时间 没有设置按照默认的格式处理 if (typeof this.properties.format === 'object') { this.defaultFormat(this.data.lastTime) } }) }, detached() { //组件销毁时清除定时器 防止爆栈 clearTimeout(timer); },},微信小程序自定义组件的生命周期指的是指的是组件自身的一些函数,这些函数在特殊的时间点或遇到一些特殊的框架事件时被自动触发。其中,最重要的生命周期是 created attached detached ,包含一个组件实例生命流程的最主要时间点。具体微信自定义组件学习参考官方文档定义组件自身的状态/** * 组件的初始数据*/data: { d: 0, //天 h: 0, //时 m: 0, //分 s: 0, //秒 result: '', //自定义格式返回页面显示结果 lastTime:'' //倒计时的时间错},组件自身的方法methods: { //默认处理时间格式 defaultFormat: function(time) { const day = 24 * 60 * 60 * 1000 const hours = 60 * 60 * 1000; const minutes = 60 * 1000; const d = Math.floor(time / day); const h = Math.floor((time - d * day) / hours); const m = Math.floor((time - d * day - h * hours) / minutes); const s = Math.floor((time - d * day - h * hours - m * minutes) / 1000); this.setData({ d, h, m, s }) }, //定时事件 tick: function() { let { lastTime } = this.data; timer = setTimeout(() => { if (lastTime < interval) { clearTimeout(timer); this.setData({ lastTime: 0, result: '' }, () => { this.defaultFormat(lastTime) if (this.onEnd) { this.onEnd(); } } ); } else { lastTime -= interval; this.setData({ lastTime, result: this.properties.format ? this.properties.format(lastTime) : '' }, () => { this.defaultFormat(lastTime) this.tick(); } ); } }, interval); }, //初始化时间 initTime: function(properties) { let lastTime = 0; let targetTime = 0; try { if (Object.prototype.toString.call(properties.target) === '[object Date]') { targetTime = Number(properties.target).getTime(); } else { targetTime = new Date(Number(properties.target)).getTime(); } } catch (e) { throw new Error('invalid target properties', e); } lastTime = targetTime - new Date().getTime(); return { lastTime: lastTime < 0 ? 0 : lastTime, }; }, //时间结束回调事件 onEnd: function() { this.triggerEvent('onEnd'); } }defaultFormat :默认时间处理函数 tick:定时事件 initTime 初始化时间onEnd:时间结束的回调倒计时组件countDown.js完整代码var timer = 0;var interval = 1000;Component({ /** * 组件的属性列表 */ properties: { target: { type: String, }, format: { type: Function, default: null } }, lifetimes: { attached() { //组件创建时 this.setData({ lastTime: this.initTime(this.properties).lastTime, //根据 target 初始化组件的lastTime属性 }, () => { //开启定时器 this.tick(); //判断是否有format属性 如果设置按照自定义format处理页面上显示的时间 没有设置按照默认的格式处理 if (typeof this.properties.format === 'object') { this.defaultFormat(this.data.lastTime) } }) }, detached() { //组件销毁时清除定时器 防止爆栈 clearTimeout(timer); }, }, /** * 组件的初始数据 */ data: { d: 0, //天 h: 0, //时 m: 0, //分 s: 0, //秒 result: '', //自定义格式返回页面显示结果 lastTime:'' //倒计时的时间错 }, /** * 组件的方法列表 */ methods: { //默认处理时间格式 defaultFormat: function(time) { const day = 24 * 60 * 60 * 1000 const hours = 60 * 60 * 1000; const minutes = 60 * 1000; const d = Math.floor(time / day); const h = Math.floor((time - d * day) / hours); const m = Math.floor((time - d * day - h * hours) / minutes); const s = Math.floor((time - d * day - h * hours - m * minutes) / 1000); this.setData({ d, h, m, s }) }, //定时事件 tick: function() { let { lastTime } = this.data; timer = setTimeout(() => { if (lastTime < interval) { clearTimeout(timer); this.setData({ lastTime: 0, result: '' }, () => { this.defaultFormat(lastTime) if (this.onEnd) { this.onEnd(); } } ); } else { lastTime -= interval; this.setData({ lastTime, result: this.properties.format ? this.properties.format(lastTime) : '' }, () => { this.defaultFormat(lastTime) this.tick(); } ); } }, interval); }, //初始化时间 initTime: function(properties) { let lastTime = 0; let targetTime = 0; try { if (Object.prototype.toString.call(properties.target) === '[object Date]') { targetTime = Number(properties.target).getTime(); } else { targetTime = new Date(Number(properties.target)).getTime(); } } catch (e) { throw new Error('invalid target properties', e); } lastTime = targetTime - new Date().getTime(); return { lastTime: lastTime < 0 ? 0 : lastTime, }; }, //时间结束回调事件 onEnd: function() { this.triggerEvent('onEnd'); } }})倒计时组件countDown.wxml完整代码<wxs src="../wxs/utils.wxs" module="utils" /><wxs src="../../comm.wxs" module="comm" /><view class="count-down"> <text wx:if="{{result!==''}}">{{result}}</text> <block wx:else> <text wx:if="{{comm.numberToFixed(d)>0}}">{{d}}天</text> <text>{{utils.fixedZero(h)}}</text> <text style="font-weight: 500">:</text> <text>{{utils.fixedZero(m)}}</text> <text style="font-weight: 500">:</text> <text>{{utils.fixedZero(s)}}</text> </block></view>其中引入了两个wxs文件中的函数 WXS(WeiXin Script)是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构。官方文档function fixedZero(val) { return val * 1 < 10 ? '0' + val : val;}//保留 pos位小数function numberToFixed(number, pos) { if (number === null || number === '' || number < 0) return '' return parseFloat(number).toFixed(pos)}组件使用引入方式"usingComponents": { "countDown": "../../../components/countDown/countDown" },代码演示 <countDown bind:onEnd="getPageList" format="{{formatTime}}" target="{{creatTargetTime}}" />const formatChinaDate = mss => { let days = parseInt(mss / (1000 * 60 * 60 * 24)); let hours = parseInt((mss % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); let minutes = parseInt((mss % (1000 * 60 * 60)) / (1000 * 60)); let seconds = parseInt((mss % (1000 * 60)) / 1000); return days + ' 天 ' + hours + ' 小时 ' + minutes + ' 分钟 ' + seconds + ' 秒 ';};data:{ formatTime:formatChinaDate, creatTargetTime:1556428889000, //时间戳}getPageList:function(){ //倒计时结束啦 console.log('倒计时结束啦')}API参数说明类别默认值format时间格式化显示Function(time)x天00:00:00target目标时间Date onEnd倒计时结束回调funtion 补充文章首发于:微信小程序之自定义倒计时组件

June 30, 2019 · 4 min · jiezi

微信小程序奔跑吧

前言学习(入坑)前端想来已有三个月了,学习总是枯燥乏味的,写代码更是如此。但是,曾记否?高中时候的你可以因为解出了一道困扰了你几日的数学题而高兴一整天。在程序员的世界里,我想,没有比做出一个项目更开心的了。 是的,此前微信小程序学习了近一个月后,仿着APP-运动世界校园写了一个微信小程序奔跑吧(取名为这个是因为看到跑步第一时间就想到了奔跑吧,兄弟)。其实我觉得自己写的这个项目着实不能称得上是一个项目,因为它只实现了原APP的一小部分功能,写得实在是简陋,要想完美,果然还是得一个团队写。好了,话不多说,我们言归正传。 这里先贴一个github地址:奔跑吧 里面有所有的源码。项目展示 使用工具及开发前准备微信开发者工具+VScodeVant-weapp+Tencent/weui-wxssiconfont+网上图片资源小程序云开发的数据库、存储及云函数微信小程序官方文档+Vant官方文档+weui官方文档网易云音乐 NodeJS 版 API项目结构大体结构页面路径、页面的窗口表现、底部 tab "pages": [ "pages/run/run", "pages/map/map", "pages/chat/chat", "pages/mine/mine", "pages/music/music", "pages/share/share", "pages/play/play" ], "window": { "backgroundColor": "#F6F6F6", "backgroundTextStyle": "light", "navigationBarBackgroundColor": "#00B26A", "navigationBarTitleText": "奔跑吧", "navigationBarTextStyle": "white" }, "tabBar": { "color": "#B5B5B5", "selectedColor": "#1296DB", "list": [ { "text": "运动", "pagePath": "pages/run/run", "iconPath": "images/run.png", "selectedIconPath": "images/run-active.png" }, { "text": "动态", "pagePath": "pages/chat/chat", "iconPath": "images/chat.png", "selectedIconPath": "images/chat-active.png" }, { "text": "我的", "pagePath": "pages/mine/mine", "iconPath": "images/mine.png", "selectedIconPath": "images/mine-active.png" } ] },不得不说微信小程序的tabBar是真的好用,不用写一句js逻辑就可以轻松实现。 ...

June 28, 2019 · 7 min · jiezi

监控微信小程序中的慢HTTP请求

摘要: 请求时间太长,影响用户体验,使用 Fundebug 监控慢请求。 Fundebug 的微信小程序监控插件在 0.5.0 版本已经支持监控 HTTP 请求错误,在小程序中通过wx.request发起 HTTP 请求,如果请求失败,会被捕获并上报。时隔一年,微信小程序插件已经更新到 1.3.1, 而且提供了一个非常有用的功能,支持监控 HTTP 慢请求。对于轻量级的性能分析,可以说已经够用。 本文我们以一个天气微信小程序为例(由bodekjan开发),来演示如何监控慢请求。bmap-wx.js中的weather()函数调用百度地图小程序 api 提供的接口来获取天气预报信息。 接入监控由于使用百度的 api,我们无法确认该接口的稳定性,可能有时候会特别慢,导致天气信息显示不出来。于是,我们使用 Fundebug 来监控请求过慢的情况。接下来,我们来演示如何监控慢请求。注册账户后,记得要在创建项目是选择“微信小程序”这一项目类型。 根据指示完成接入流程: 在app.js顶部加入下面的代码(记得将 apikey 替换成你自己的): var fundebug = require("./utils/fundebug.1.3.1.min.js");fundebug.init({ apikey: "YOUR-API-KEY", monitorMethodCall: true, monitorMethodArguments: true, monitorHttpData: true, setSystemInfo: true, setUserInfo: true, setLocation: true, httpTimeout: 200});虽然init()函数只要设置apikey即可使用,但是为了最大程度发挥监控的威力,我们不妨多设置一些监控选项。微信小程序插件有很多的可配置项,由于涉及到数据,默认处于关闭状态。我们可以监控函数调用(monitorMethodCall),以及函数调用的参数(monitorMethodArguments),监控 HTTP 请求的 Body 中的数据(monitorHttpData),获取系统信息(setSystemInfo)、用户信息(setUserInfo)、地理位置(setLocation)。 监控慢请求最后,最重要的一步,配置httpTimeout来监控超过特定时长的请求,httpTimeout 类型为 Number,单位为毫秒(ms)。演示起见,我们将时间设置为 200 毫秒。 在微信开发者工具内运行代码,Fundebug 立马收到报错。小程序发往https://api.map.baidu.com/telematics/v3/weather接口的请求时长为 571ms,超过预设时间 200ms。 错误详情该请求返回代码 200,表明能够正常获取数据。点击该条错误,查看错误详情: ...

June 27, 2019 · 1 min · jiezi

微信小程序数据统计和错误统计的实现

某些情况下我们需要对小程序某些用户的行为进行数据进行统计,比如统计某个页面的UV,PV等,统计某个功能的使用情况等。好让产品对于产品的整个功能有所了解。在网页里,我们很多人都用过谷歌统计,小程序里也有一些第三方数据统计的库, 比如腾讯的MTA等等。但是,第三方的数据统计库要么功能太简单,满足不了需求,要么就是要收费。(留下了贫穷的泪水。)等等,又不是你出钱,怕啥? 贵一点就贵一点呀。 嗯,说的没错。但是,公司团队内部想实现一套完整的自己的数据统计系统以满足自己的需求。所以,还是没有用第三方的。 所以,具体要统计些啥? 产品经理想知道用户都是怎么进入我们的小程序的?用户在我们小程序里那个页面停留的时间最长?平均用户停留时间是多少?想知道我们最近开发的那个功能用的人多不多?想统计小程序里的一些按钮有多少用户点击了开发自己总是很难复现用户端出现的bug,要是可以知道用户端发生错误时,知道用户当时的用的手机型号,微信版本,网络环境,页面参数,和错误信息就好了想知道我们小程序启动时间是多少?接口在用户端的平均响应时间是多少ms? 哪些接口报错了针对产品经理的需求,我们可以知道,Ta想要的是就是数据统计要实现的功能。对于开发来说,我们关注的更多就是错误统小程序性能这块的东西。 好,到这里,我们需求是明白了。就是要实现一套既能统计普通的埋点数据,也要能统计到小程序里一些特殊触发的事件,比如appLaunch, appHide 等,还要可以统计错误。 好,那先来看看如何实现产品的需求吧 用户进入小程序可以在 小程序 onLaunch 回调里拿到参数 的scene 值,这样就可以知道用户是怎么进入小程序的了。小case, 难不到我。 嗯,第一个需求实现了,那如何统计第二个呢?如何统计某个页面的停留时间呢? 这也难不倒我,用户在进入页面时会触发onShow 事件, 同样,在离开页面(或者切后台时)会触发onHide事件,我只需要在onShow里记录一下时间,同时在onHide 里也记录一下时间,把两个时间一减就可以了。 Page({ data: { beginTime: 0, endTime: 0 }, onShow: function() { // Do something when page show. this.setData({ beginTime: new Date().getTime() }) }, onHide: function() { // Do something when page hide. let stayTime = new Date().getTime() - this.beginTime; // 这个就是用户在这个页面的停留时间了 }, })等等,这样确实实现了需求,万一产品要统计所有也面的停留时长? 那我们岂不要在每一个页面都这样写一遍?有没有更好的方法呢? ...

June 26, 2019 · 3 min · jiezi

微信小程序全局样式无法作用于自定义组件的解决办法

在组件中加入以下代码: Component({ options: { addGlobalClass: true }})

June 24, 2019 · 1 min · jiezi

微信小程序自定义组件boundingClientRect获取到的rect值为null

解决办法: 在自定义组件内获取必须用SelectorQuery.in() Component({ lifetimes: { ready() { const query = wx.createSelectorQuery().in(this) const num = Math.ceil(this.data.picList.length / LINE_LENGTH) query.select('.tab-content-item').boundingClientRect((rect) => { this.setData({ swiperHeight: rect.height * num + 'rpx' }) }).exec() } },})const query = wx.createSelectorQuery().in(this)这一句是最重要的,要用.in(this),this传入的是自定义组件的实例。否则获取到的rect值为null

June 21, 2019 · 1 min · jiezi

小程序生成海报代码分享

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

June 20, 2019 · 1 min · jiezi

微信小程序线上更新版本流程及如何运用

1.1 小程序官方文档:(1)小程序线上版本更新官方文档(updateManager对象管理线上版本更新):https://developers.weixin.qq....(2)小程序强制更新:https://developers.weixin.qq.... 2.1 参考博客:微信小程序版本自动更新:https://www.jianshu.com/p/4f5... 3.1 关键知识点:(1)小程序热启动(2)小程序冷启动(3)updateManager对象(4)利用wx.canIuse( )方法判断getUpdateManger(5)UpdateManager.onCheckForUpdate(function callback)回调函数监听是否后台有更新版本(6)UpdateManager.onUpdateReady(function callback)监听版本成功下载后利用UpdateManager.applyUpdate()重启小程序(7)UpdateManager.onUpdateFailed(function callback)监听版本更新失败后的回调(8)微信小程序在冷更新并且有新版本的情况下才能重启 4.1 下图是更新的流程: 5.1 代码展示: if (wx.canIUse('getUpdateManager')) { const updateManager = wx.getUpdateManager() console.log(updateManager); updateManager.onCheckForUpdate(function (res) { // 请求完新版本信息的回调 console.log(res); if (res.hasUpdate) { updateManager.onUpdateReady(function () { wx.showModal({ title: '更新提示', content: '新版本已经准备好,是否重启应用?', success: function (res) { // res: {errMsg: "showModal: ok", cancel: false, confirm: true} if (res.confirm) { // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启 updateManager.applyUpdate() } } }) }) updateManager.onUpdateFailed(function () { // 新的版本下载失败 wx.showModal({ title: '已经有新版本了哟~', content: '新版本已经上线啦~,请您删除当前小程序,重新搜索打开哟~' }) }) } }) }5.1 模拟更新版本:第一步:点击普通编译并添加编译模式 ...

June 14, 2019 · 1 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

Fundebug-微信小程序BUG-监控插件更新至-131支持监控-HTTP-慢请求

摘要: 1.3.1新增 httpTimeout 配置选项,支持监控 HTTP 慢请求,同时修复了记录的 HTTP 响应时间偏小的 BUG。 Fundebug是专业微信小程序 BUG 监控服务,可以第一时间捕获线上环境中小程序的异常、错误或者 BUG,及时给开发者推送报警,帮助您快速修复 BUG。 Fundebug的微信小程序BUG监控插件更新至1.3.1,新增httpTimeout配置选项,支持监控 HTTP 慢请求,同时修复了记录的 HTTP 响应时间偏小的 BUG,请大家及时更新! 监控 HTTP 慢请求Fundebug 专注于 BUG 监控,暂时无意于提供全面的性能监控服务。但是,当 HTTP 请求过慢,导致用户体验很糟糕时,也可以理解为一种广义的 BUG。HTTP 请求的性能问题,可能是代码的算法不够好导致的,有可能是数据库的索引不合理导致的,还有可能是其他原因,这些都是技术层面的”BUG“,需要开发者及时处理。 当然,监控所有 HTTP 请求的响应时间不是我们 Fundebug 需要做的事情,因此我们只支持监控慢请求。用户只需要配置一个阈值httpTimeout,所有响应时间超过阈值的 HTTP 请求都会上报的 Fundebug,这样可以帮助开发者发现一些慢请求,及时优化性能。 微信小程序配置选项 networktimeout根据微信小程序的开发文档,网络请求的默认超时时间是 60s,用户可以通过配置networktimeout来自定义。如果某个 HTTP 请求的响应时间超过这个阈值的话,则该请求会出错,Fundebug 也会上报这个超时错误。但是,networktimeout 不能配置的太低,否则超时的请求都会失败,这并不合理。所以配置 networktimeout 并不能实现监控 HTTP 慢请求的目的。 httpTimeout监控 HTTP 慢请求的正确方式是通过 Fundebug 的配置选项httpTimeout来实现。 httpTimeout 类型为 Number,单位为毫秒(ms)。 如果你希望监控较慢的 HTTP 请求,则可以通过httpTimeout配置阈值,比如 1000: fundebug.init({ httpTimeout: 1000});则所有响应时间超过 1000ms 的请求都会上报到 Fundebug。 ...

June 12, 2019 · 1 min · jiezi

微信小程序开发中遇到的问题及解决办法三

大纲:根据近期我在小程序开发中接到的需求,总结一下下面四个开发需求所遇到的问题: 1、关于微信现已开放小程序内搜索(sitemap 配置);2、微信小程序的激励视频广告接入;3、页面路由带的参数如果是布尔类型处理注意问题及处理;4、微信小程序中的函数节流; 接下来就是详情: 一、关于微信现已开放小程序内搜索;如果对于这个功能一无所知的老铁,可以先看看官方的声明:1、收录设置功能说明及详情;2、微信“小程序搜索”功能服务使用须知; 说明:开发这个功能,主要是让小程序直接能在搜索栏中直接搜到对应的小程序页面,增加自己的小程序的曝光量。资料整理:1、关于sitemap配置;2、微信小程序页面seo;附:关于微信搜索小程序内页面的功能,只能在线上环境有用,而且没有提供测试的渠道。 二、微信小程序激励视频广告接入1、微信视频广告指引;截图:具体使用:注意:1、激励视频广告组件是一个原生组件,层级比普通组件高。激励视频广告是一个单例(小游戏端是全局单例,小程序端是页面内单例,在小程序端的单例对象不允许跨页面使用),默认是隐藏的,需要调用 RewardedVideoAd.show() 将其显示;2、通过wx.createRewardedVideoAd(Object object)创建的视屏组件,小程序中是一个页面内的单例。由于广告对象是单例,且仅对单个页面有效,建议开发者在页面加载后(onLoad生命周期)创建一个广告位,并且在这个页面的生民周期内重复调用该广告对象;3、如果是在组件中使用视频组件,当前页面也创建了视频组件,视频组件的公共方法会相互影响;4、在激励视频广告创建后,组件会拉去一次广告,用户点击关闭广告后会拉去下一条广告,我们可以监听组件事件onLoad判断是否展示广告入口; 三、页面路由带的参数如果是布尔类型处理注意问题及处理;页面参数如果这样传:isRed是布尔类型(true|false),如果在页面获取这个参数的时候,记得处理一下,因为不管isRed=true或者false,页面参数options获取的都是字符串类型,可以通过这样,来获取它的值: let isRed = options.isRed=="true"四、微信小程序中的函数节流1、什么是函数节流?答: 当持续触发事件时,保证一定时间段内只调用一次事件处理函数。2、我的应用场景?答:比如点击签到、观看完视频广告,点击关闭按钮获取奖励或者是参与抽奖获取奖励……开发中遇到的问题:前端没有对高频请求做处理,用户在弱网或者飞行模式下,短时间内能多次快速点击请求,获取多次奖励;解决办法:添加简单节流处理:说明:我这里讲的只是前端我使用的处理办法,最好的办法还是交个后端同学来处理高频请求问题,因为如果这样添加,前端代码会有更多冗余代码,节流的时间间隔也不好控制,也显得不友好。 随记:接下来,小程序项目要告别一段时间做pc端项目了;接下来,要去见见不一样的自己了~

June 10, 2019 · 1 min · jiezi

码code-关于小程序云开发你想知道的这里都有

对于想要开发一个实现简单功能的小程序的开发者来说,总会绕不开搭建服务器的难题,往往需要他们花费精力进行后端基础设施建设及维护。 小程序·云开发的出现,则可以帮助开发者们跳开这一环节,无需搭建服务器便能实现开发。 本次分享是通过实战项目“名片小程序”的开发,讲解云开发的功能与开发优势,为开发者提供提高开发效率的方法与灵感。 云开发的特点及优势小程序·云开发是腾讯云为移动开发者提供的一站式后端云服务,它帮助开发者统一构建和管理资源,免去了移动应用开发过程中繁琐的服务器搭建及运维、域名注册及备案、数据接口实现等繁琐流程。 在传统开发模式中,开发者需要从小程序端通过额外引用的SDK请求后端,需要关心弹性伸缩、异地容灾、网络防护、安全加固等众多条件。 相比而言,云开发模式中,开发者从小程序端通过小程序原生接口请求云开发即可。 云开发三大能力的功能介绍目前『云开发』 提供了三大基础能力支持,分别是云数据库、存储及云函数。 云数据库文档型数据库包含多个近似于JSON数组的集合,数组中的对象是记录,格式为 JSON 文档。简单易用:数据库 API 包含增删改查,操作简单;支持触发器,满足特殊场景。权限控制:通过 API 在客户端内和云函数内进行数据操作,安全可靠。 云存储快速上传:提供文件存储空间,可在客户端和云函数端通过 API 使用存储。权限管理:基于用户身份的安全控制,带权限管理的云端下载。CDN 加速:存储内的文件,天然 CDN 加速,提升用户体验。 云函数云端运行:无需采购、部署、运维传统硬件,节约人力及成本。高效开发:每个函数单独运行、部署,上传代码后即可自动部署,提升了独立开发和迭代的速度。弹性伸缩:根据请求量实现毫秒级实时弹性伸缩,函数未执行不产生任何费用。云调用:在云函数中使用云调用调用微信开放能力,无需换取access_token。本地调试:云开发提供了云函数本地调试能力,方便开发者在本地进行云函数调试。 云开发操作介绍新建云函数在微信开发者工具中上传云函数代码,并进行函数配置的修改。 创建数据库添加集合,并对记录列表、索引管理、权限设置进行添加调整。 管理存储上传文件至云端,方便在小程序端和云函数端通过API使用云文件存储。 云开发项目实战为了让读者更好地了解云开发的使用操作,我们将推出“AI智能名片识别小程序”项目实战的直播课程。课程内容会从小程序·云开发的三大基础能力出发,并围绕“利用云开发插入、读取数据”“利用云开发上传图片”“学习如何使用在云开发上实现名片识别逻辑”这三个知识点具体讲解。 本次直播课程将于6月13日20:00-21:00在微信群进行分享,并提供在线直播答疑和日常技术交流。欢迎各位感兴趣的开发者们扫下方二维码,添加小助手进群。 了解更多小程序开发相关内容,欢迎微信扫描下方二维码关注「微信极客WeGeek」公众号,共筑微信生态。

June 10, 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

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

 小程序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

JAVA免费微信管家系统JeeWx-41-版本发布微信砍价活动闪亮登场

JEEWX 从4.0版本开始,技术架构全新换代更名“捷微H5”。这是一款开源免费的微信运营平台,是jeewx的新一代产品,平台涵盖了:微信公众号管理、各种微信活动、小程序、微网站、微商城、分销商城、小程序商城、小程序网站、砍价、投票、会员等等功能,是一套成熟的互联网运营产品。架构层面,采用JAVA语言,具备更高的并发能力和大数据能力,采用微服务架构,插件式开发模块化、UI体验更好;另外强大的代码生成器,显著提高开发效率,便于用户二次开发;最大的优势:插件模式,每个功能模块以插件方式提供,方便插拔集成,个性化定制。一、升级日志本版本4.0是大换代版本,采用微服务架构,全部功能重写,此版本开启插件服务模式1、新增活动:微信新年砍价;2、提供全新录制教学视频;3、提供最新的使用文档;4、修改域名变更,属性文件读取失败等问题;5、修改删除一级菜单,子菜单未跟着删除问题;6、重置token,增加redis未配置提示;7、九宫格、水果机,新增项目说明文档,本地测试地址;二、平台功能介绍【微信公众号】 1、微信账号管理2、微信菜单管理(支持小程序链接)3、关注欢迎语4、关键字管理5、文本素材管理6、图文素材管理7、强大的图文编辑器(支持素材选择)8、粉丝用户管理9、粉丝同步功能10、接受消息功能11、Oauth2.0链接12、微信第三方平台(全网发布)13、系统用户管理14、系统角色管理15、系统菜单管理16、项目logo设置17、活动插件管理【微信活动】 1、九宫格2、摇一摇3、微砍价三、项目介绍捷微 - H5活动源码列表(陆续更新..) 1.微信公众号管理 P3-Biz-commonweixin2.摇一摇送卡券 P3-Biz-shaketicket3.九宫格活动 P3-Biz-jiugongge4.新年砍价 P3-Biz-gzbargain5.启动项目 P3-Web四、开发入门 1.Eclipse + Maven + JDK7 2.项目以Maven方式导入eclipse 3.初始化数据库脚步 P3-Web\doc\db\jeewx-h5-mysql-20180810.sql 4.采用maven方式,启动主项目P3-Web,命令:tomcat:run 活动访问地址: http://localhost/jeewx 说明:插件不能单独启动,maven方式引入到Web项目 5.系统默认登录账号 admin/123456 五、下载地址源码下载: https://gitee.com/jeecg/h5huo... 官方网站: htttp://www.jeewx.com QQ技术群: 97460170 体验公众号: 六、系统演示 捷微H5活动平台(管理后台) 捷微H5活动平台(H5微信活动)1.砍价活动-效果图 2.九宫格活动-效果图 3.斧头帮砍价-效果图 4.摇一摇送卡券-效果图

June 7, 2019 · 1 min · jiezi

微信小程序上传文件小结

前言后端用的是Rails ActiveStorage direct_upload的处理方式, 前端被要求: 提供文件的MD5-Base64校验值,获得上传地址;将文件上传到上述指定地址(此处会校验文件的MD5-Base64值是否与上一步给的一致);将文件的signed_id作为文件参数。相关知识因为目前开发任务重且紧,暂时略过此部分,只记录结论要点,后续有时间再补充相关知识 要点小结3.0 上传文件(后端 Rails: activeStorage)Step 1: 计算文件MD5-Base64摘要小程序中前端无法获取文件的Binary格式,因此无法自行或使用第三方库来计算文件的MD5值,但幸运的是,小程序也提供了API来做这件事,请使用:wx.getFileInfo将获得的MD5值转为Base64格式。可使用此项目中utils/base64.js的encode方法,该方法适用于转换字符串。也可使用CryptoJS库,需要注意的是,CryptoJS.enc.Base64.stringify需要的参数是WordArray格式,不能直接传String,要先用CryptoJS.enc.Utf8.parse转换一下字符串Step 2: 上传文件到上一步返回的指定direct_upload地址小程序前端无法直接获得文件的Binary格式传给后端,但可以通过wx.uploadFile上传文件,通过此接口发送请求,后端可获取到文件Binary格式后端提供的上传文件接口需符合wx.uploadFile的要求,即请求方式为POST, 并指定所需文件key名(而不是直接要求把Binary文件丢在请求body中)

June 7, 2019 · 1 min · jiezi

微信小程序-页面禁止上下滚动全屏显示

全屏页面在想要设置为全屏的页面的json文件中设置 "disableScroll":true true 页面禁止上下滚动,不可以在app.json中设置,要写在page.json中

June 6, 2019 · 1 min · jiezi

拥抱小程序WeTest小程序全链路测试解决方案正式上线

作者:WeTest小编商业转载请联系腾讯WeTest获得授权,非商业转载请注明出处。原文链接:https://wetest.qq.com/lab/view/462.html 背景随着微信开放小程序开发功能,迅速在各个实体店抢占流量入口,广大商家看到了在线和离线的机会整合,利用小程序版本特点低成本进入市场,达到流量的获取和转化。 伴随着资本的进入,小程序开发市场也因此越来越壮大,小程序各项测试服务需求更是迫在眉睫,腾讯WeTest测试团队的微信小程序测试服务就在此背景下应运而生。_ 适用场景我是商户:作为小程序投入的直接投资人,往往购买采用第三方开发小程序的服务,那么我们小程序的质量是否有保障? 现实情况是 1.商户在通过第三方开发商完成小程序开发后,无法保障明确小程序的质量情况,需要对第三方外包开发产品进行接口性能、功能的质量验收,避免外包供应商开发质量过低对客户造成损失; 2.在各种大型节日前后(如六一八、双十一、双十二、双旦等),需要验证小程序在高并发下活动是否能正常进行时,无法确认是否存在优惠券盗刷等安全隐患; 在需要对新增功能进行质量评估时,无法保障大功能上线时的运行正常,从而导致可能发生的造成品牌口碑损失的风险。我是开发者:作为小程序搭建的开发人员,在小程序测试的专业度上不够专业,从而导致小程序会在安全,兼容,功能,性能等方面面临各式各样的潜在风险。 腾讯WeTest核心优势作为腾讯旗下质量服务平台,WeTest平台拥有众多其他测试公司所没有的优势。 1.在微信测试版本方面,WeTest支持各个微信版本的测试,避免部分用户因为微信版本不升级导致的测试盲区,微信账号方面我们更是拥有海量的资源,商户不必担心有效账号问题。 2.在性能数据报告方面,腾讯WeTest团队提供JS Error等问题维度记录以及首屏加载、页面切换时长等特有性能维度,并且提供部分性能优化建议,在报告中做到精准定位问题,问题聚类分析,问题解决建议等测试模块。 3.在测试流程方面,腾讯WeTest团队更是以微信小程序官方测试标准详细测试每一个微信小程序,以行业标准指标为商户提供建议。 腾讯WeTest小程序测试解决方案介绍小程序安全测试:腾讯WeTest团队模拟黑客攻击形式,对小程序业务系统进行渗透测试,比黑客更早发现可导致业务数据泄露,资产受损、数据被篡改,提前预知各类安全风险,为开发者提供方案修复安全漏洞,为小程序安全质量保驾护航。 小程序兼容测试:对市面主流热门安卓机型或苹果机型进行适配兼容测试,并在各种不同微信版本中进行验证,提供测试机型详细测试报告。 小程序性能测试:根据用户需求及服务器架构情况进行用例设计,支持定制高并发场景,结合测试报告针对客户的测试目标给出明确的结论,如“高风险/低风险/无风险”等,并对每个测试场景的测试结果做出梳理,标明瓶颈节点和瓶颈接口,为客户优化提供方向。 小程序功能测试:WeTest测试经理根据需求,针对应用进行用例设计,覆盖主要业务逻辑和功能点,逐一验证功能完整性、正确性及适用性的测试服务。(小程序上线全生命周期) 客户案例一、优衣库解决方案 WeTest团队为优衣库小程序定制专属功能测试服务,划分六大模块,总共覆盖近200多个测试项,不仅对公众号通用项,如登录,添加小程序等功能项测试。针对其中特色服务“门店入口”进行检测,精准定位用户地理信息,让用户线上下单,门店直取直派,省了用户排队等候时间,也省了厂商测试成本。 项目收益 此次测试帮助优衣库小程序发现了5个功能问题,保证优衣库小程序在“商品搜索”“下单流程”等核心场景在双十一期间稳定运行。 二、拉夏贝尔解决方案 安全层面通过对账号体系&交易体系的仿黑客渗透,为拉夏贝尔排查了账号及交易体系方面的安全风险,双方合作进行了快速修复。 性能层面提前定位支付接口频率限制及部分接口性能瓶颈问题。 项目收益 在双方的共同努力下,保障了拉夏贝尔小程序的安全运行环境,为拉夏贝尔的客户提供安全良好的购物环境。 性能层面通过修改支付频率限制,优化页面缓存与调整限流计算,解决小程序的性能问题。 除此以外,我们更是对龙湖地产,沃尔玛,都市丽人,麦德龙等多家小程序以及《跳舞的线》,《野蛮人大作战》等小游戏进行了测试服务。_目前WeTest小程序测试服务方案已经正式对外上线,欢迎了解咨询~ **点击“传送门”即可了解腾讯WeTest最新动态。传送门:https://wetest.qq.com/solution/miniProgram** 如果使用当中有任何疑问,欢迎联系腾讯WeTest企业QQ:2852350015

June 2, 2019 · 1 min · jiezi

小程序swiper轮播CSS3动画及跳转到指定swiperitem实现思路

需要解决的问题近几日一直在看怎样制作微信小程序的swiper轮播图。因为我既需要生成小程序的代码,也需要生成H5版代码,如果编写两套效率会比较低下,所以选择了uni-app。 uni-app已经在基础组件swiper中已经直接支持了轮播动画。 我主要需要解决的是以下几个问题: ①在swiper中怎样添加css3流行的animate.css动画。②添加好后如果滑动了轮播图,怎样能保证下一屏的动画不自动播放。③怎样能实现轮播图的无限循环播放。④怎样能实现,当用户点击一个按钮之后,可以跳转到指定的swiper-item中。也就是跳转到指定的屏。⑤小程序和H5版的代码会生成一个头部,在H5版中需要隐藏掉导航栏。以下就是我整个制作的思路过程,仅供参考。另外,代码是uni-app开发,所以在小程序中和H5中测试都没有问题。另外为了方便小程序开发同学了解,会提供小程序版代码和uni-app代码供参考。 代码实现在H5开发中经常使用的就是animate.css。在微信中自然是支持的,因为微信会对上传的小程序有大小限制,所以这里我使用了一个极简化的animate.css,其中删掉了很多-webkit-animation开头的css3。因为我们只需要在小程序和H5中运行,这样做影响也不大。如果需要的话,可以从下面的代码中获取。 我们先来看下代码: <template> <view class="content"> <button type="primary" @tap="goChange">跳转到第二屏</button> <swiper class="content-swiper" :vertical="true" :indicator-dots="true" :autoplay="false" :interval="3000" :duration="1000" @change="changeSwiper" @animationfinish="changeFinish" :current-item-id="item_id" circular="true"> <swiper-item item-id="slide0"> <view class="swiper-item"> <image src="../../static/uni.png" :class="animate_0"></image> </view> </swiper-item> <swiper-item item-id="slide1"> <view class="swiper-item"> <image src="../../static/uni.png" :class="animate_1"></image> </view> </swiper-item> <swiper-item item-id="slide2"> <view class="swiper-item"> <image src="../../static/uni.png" :class="animate_2"></image> </view> </swiper-item> <swiper-item item-id="slide3"> <view class="swiper-item"> <image src="../../static/uni.png" :class="animate_3"></image> </view> </swiper-item> </swiper> </view></template><script> export default { data() { return { item_id: 'slide2', animate_0: 'animated swing', animate_1: '', animate_2: '', animate_3: '' } }, onLoad() { }, methods: { changeSwiper(event){ // 清空除了当前swiper以外的所有动画 let current = event.detail.current; // 当前页下标 this.item_id = 'slide'+current; // 这里必须记录,否则只能跳转一次 switch (current){ case 0: this['animate_1'] = this['animate_2'] = this['animate_3'] = ''; break; case 1: this['animate_0'] = this['animate_2'] = this['animate_3'] = ''; break; case 2: this['animate_0'] = this['animate_1'] = this['animate_3'] = ''; break; case 3: this['animate_0'] = this['animate_1'] = this['animate_2'] = ''; break; } }, changeFinish(event){ // swiper动画完成之后,给当前swiper添加动画效果 let current = event.detail.current; switch(current){ case 0: this['animate_0'] = 'animated swing'; break; case 1: this['animate_1'] = 'animated shake'; break; case 2: this['animate_2'] = 'animated tada'; break; case 3: this['animate_3'] = 'animated heartBeat'; break; } }, goChange(){ this.item_id = 'slide1'; } } }</script><style lang="scss"> @import '../../common/animate.css'; .content { text-align: center; .content-swiper{ height: 100vh; image{ height: 200upx; width: 200upx; margin-top: 200upx; } } }</style>首先uni-app支持sass。在css中直接引入了简洁版animate.css。问题①之后通过查看文档,发现circular这个参数可以实现类似H5页面使用swiper.jsloop参数的功能。这里我掉到了uni-app和微信小程序文档描述的坑中。因为一直在找loop(循环)这个参数,我甚至都以为实现不了这个无限循环的功能了呢。原来小程序中这个参数叫做circular(圆形)。o(╯□╰)o 问题③因为我这里要实现一个竖屏的滑动效果,所以将参数vertical设置为true。在uni-app中,通过change事件,可以监听每一个轮播屏的改变。在这个事件中,我记录的当前屏的下标current。然后将非当前屏的全部css3动画取消掉。最后在animationfinish事件中,当swiper滑动动画结束后,给当前屏的元素添加css3动画。问题②在uni-app中有个current-item-id参数,代表当前所在滑块的 item-id。这个文档我看了好久,才明白。原来是需要在swiper-item中指定上item-id。然后当用户点击事件触发时,修改绑定到current-item-id上的值即可。我的代码初始化时指定到了item-id为slide2这一屏上。问题④最后一个问题时uni-app中隐藏掉H5导航栏。只需要在pages.json中设置titleNView为false即可。微信小程序代码<!--index.wxml--><view class="container"> <button bindtap='goChange'>跳转到</button> <swiper vertical="true" circular="true" current="{{currentId}}" indicator-dots="true" bindchange="changeSwiper" bindanimationfinish="changeFinish"> <swiper-item> <image src='../../static/uni.png' class='animated {{animate_0}}'></image> </swiper-item> <swiper-item> <image src='../../static/uni.png' class='animated {{animate_1}}'></image> </swiper-item> <swiper-item> <image src='../../static/uni.png' class='animated {{animate_2}}'></image> </swiper-item> </swiper></view>//index.jsconst app = getApp()Page({ data: { currentId: 0, animate_0: 'swing', animate_1: '', animate_2: '' }, onLoad: function() { }, goChange: function() { this.setData({ currentId: 2 }); }, changeSwiper: function(event) { let current = event.detail.current; switch (current) { case 0: this.setData({ animate_1: '', animate_2: '' }); break; case 1: this.setData({ animate_0: '', animate_2: '' }); break; case 2: this.setData({ animate_0: '', animate_1: '' }); break; } }, changeFinish: function(event) { let current = event.detail.current; switch (current) { case 0: this.setData({ animate_0: 'swing', }); break; case 1: this.setData({ animate_1: 'shake', }); break; case 2: this.setData({ animate_2: 'tada', }); break; } }})我将代码托管到了腾讯云开发者平台,需要的话可以参考。在代码目录unpackage/dist/build/h5中,就是生成好的H5版页面。需要注意的是,要部署到web服务器使用,不支持本地file协议打开。其中生成了两个版本的代码,方便大家参考。 ...

May 31, 2019 · 2 min · jiezi

码code-巧用2种方法打破20条云开发数据库限制

小程序·云开发是小程序的一种后端开发模式,能够帮助开发者快速构建微信小程序的后端服务,无需再搭建服务器。 然而熟悉云开发的开发者应该了解,即使云开发能基本满足小程序开发需求,但在数据获取上还是有所限制。 为了防止误操作以及保护小程序体验,开发者是需要避免一次性获取过量的数据,只获取必要的数据,所以服务器一次默认并且最多返回 20 条记录。但对于有数据大量获取需求的开发者来说,只能放弃云开发吗?答案是no。 微信团队之前在云课程上就已经分享了打破数据库列表限制的2种方法,通过云函数最多可获得100条数据。 这次的方法分享是以音乐播放器小程序为实例,通过云函数调用云数据库,实现用户上传音乐的功能。 音乐播放器的核心功能是播放歌曲,也就是需要它能够获取数据库所存储的歌曲信息,然后传到小程序端,去实现播放器的播放、暂停、切换。 01 上传歌曲信息至云数据库歌曲信息包括id、歌曲名、歌手、封面、音频文件等。 playlist: [{ _id: '', cover: '', singer: '', title: '', src: ''}],02 利用云函数获取数据列表getlist(){ let that = this; wx.cloud.callFunction({ name: ’getmlist’,//自己的云函数名称 success: res=>{ wx.stopPullDownRefresh() if(res.result){ let playlist = res.result.data console.log({ playlist }) if(playlist = undefined playlist.length == 0){ wx.showToast({ title: ’no data’, }) }else{ that.setData({ isShowArtcle: true, playlist: playlist, }) } } }, fail:err => { wx.stopPullDownRefresh() wx.showToast({ title: ’no data’, }) } })}然而目前的做法只能获取20条数据,也不能支持用户上传音乐文件并正常加载播放。为了实现这一功能,需要我们设置云函数,调用云数据库,从而打破数据限制。 ...

May 31, 2019 · 1 min · jiezi

讲case-小程序怎么月收百万抽奖助手有4种模式

小程序的特性是“用完即走”,工具类小程序更是如此。这也就意味着,这类小程序往往面临粘性不够、留存难的问题,“昙花一现”的情况比比皆是。开发者应该如何考量自己小程序未来的发展方向?我们将分期,讨论工具类小程序发展的可能性。 本期是由访问人次过6亿、月收入百万级的抽奖助手小程序产品负责人邱岳带来的经验分享,探讨工具类小程序发展成营销平台的可能性。 转载来源:腾讯公开课 原作者:见实“我们目前实现了百万级的月收入,但真的,收入模式的灵感和实现都是客户推着我们做的”。 邱岳说这话时有些不好意思,看起来有点腼腆的他这时更加局促。 他是无码科技合伙人,一直都在担任产品经理角色。这个由几个人小团队误打误撞做出的小程序抽奖助手,今天已有6亿人次在上面进行了千万次抽奖。 原本,一个简单工具类小程序如何快速获得增长和留存就是一个非常吸引人的话题,现在更要加上“收入”这个关键词了——抽奖助手已积累了200多家品牌客户,每月收入超过百万级。 在深聊之前,原本以为邱岳会讲一个反复试错的故事,如爆款小程序如何在挣钱这件事情上进行反复试错、摔过多少跟头、如何艰难建立收入模式等等,结果听到的完全不一样。邱岳提到,当用户和品牌都在工具上时,更多增值需求会喷薄而出,品牌和用户都会主动找来要求提供更好的服务,付费这件事情也就直接蕴含在里面了。 在抽奖助手“刚刚起步”的收入构成中,明显由四部分构成,分别是:抽奖定制化推广合作、卖流量、增值服务、电商。四类收入的效果如何?中间有哪些思考,邱岳完整地复盘了这个故事。 四种收入模式:从被动到主动构成收入来源第一部分的“抽奖定制化推广合作”,正是客户主动找上门,希望在抽奖活动上进行付费合作,这让最初没有专职销售人员的抽奖助手团队很好奇,到底是怎么回事? 邱岳跑去翻了翻数据,同时也对比了下不同渠道,发现了一个情况:通过抽奖活动所实现的获客效率,相比其它渠道高出4到6倍。这个获客模式十分自然。 不过,这一类推广都需要团队进行定制化设计及个性化的方案设计,需要按项目来推进,对于人手紧张的小团队会受到很多限制。 第二部分收入构成是“卖流量”。截止2018年底,抽奖助手累计用户已经6000万,作为一个有着大量用户的工具类小程序,流量售卖本就是天然收入模式之一。 此前不久,微信也开放了小程序的激励视频广告,抽奖助手是最早接入测试的团队之一。虽然邱岳没有提及实际收入数据,但他明确讲到,“从年初接入内测到现在,每天从激励视频上拿到的收入已增长了十几倍,而且目前依在快速增长。” 第三部分是“增值服务”。如允许用户在安卓端小程序内购买功能更加丰富的高级版抽奖样式,或者购买为线下活动设计的现场抽奖的功能等。 过去抽奖助手曾做过几次安卓版小程序付费功能点的调整,核心逻辑是把简单易懂、使用率更高的功能免费,对那些更复杂、使用率更低的功能收费,和社交场景相关的功能、具有商业场景性质的功能收费。如高级版功能中的公众号绑定、阅读图文详情页功能等,就符合上述逻辑,比较适合设计成为增值点。 邱岳的体会是,选择付费的功能点时要谨慎些,尤其要避免把普适性功能做成收费功能,根据实际数据情况,在用户体验产品层、传播层、收入层三个方面找到平衡点。 第四部分就是电商合作。利用第三方电商工具,帮助用户购买商品、发起抽奖,当然也可以让用户直接下单购物。 这部分收入来源被邱岳放到最后,实际迭代和尝试过程中也最难。抽奖助手的擅长是做工具,而不是卖货。因此,在实际尝试多次后,邱岳建议,创业团队要专注做自己擅长的事情,其他事情就交给专业人士去干。如电商就和专业的电商团队合作。即便团队真的想要自己卖货,也不要往上游走太远,根据自身产品场景做销售或代销就是非常不错的选择。 克制赚快钱的两个原则:选择关键场景、不过度商业化这四个收入构成,邱岳个人最喜欢增值服务部分,“这是工具类产品变现最体面、最健康的方式之一”。邱岳认为这样的变现对产品经理来说最适宜,“付费的用户,和产品能够帮助并创造价值的人群,能够形成两端一致”。在实际运营过程中,抽奖助手从安卓端小程序中获得的增值服务收入一直非常稳定。 如果将工具类型产品当作是一盘好菜的话,这就是让吃的人开心后向炒菜的人付费,大家都得到了回报,这才是“纯粹”。从产品经理的角度来说,这样的收入模式也是比较美好的方向和正向激励。其他如广告等总是要不停的打断用户体验,看起来就不那么纯粹了。 其实这些组成部分背后,也有很多选择。例如,如果仅仅是卖流量,要选择什么样的广告主?最早找上门的客户中,存在着很多做销售、卖金融P2P、养生和保健品等,这些都被抽奖助手拒了。 此外,一款纯工具类型的产品,如何设计广告位置?抽奖助手选择在关键场景加一些广告位置,但尽可能不打断用户体验交互的流程。 “做广告必须要有所克制。不能在用户和产品产生互动时插入广告,必须让用户有绕过广告的空间。” 邱岳说,甚至,用户完全可以对广告视而不见继续后续操作。但做起来其实很难,毕竟多开广告位能多几倍的收入,好处则是聚焦在用户体验上,可以提高转化率。 这两个细节构成了抽奖助手变现的两个原则,一是不把流量卖给不认可的广告主,二是在尽量不影响用户体验的前提下开辟广告位。 这反而吸引了越来越多广告客户上门求合作,不仅包含美妆、化妆品类,还有一些大平台在抽奖助手小程序上做活动,共同特点都是要流量,要曝光。 而邱岳所说的“克制”另一面也表现在:抽奖助手当然也希望获得更大、更多收入,不过这个团队没有投入更多资源: “这跟我们的心态、自身能力相关。一是如果业务量很大,会有客户主动来找到我们。二是我们团队人数不多,没有考虑加很多商务或者销售,也就并没有非常有攻击性地去大量接触更多客户,只在力所能及的范围内去做,服务好每一个合作客户。”幸运的是,虽然没有大家想象中的特别“死磕”的过程,也因此没有犯特别大的戏剧性的错误。 给小程序创业者的三个变现提醒不过,更关键的问题是: 在各种变现策略的背后,如何选择适合自己产品和团队的收入方式? 这是大多创业团队遇到的难题之一。在小程序生态中,如果通过产品或者服务向有需求的B端提供价值?邱岳通常会这样追问自己几个问题。 第一个追问:这个收入模式最终是由谁来买单?他们关注的价值是什么? 如想提升广告收入,就去考虑广告主的广告费从哪里来?客户究竟是做电商还是做游戏的?钱是融资还是赚的利润?购买的服务是希望冲量、希望省钱?还是希望提升转化?等等。 这些反问代表着每一分钱背后的价值诉求。每一分钱背后都有不同价值诉求的交易,想清楚买单的人是谁、钱从哪来,就能去判断具体收入模式的持续性和稳定性,能够判断用户画像是否匹配。如果广告主用一块钱获得用户,但只能创造五毛钱价值,这个生意从长期来看就有危险。 第二个追问是:收入模式背后的引擎是什么?什么要素会影响收入的波动? 如影响广告收益的是曝光和点击,而流量和广告策略则是带来收入的引擎。分析收入引擎有助于确定运营失利点和收入的天花板。邱岳说,“与其去突破或拯救天花板,不如尝试建立新的收入引擎。” 怎么确定这个收入天花板?如果流量稳定在一个量级,死活都拉不上去,那么流量就是整个广告收入的天花板。这时就算再投资源、优化广告策略,都不会有太大作用。因为优化通常带来百分比级别的增长,而尝试建立新收入引擎则会带来十倍,甚至百倍收入增长。 第三个追问:现在做的收入模式是否与生态共赢? 对于小团队在微信生态中创业和挣钱,也要去关注自己产品和微信生态之间的关系。虽然一波流(可以理解为3天应用、7天应用,意思是过完这几天就“死掉”的小程序、小应用。通常这类产品还有一个戏谑的称呼:“日抛型”、“周抛型”小程序)和抄袭党在前期确实能赚到一点钱,但这种依靠消耗生态来赚钱的方式根本无法持续。 了解更多小程序开发相关内容,欢迎微信扫描下方二维码关注「微信极客WeGeek」公众号,共筑微信生态。

May 30, 2019 · 1 min · jiezi

业内首个-React-Native转微信小程序引擎-Alita-正式发布

作者:京东ARES多端技术团队前言Alita是一套由京东ARES多端技术团队打造的React Native代码转换引擎工具。它对React语法有全新的处理方式,支持在运行时处理React语法,实现了React Native和微信小程序之间的主要组件对齐,可以用简洁、高效的方式把React Native代码转换成微信小程序代码。 Alita不是新的框架,也没有提出新的语法规则,她只做一件事,就是把你的React Native代码运行在微信小程序端。所以Alita的侵入性很低,选用与否,并不会对你的原有React Native开发方式造成太大影响。 Alita项目开源地址: https://github.com/areslabs/alitaReact Native 微信小程序 Alita 具备哪些能力完备的React语法支持Alita的设计目标是要尽可能无损的转换RN应用,即使是已经存在的RN应用,我们也希望只做少量的修改就可以在微信小程序平台运行,所以这就要求Alita必须对React语法有足够的支持,包括 JSX 语法,React生命周期等 JSX语法Alita 支持大部分 JSX 语法,这意味着什么呢?意味着你可以使用React自由的代码方式以及强大的组件化支持,意味着你可以延用自己的编程习惯,不需要对已有的RN代码进行过多修改。这主要得益于 Alita 是在运行时处理 JSX语法,而不是现在社区上常见的编译时处理。 因此 Alita 没有诸如以下社区其他方案的限制: JSX 只允许出现的组件的 render 方法中不能通过 props 传递 JSX 片段或者返回 JSX 的函数不支持在属性上传递函数Alita 转换以下代码毫无压力: 生命周期Alita 支持所有的 React 生命周期。微信小程序本身给组件提供了生命周期,但是这些生命周期在写法和调用上与 React 存在着一些的差异,另外 React 生命周期更加丰富。Alita 在支持 React 生命周期的时候,把它们分为了两类,第一类: componentDidMount,componentDidUpdate,componentWillUnmount 这3个生命周期在微信小程序上有相应的触发时机,比如ready, detached,只需要在微信小程序相关回调触发的时候,调用 React 组件对应的方法即可。另外一类,在微信小程序端没有直接对应的生命周期,对于这一类生命周期,主要是借助于 Alita 内部嵌入的 mini-react,触发相应的回调。通过这两种方式,Alita 实现了 React 生命周期的对齐。 此外,Alita 抹平了 RN 和微信小程序之间的事件及样式差异,能够无损得将RN事件和样式传递到微信小程序中。 RN基本组件和APIRN 提供了很多基本的组件和 API,这些组件加上 React 开发方式,共同构成了 RN 应用。Alita 除了要对 React 语法进行处理,还必须在预先在微信小程序平台对齐出一套与 RN 等效的组件和 API。比如在 RN 端,请求网络的方式是通过 fetch 方式,但是微信小程序本身并不存在 fetch 方法,就这要求 Alita 必须基于微信小程序的网络 API,在微信小程序上实现一个 fetch 方法。 同样的以 RN 组件 FlatList 为例,当 Alita 把 RN 应用转化为微信小程序代码之后,FlatList 在微信小程序平台并不存在,需要预先在微信小程序平台实现小程序版本的 FlatList 。这个预先处理的过程,我们称之为对齐,对齐的过程包括组件,组件属性,API 等。 ...

May 30, 2019 · 1 min · jiezi

微信小程序编写

做一个有关运动的微信小程序,有没有好的推荐????

May 25, 2019 · 1 min · jiezi

行业log-小程序命名规范大调整现在不能这样取名了

上周,微信开放社区公布了小程序名称规则调整的公告,主要是针对之前一些投机的取名做法罗列了调整和优化建议,调整后的命名规范比之前更加严格。 小程序的价值在于提供服务,平台也是希望小程序名称等的信息能够具有准确性和独特性,减少误导、混淆用户理解的可能性。这些调整规范也可以总结为“五不一建议”: 01 不得使用违反广告法等禁止的用语Eg. 国家级、世界级、最高级、最佳、第一、唯一、首个、最好、精确、顶级、最低、最底、最便宜、最大程度、最新技术、最先进科学、国家级产品、填补国内空白、绝对、独家、首家、最新、最先进、第一品牌、金牌、名牌、最赚、超赚、最先、巨星、奢侈、至尊、顶级享受 02 不得使用营销味重的商业化用语Eg. 免费、促销、清仓、打折、免单 广告法禁用语和商业化用语往往自带夸大的表达效果,会对用户产生误导。 03 不得混用热门公众号、小程序或第三方品牌名称蹭热门应用、小程序或第三方知名品牌名称一直是某些小程序增加曝光的途径,这也会导致用户用错小程序,带来时间和精力上的浪费。在新的规则规范下,这类做法将被禁止,除非已获授权。 04 不建议使用广义归纳类的词汇直接使用这类词汇,缺乏显著性,也会给用户带来无法识别、区分小程序的困扰。 05 不建议使用关键词堆砌过于冗长的关键词堆砌名称是为了能够在搜索结果上获得更多的曝光,但这并不利于品牌记忆的建立以及用户的理解。应对方法:可将小程序有关的关键词放入功能介绍,达到关键词搜索优化的目的。 06 建议在名称信息上包含品牌信息这种名称具有辨识度,也便于用户识别。小程序正确的名称公式:品牌+产品类别名/产品名 这些调整从表面看是为了提升用户体验,那对开发者而言,这么严格的规范究竟是好还是坏呢? 命名审核虽然在短期会给开发者造成一定的麻烦,但从长期看来,这是保障开发者权益的举措。 以小游戏为例,开发者辛苦打造了一个爆款出来,结果被抄袭又名称相似的小游戏瓜分了流量。但现在在这个命名规范的限制下,以下情况将会大大减少。 同时,开发者通过现有的小程序与用户建立了品牌偏好,在新的小程序推出时能够形成小程序矩阵,也可以降低宣传成本。 微信平台这次调整,其实是在强调“品牌”,目的是让用户通过使用小程序,接受并建立对开发者产品品牌的认知,这样也有利于开发者产品的长远发展。 特别注意对于调整规范发布前已经通过审核的小程序,开发者也不要掉以轻心,近期平台可能将对名称重新审核,所以请提前自查,做好准备。 了解更多小程序开发相关内容,欢迎微信扫描下方二维码关注「微信极客WeGeek」公众号,共筑微信生态。

May 23, 2019 · 1 min · jiezi

mpvue小程序循环动画开启暂停

用小程序的animation属性实现循环动画的开启与暂停,并封装到组件。 实现一个字体图标组件的循环旋转动画开启/暂停 用于点击图标,字体颜色变换,开始循环旋转动画,并刷新内容刷新结束,停止动画,并设置字体颜色为原来的主要利用setInterval定时器循环执行动画首先,组件写出来添加点击事件,动画属性,style属性(用来动态修改样式) src/components/refresh.vue<template> <div> <div class="iconfont icon-shuaxin" :animation='refreshA' @click="refresh" :style='style'></div> </div></template>设置初始数据使用一个 布尔 数据refreshing判断动画的状态为开启true/暂停false <script>export default { data () { return { refreshA: null, style: 'color: #eee;', // 用来设置存储旋转的度数 rotate: 0, // 存储定时器id refreshI: null } }, props: ['refreshing']}</script>添加点击事件函数<script>export default { methods: { // 刷新按钮点击 refresh () { // 正在刷新 则跳出,避免在循环动画执行时,再次出发点击刷新事件 if (this.refreshing) return // 否则提交刷新事件 this.$emit('refresh') }, // 刷新动画结束 refreshend () { // 当动画结束,字体颜色恢复原来 this.style = 'color: #eee;' } }}</script>监听refreshing状态<script>export default { watch: { refreshing (newV, oldV) { // 没有正在刷新 > 正在刷新 设置循环动画 if (newV && !oldV) { this.style = 'color: #fff;' this.refreshI = setInterval(() => { // 每次 +360 实现每 300 毫秒旋转 360 度 this.rotate += 360 let animation = wx.createAnimation() animation.rotateZ(this.rotate).step() this.refreshA = animation.export() }, 300) return } // 从正在刷新 > 刷新完成 清空循环定时器动画 if (!newV && oldV) { // 防止网速过快,动画队列还没生成就刷新完成,这里判断动画队列是否为空 // 为空,就重置一下样式 if (!this.refreshA) this.style = 'color: #eee;' clearInterval(this.refreshI) this.refreshA = null } } }}</script>需要注意的是定时器时间必须和动画的过渡时间设置为相同组件调用src/pages/index/index.vue<template> <div> <Refresh @refresh='refresh' :refreshing='refreshing'/> </div></template><script>import Refresh from '@/components/refresh'export default { data: { // 初始状态肯定为 false ,点击刷新组件后,在事件函数中再设置为 true refreshing: false }, components: { Refresh }, methods: { async refresh () { this.refreshing = true // 这里为一个异步请求api let data = await api.getData() // 请求完成,执行想要操作的代码后,设置动画为 false // this.data = data this.refreshing = false } }}</script><style lang="stylus" scoped></style>refresh组件完整代码<template> <div> <div class="iconfont icon-shuaxin" :animation='refreshA' @click="refresh" :style='style'></div> </div></template><script>export default { data () { return { refreshA: null, style: 'color: #eee;', rotate: 0, refreshI: null } }, props: ['refreshing'], watch: { refreshing (newV, oldV) { if (newV && !oldV) { this.style = 'color: #fff;' this.refreshI = setInterval(() => { this.rotate += 360 let animation = wx.createAnimation() animation.rotateZ(this.rotate).step() this.refreshA = animation.export() }, 300) return } if (!newV && oldV) { if (!this.refreshA) this.style = 'color: #eee;' clearInterval(this.refreshI) this.refreshA = null } } }, methods: { refresh () { if (this.refreshing) return this.$emit('refresh') }, refreshend () { this.style = 'color: #eee;' } }}</script><style lang="stylus" scoped></style>效果正常效果,看图中右上角 ...

May 14, 2019 · 2 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

知晓推送正式上线送你-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

微信小程序事件对象中etarget和ecurrentTarget的区别

在小程序的事件回调触发时,会接收一个事件对象,事件对象的参数中包含一个target和currentTarget属性,接下来说说这二者的区别。 首先上代码: wxml部分:<view id='tar-father' bindtap='click'> 父组件 <view id='tar-children'>子组件</view> </view> wxss部分:#tar-father{ width: 300rpx; height: 300rpx; background-color: skyblue;}#tar-children{ background-color: pink;}效果图 js部分: click: function (event) { console.log(event.target) console.log(event.currentTarget) }当点击图中粉色子组件区域时的输出结果: event.target 为其子组件,也就是触发该事件的源头组件event.currentTarget 为事件所绑定的组件当点击图中蓝色父组件区域时的输出结果: event.target 为父组件,因为触发的源头也就是父组件本身event.currentTarget 始终为事件所绑定的组件总结:target对应的是触发事件的源头组件,这个组件有可能是子组件,有可能是父组件,主要是看执行动作的区域。而currentTarget始终对应事件所绑定的组件。

May 8, 2019 · 1 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

手把手教你写一个微信小程序日历组件

今天我们一起写一个微信小程序日历组件 微信小程序日历组件https://github.com/749264345/wx-calendar好,我们先看一下要实现的模样,如下图由以上截图我们可以看到 1.日历可以通过按钮【切换展示效果】改变日历的呈现效果,上图是平铺模式,下图是收起滚动模式。2.通过点击具体的日期可以在页面上显示当前选中的具体日期。3.点击【今天】快速回到当日视图。4.点击【◀】和【▶】切换月份。上面的四点也是基本的交互需求,我们马上开始。首先,我们先结构后样式,做出最基本的界面结构这边我们把整体结构分成上中下,操作显示区,星期显示区,日期显示区。<view class='calendar'> <!--显示当前年月日--> <view class='calendar-title'> <view class='item ctrl' bindtap='lastMonth'>{{lastMonth}}</view> <view class='item title'>{{title}}</view> <view class='item ctrl' bindtap='nextMonth'>{{nextMonth}}</view> <view class='item ctrl today' bindtap='today'>今天</view> </view> <!--星期--> <view class='calendar-week'> <view class='item'>{{item}}</view> </view> <!--日期--> <view class='calendar-container'> <!--上个月占位格子--> <view class='grid gray'>{{item}}</view> <!--当月格子--> <view class='grid'> <view class="wrap">{{item.date}}</view> </view> <!--下个月占位格子--> <view class='grid gray'>{{item}}</view> </view></view>这是我们基本的日历结构,机智的小伙伴已经从布局中知道我们实现的大致逻辑了,是的,我们先获取当月有多少天,上月和下月有多少天,这样我们的日历就出来了。好,慢慢来,下面我们详细说,我们先写上基本的样式。 .calendar { width: 100%; text-align: center; font-size: 30rpx; box-sizing: border-box;}/* 标题 */.calendar-title { line-height: 70rpx; font-size: 30rpx; text-align: left; padding: 0 20rpx; box-sizing: border-box;}.calendar-title .ctrl { display: inline-block; padding: 0 20rpx; background: #f5f5f5; border-radius: 10rpx;}.calendar-title .item { display: inline-block; vertical-align: middle; line-height: 50rpx;}.calendar-title .title { min-width: 300rpx; text-align: center;}.calendar-title .today { float: right; margin-top: 10rpx;}/* 星期 */.calendar-week { display: flex; text-align: center; padding: 20rpx 10rpx; box-sizing: border-box; border-top: 1rpx solid #e0e0e0; border-bottom: 1rpx solid #e0e0e0; background: #f5f5f5;}.calendar-week .item { flex: 1;}/* 日期 */.calendar-container { display: flex; flex-wrap: wrap; padding: 20rpx 10rpx; box-sizing: border-box;}.calendar-container .grid { display: inline-block; width: 14.28571428571429%; line-height: 70rpx; position: relative; z-index: 1;}.calendar-container .grid.gray { color: #ccc;}.calendar-container .grid .wrap.select { background: rgb(49, 120, 228); border-radius: 10rpx; color: #fff; width: 80%; margin: 0 auto;}以上我们基本试下了日历的界面,下面我们来实现星期和日期的展示。好,我们先显示星期,我们先在组件中定义一个数组,用来遍历显示星期的标题; ...

May 2, 2019 · 3 min · jiezi

微信小程序生命周期与关键性能指标

本文将介绍微信小程序整个App的生命周期、单个页面的生命周期和组件的生命周期,并研究了这三个元素生命周期的关系,这在学习和开发过程中对理解小程序运行机制有重要意义。最终,由生命周期整理出小程序的关键指标,仅供参考。 App的生命周期在app.js中有其生命周期相关的三个方法:onLaunch、onShow和onHide。 首先是onLaunch,这是整个小程序的第一个生命周期回调函数,在小程序初始化完成后调用。 接着,小程序将触发onShow事件,如果小程序从后台切回前台后也会触发该事件。 最后,是小程序切到后台的事件onHide。 Page的生命周期在每个页面注册函数Page()的参数中,有生命周期的方法:onLoad、onShow、onReady、onHide、onUnload。 页面触发的第一个生命周期回调是onLoad,在页面加载的时候触发,其参数是页面的query参数,一个页面只有一次; 接着是onShow,监听页面的显示,与onLoad不同,如果页面被隐藏后再次显示(例如:进入下一页后返回),也会触发该生命周期; 触发onShow之后,逻辑层会向渲染层发送初始化数据,渲染层完成第一次渲染之后,会通知逻辑层触发onReady生命周期,一个页面只有一次; onHide是页面隐藏但未卸载的时候触发的,如 wx.navigateTo 或底部tab切换到其他页面,小程序切入后台等。 onUnload是页面卸载时触发,如wx.redirectTo或wx.navigateBack到其他页面时。 Component的生命周期组件最重要的生命周期是created、attached、detached ,包含一个组件实例生命流程的最主要时间点。 首先,当组件实例刚被创建时, created生命周期被触发。此时,还不能调用setData 。 通常情况下,这个生命周期只应该用于给组件this添加一些自定义属性字段。 接着,在组件完全初始化完毕并且进入页面节点树后, attached生命周期被触发。此时, this.data 已被初始化为组件的当前值,绝大多数初始化工作可以在这个时机进行。 在组件离开页面节点树后, detached生命周期被触发。退出一个页面时,如果组件还在页面节点树中,则 detached 会被触发。 此外,组件生命周期还有ready和move生命周期,分别在视图层布局完成和组件实例被移动到节点树另一个位置时执行。 整体周期现在我们知道了App、Page、和Component分别的生命周期顺序,那么他们之间的生命周期顺序又是如何?通过开发一个简单的demo,观察运行结果,可以得到如下结论: 打开页面的情况首先,前一个页面隐藏,在加载下一个页面之前,需要先初始化新页面的组件。页面首次渲染之后,会触发组件的ready,最后触发的是页面的onReady,如下图: 从PageA打开pageB时的生命周期顺序 离开页面的情况离开当前页面时,首先触发当前页面的卸载onUnload,接着是组件离开节点树的detached。最后显示之前的页面,触发onShow。如下图: 从PageB返回到PageA的生命周期顺序 打开App的情况App、Page与Component生命周期运行顺序,先从App加载然后再加载Page,在加载Page之前会先初始化该页面所用的所有组件,之后才触发页面的onLoad生命周期,如下图: 打开App时的生命周期顺序 切换到后台切换到后台时,小程序和页面并没有卸载,只会触发隐藏。先触发页面的onHide,接着是App的onHide。如下图: 切换到后台时的生命周期顺序 切换到前台切换到后台时,小程序会先触发onShow,之后才是页面的onShow。如下图:切换到前台时的生命周期顺序 关键性能指标了解了小程序各个阶段的生命周期,我们可以制定出关键节点的性能指标,整理如下表: 维度指标含义App小程序打开时间firstPage.onLoad - onLaunch 打开首页显示时间firstPage.onReady - onLaunch页面首次渲染时间page.onReady - page.onLoad 可交互时间(首屏时间)首屏相关模块最后一次setData的时间点 - page.onLoad 接口请求时间请求返回时间 - 请求发送时间参考文档官方文档 Page:https://developers.weixin.qq....官方文档 App:https://developers.weixin.qq....官方文档 页面生命周期:https://developers.weixin.qq....官方文档 组件生命周期:https://developers.weixin.qq....

April 30, 2019 · 1 min · jiezi

mpvue骨架屏vue骨架屏原生微信小程序wxml骨架屏分享笔记

mpvue小程序骨架屏可查看这篇文章《小程序骨架屏》 原生微信小程序wxml骨架屏可参考作者腾讯的git项目:《skeleton》 vue骨架屏vue-skeleton-webpack-plugin 骨架屏框架,多种样式 方法一:(SPA 中单个 Skeleton) 可参考这个文章《vue-cli 构建的项目如何加入骨架屏 skeleton》 方法二:(SPA 中多个 Skeleton)这里和方法一相同的创建和build里创建流程一样。主要修改的里面的代码: src下创建2种骨架屏展示,然后可根据不同路由页面,进行显示其他一种,下面实现路由分配 /build/webpack.skeleton.conf.js 修改为: 'use strict';const path = require('path')const merge = require('webpack-merge')const baseWebpackConfig = require('./webpack.base.conf')const nodeExternals = require('webpack-node-externals')const utils = require('./utils')const config = require('../config')const isProduction = process.env.NODE_ENV === 'production'const sourceMapEnabled = isProduction ? config.build.productionSourceMap : config.dev.cssSourceMapfunction resolve(dir) { return path.join(__dirname, dir)}let skeletonWebpackConfig = merge(baseWebpackConfig, { target: 'node', devtool: false, entry: { app: resolve('../src/entry-skeleton.js') }, output: Object.assign({}, baseWebpackConfig.output, { libraryTarget: 'commonjs2' }), externals: nodeExternals({ whitelist: /\.css$/ }), plugins: []})// important: enable extract-text-webpack-pluginskeletonWebpackConfig.module.rules[0].options.loaders = utils.cssLoaders({ sourceMap: sourceMapEnabled, extract: true}),module.exports = skeletonWebpackConfig/build/webpack.dev.conf.js 和 /build/webpack.prod.conf.js 修改为 ...

April 29, 2019 · 1 min · jiezi

微信小程序禁止page页面上下滑动

在单页面设置disableScroll为true即可; 则页面整体不能上下滚动。只在页面配置中有效,无法在 app.json 中设置 其他就是微信小程序有的,但很多人都不知道。比如个人中心一般就几个菜单栏,不需要上面滑动,所以可以禁用掉,这样体验好些。

April 29, 2019 · 1 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

码code-小程序接入激励式视频广告硬核指南

4月16日,微信开放社区发布了“「激励式视频广告」向非游戏类小程序流量主开放“的公告,也就是说现在只要是开通了流量主的小程序,就可以跟小游戏一样插入激励视频广告。 激励式视频广告的功能对用户来说:在小程序的某个场景中主动触发激励式广告,待完整播放视频广告,并手动点击“关闭广告”按钮后,将获得该小程序下发的奖励。 对流量主来说:可通过视频广告的有效曝光,与平台分成收取的广告费用。100W元以下广告流水,按照5:5分成,100W元以上广告流水,按照 3:7分成(流量主3成),分成不设封顶。 激励式视频广告的接入步骤01 / 开通流量主累计UV不低于1000的开发者可登录小程序后台,进入流量主,点击开通,并按照指示填写资料。 02 / 创建广告位新流量主直接点击“立即创建”广告位。 已开通的流量主选择广告位管理——点击新建广告位——选择激励式视频的广告位类型。 03 / 获取代码回到广告位管理,获取刚新建广告位的代码。 04 / 嵌入代码激励式视频的触发流程如下图,这也就是说明,激励式视频需要实现重复调用、监听的效果: 接口说明wx.createRewardedVideoAd(Object object)创建一个激励式视频广告,返回一个单例对象,该对象仅对单个页面有效。多次创建,将返回同一个激励式视频广告对象(RewardedVideoAd)建议开发者在页面加载后(onLoad事件)创建一个广告对象,并在该页面的生命周期内重复调用该广告对象 接口说明RewardedVideoAd激励式视频广告对象•Promise RewardedVideoAd.load() 加载激励式视频广告数据•Promise RewardedVideoAd.show() 显示激励式视频广告•RewardedVideoAd.onClose(Function callback) 监听激励式视频广告的关闭事件当用户点击“关闭广告”按钮时,激励式视频会从下方切出屏幕,此时会触发onClose注册的回调函数onClose回调会带一个状态对象status,描述广告被关闭时的状态(基础库2.1.0版本支持,旧版本基础库未返回该对象,开发者需要兼容),开发者需要根据该状态的属性判断是否视频是否播放结束、可以向用户下发奖励 •RewardedVideoAd.offClose(Function callback) 取消监听激励式视频广告的关闭事件•RewardedVideoAd.onLoad(Function callback) 监听激励式视频广告的加载成功事件当激励式视频广告成功加载到广告数据时,会触发onLoad注册的回调函数在组件创建后会拉取一次广告,用户点击关闭广告后会去拉取下一条广告,开发者可监听 onLoad 事件判断是否展示广告入口•RewardedVideoAd.offLoad(Function callback) 取消监听激励式视频广告的加载成功事件•RewardedVideoAd.onError(Function callback) 监听激励式视频广告的错误事件•RewardedVideoAd.offError(Function callback) 取消监听激励式视频广告的错误事件 (要想了解更多详细的接口文档,可点击获取《小程序激励式广告流量主指引》ppt。) 激励式视频广告可接入的场景激励视频广告的插入方式也给予了流量主极大的自主性,广告触发场景与奖励内容均可自定义。那么对于非游戏类的流量主来说,有什么奖励可以刺激到用户点击激励视频广告?我们为大家想了一些可供参考的接入场景: 01 / 工具类工具类小程序在给用户提供使用价值时会沉淀流量,激励视频广告给工具类小程序带来比较自然的变现机会,兼顾“用完即走”的场景理念,工具提供方可以适当借力激励视频广告深挖用户价值。比如抢火车票小程序,观看视频广告可以获得加速包: 02 / 资讯类资讯类小程序满足用户的阅读需求,流量主可以对某些内容进行锁定,引导用户观看视频才能获取。比如课堂小程序,观看视频广告可以解锁下一阶段的课程: 03 / 购物类这类小程序一般会通过邀请好友、幸运转盘等互动机制给予用户优惠券、积分等福利。当激励视频广告成为一种新的互动形式,能够为小程序增加了变现机会,同时也因为操作简单提高了用户的接受度。比如电商小程序,观看视频后可以获得红包: 接入激励式视频广告的注意事项激励视频广告是一个辅助变现工具,流量主在选择场景插入时一定要兼顾平衡,不能一味追求广告收入而不断提高小程序的用户使用门槛,影响小程序触达用户的便捷性,造成用户流失。所以流量主应该适当设置触发场景,也可提供更多服务价值激励机制,平衡用户体验。 了解更多小程序开发相关内容,欢迎微信扫描下方二维码关注「微信极客WeGeek」公众号,共筑微信生态。

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