发表日期:2017-12 文章编辑:小灯 浏览次数:1159
还有两三天就跨年了,今天总结下开发小程序的心得与体会 开发前准备
本文首先假定开发者已经粗略阅读过微信小程序的开发文档,所以注册小程序的流程就不介绍了。不过需要注意,小程序现在只允许企业用户注册,所以认证需要企业营业执照复印件和加盖公章的小程序申请公函。如果是选择对公账户认证,则不需要公函。另外,如果需要使用微信支付接口,则需要另外进行一次微信认证,这个就必须使用300块的方式了,如果要进行第三方平台开发小程序,建议使用对公账户,一般几毛钱就能认证一个小程序。
开发工具介绍
我调试用的开发工具就是微信官方提供的IDE,编写代码还是使用Atom编辑器,毕竟代码高亮提示等等是必须的啊,现在也有了很多第三方的IDE或者插件,但是用起来感觉整合度不如官方版,索性不换了。新建项目需要输入注册小程序时获取的AppId。需要注意的是设置页面:其中有一项是开发环境不校验请求域名以及TLS版本。这一项需要勾选上,因为微信只支持HTTPS的协议而且必须是指定域名,这让开发者使用localhost调试变的很麻烦,勾选此项之后就没有这种限制了,但只有在开发环境才可以,
开发者工具调试界面和Chorem浏览的开发者工具类似,调试工具分为 7 大功能模块:Wxml、Console、Sources、Network、Appdata、Storage、Sensor、Trace。
语言
首先,小程序类Web,但不同于我所认识的HTML,他有属于自己的开发语言:
JavaScript: 微信小程序的 JavaScript 运行环境即不是 Browser 也不是 Node.js。它运行在微信 App 的上下文中,不能操作 Browser context 下的 DOM,也不能通过 Node.js 相关接口访问操作系统 API。
WXML: 作为微信小程序的展示层,并不是使用 Html,而是自己发明的基于 XML 语法。
WXSS: 用来修饰展示层的样式。官方的描述是 “ WXSS (WeiXin Style Sheets) 是一套样式语言,用于描述 WXML 的组件样式。WXSS 用来决定 WXML 的组件应该怎么显示。”
入口文件
小程序主要包含以下三个入口文件:
app.js 这个文件是整个小程序的入口文件,我们主要做了网络检测、用户信息获取等;当让也可以注入公用的方法在其他页面中去通过getApp()调用(注:页面中调用app.js中的方法时不需要通过require或者import引入)
app.json 这个文件可以对小程序进行全局配置,决定页面文件的路径、整体窗口表现、设置网络超时时间、设置多tab等.
app.wxss 是小程序的公共样式表
一、准备工作
注册一个小程序账号,得用一个没注册过公众号的邮箱注册。
注册完账号,登录,在主页面左边列表中点击设置,然后再设置页面中选开发设置就可以看到AppID,用于登录开发工具。
二、开始项目
image.png项目名称可为中文和英文
勾选快速启动模版
image.png启动后
image.png 这是官方提供的示例模版
image.pngapp.js: 小程序逻辑,生命周期,,全局变量app.json: 小程序公共设置,导航栏颜色等,不可以注释app.wxss :小程序公共样式,类CSS 。
image.png每一个小程序页面是由同路径下同名的四个不同后缀文件的组成,如:index.js、index.wxml、index.wxss、index.json。
微信小程序中的每一个页面的【路径+页面名】都需要写在 app.json 的 pages 中,且 pages 中的第一个页面是小程序的首页。
image.png每个基础页面组成
image.png这四个文件按照功能可以分成三个部分:
配置:json 文件 逻辑层:js文件 视图层:wxss.wxml文件 在 iOS 上,小程序的 javaScript 代码是运行在 JavaScriptCore 中,在 Android上,小程序的 javaScript 代码是通过 X5 内核来解析,在开发工具上,小程序的 javaScript 代码是运行在 NW.js(chrome内核)中,所以开发工具上的效果跟实际效果有所出入。
2、组件
微信提供了许多组件,主要分为八种:
视图容器、基础内容、表单组件、操作反馈、导航、媒体组件、地图、画布 包含view、scroll-view、button、form等普通常用的组件,也提供了地图map、画布canvas。
组件主要属于视图层,通过wxml来进行结构布局,类似于html。通过wxss修改样式,类似于css。组件使用语法实例:
<!--普通视图--> <view>这是一个普通视图</view> <!--wxss样式修改--> <view class="mainView">样式修改过的视图</view> 更多的组件以及相关使用方法可以到官方文档-组件查看
网络媒体数据位置设备界面开发接口 其中网络请求的使用必须先到公众平台登录小程序账号,在设置页面那里,设置允许访问的域名,网络请求包含了普通的http请求、支持上传、下载、socket。基本上满足了我们开发中所需要的网络需求。
这些API属于逻辑层,写在js文件中,使用示例:
//获取当前定位,返回经纬度等具体信息 wx.getLocation({type: 'wgs84', success: function(res) {var latitude = res.latitude var longitude = res.longitudevar speed = res.speed var accuracy = res.accuracy} }) 可以到官方文档-API查看其它API的使用方法。
生命周期
当然,微信小程序和其他前端框架类似也是有生命周期的:
Page({ /** * 页面的初始数据 */ data: {},/** * 生命周期函数--监听页面加载(像首页数据请求可以放在这里) */ onLoad: function (options) {},/** * 生命周期函数--监听页面初次渲染完成 */ onReady: function () {},/** * 生命周期函数--监听页面显示 */ onShow: function () {},/** * 生命周期函数--监听页面隐藏 */ onHide: function () {},/** * 生命周期函数--监听页面卸载 */ onUnload: function () {},/** * 页面相关事件处理函数--监听用户下拉动作(这里添加了下拉刷新的功能) */ onPullDownRefresh: function () {},/** * 页面上拉触底事件的处理函数 */ onReachBottom: function () {},/** * 用户点击右上角分享 */ onShareAppMessage: function () {} }) 当我们在data中初始化的值需要修改时,可在各生命周期及方法中通过setData()修改。由于小程序的入口页面就是首页,在首页添加了用户登陆和网络状态的检测在onLoad中。
tabBar即小程序的底部导航栏,由于微信的限制,最少2个最多5个导航栏,只可设置文案、图标。(知识点:图的大小为81px边缘要留透明的白边,不然图会很大)
小程序样式采用WXSS语言(具有CSS大部分特性)。他也提供了一种新的单位rpx(可根据屏幕宽度自行适应)。官方规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素,既然这样我们也推荐了我们设计师采用iPhone6作为设计标准,即750px宽度。
但是在实际的开发过程中如果字体大小也使用rpx做单位的话,在iPhone6 Puls上显示文字过大,影响美观。后经过测试采用了px做单位,即原设计稿尺寸的一半+px,这样可以保证文字大小在各设备中保持一致。
在官方文档上有明确规定,本地资源是无法通过CSS获取的,图片的话只能使用网络资源或base64方式。首页有个需要判断网络状态的需求,由于断网情况下无法获取网络资源,最后就使用了base64的方式。
官方获取网络状态的API是getNetworkType为异步接口,通过它的返回结果再进行下一步(是显示无网络还是调用数据列表接口),说到这里大家都知该怎么办了——Promise,具体封装如下
new Promise((resolve, reject) => { let req = wx.getNetworkType({ success: function (res) { var networkType = res.networkType; if (networkType === 'none') { resolve(false) } else { resolve(true) } }, fail() { reject(false) } }); }) 调试的时候最大的问题呢是:无论是开发者工具上还是手机上,记得先把缓存删干净再测。特别是开发者工具每次切换host都要清理缓存,再重新打开,而且出现bug的时候尽量多测几次,进行反复确定。不然的话,你可能会发现,本来测好的功能又出现问题了,或者是本来有问题的部分又没有问题了。
知识点1:
<text wx:for="{{titles}}"wx:key="{{item}}"class="home-title {{index == activeIndex ? 'active' : ''}}" bindtap='changeClassify'>{{item.name}} </text> // index == activeIndex class为 "home-title active" 否则为 "home-title " 知识点2:
// 普通的单次循环 <text wx:for="{{titles}}" wx:key="{{index}}">{{item.name}}</text>//循环嵌套时使用 wx:for-item="XXX"<view wx:for="{{hotArr}}"> <view class="classify-title" bindtap="goClassifyPage"> <text>{{item.name}}</text> </view><view class="classify-items"> <view class="classify-item" wx:for="{{item.data}}"wx:for-item="cell" wx:key="index"> <view> <text class="classify-item_name">{{cell.name}}</text> </view> </view> </view> </view> 知识点3:
//router 跳转传参及参数获取 <text wx:for="{{titles}}" wx:key="{{index}}" bindtap='changeClassify' data-id="{{index}}">{{item.name}}</text> //js function changeClassify(e) { // let id = e.currentTarget.dataset.id;//跳转到classify 页面 wx.navigateTo({ url: '../classify/classify?id=' + id }) }//classify 页面 获取参数 onLoad: function (opts) { console.log(opts.id) console.log(this.options.id) } 知识点:4
// 上拉加载更多 onReachBottom() { if (this.data.next) { this.setData({ isHideLoadMore: false }) this.getNextPage() } } // 下拉刷新 onPullDownRefresh: function() { this.refreshData() } //this.refreshDate里一定要使用停止下拉刷新的API 知识点:5
/** * 1. 给template 设置name * 2. 组件传过来的值可以直接使用hidden="{{!isloading}}" */ <template name="loading"> <view class="qtshe-loadmore" hidden="{{!isloading}}"> <view class="qtshe-loading"></view> <view class="qtshe-loadmore-tips">正在加载</view> </view></template> ///*** 使用通用的template* 1. 按路径引入 * 2. 设置 is 等于 template的name data="{{isloading}}" 给template的数据 */ <import src="../template/loading.wxml"/> <template is="loading" data="{{isloading}}"></template> 知识点:6
<scroll-view class="recommend_scroll_x_box" scroll-x="true"> <view class="recommend_hot_box" wx:for="{{hotList}}"> <image src="{{item.pic}}" class="recommend_hot_image"></image> </view> </scroll-view> scroll-view.wxss
.recommend_scroll_x_box { height: 245rpx; white-space: nowrap; display: flex; }::-webkit-scrollbar { width: 0; height: 0; color: transparent; }.recommend_hot_box { width: 230rpx; height: 245rpx; margin-right: 24rpx; display: inline-block; }.recommend_hot_image { width: 230rpx; height: 143rpx; } scroll-view.js
Page({ data: { hotList: [ { pic: 'https://ojlf2aayk.qnssl.com//act/1501760559/banner.png' }, { pic: 'https://ojlf2aayk.qnssl.com//act/1501760559/banner.png' }, { pic: 'https://ojlf2aayk.qnssl.com//act/1501760559/banner.png' }, { pic: 'https://ojlf2aayk.qnssl.com//act/1501760559/banner.png' }, { pic: 'https://ojlf2aayk.qnssl.com//act/1501760559/banner.png' } ] } 完美解决
微信小程序下拉刷新在苹果机上 会上弹
原因是:onPullDownRefresh和showLoading或者showModel同时使用
然而很多需求是需要下拉刷新的时候顺便加载个showLoading。
现在的解决方法只能避免两个API同时出现,使用onPullDownRefresh的时候不使用showLoading或者showModel
小程序获取二维码的问题
因为前端通过小程序官方提供的接口获取到的是个二进制的流,使用小程序自带的image标签是不能进行展示的,并且前端暴露AppID和AppSecret密钥不安全,所以这里的操作都是需要后端来进行的,此时交给后端进行转换并返回一张小程序码的图片给你。
前端只需要拿到后端返回图片的图片展示即可。现与后端约定:
我给页面page(第一,第三个接口是path)路径,以及需要的scene字段。
期间遇到的问题:scene字段是什么?我怎么拿到?
期间设想scene是扫码后才能拿到的场景值,注意是扫码后才会有,那我怎么生成小程序码,这里陷入一个误区了。
其实scene在这里你可以理解为传参数的一个字段。
⚠️第一个第三个接口是不需要传入scene字段的且字段为path
path: 'pages/index/index?jobId=111111' //此时字段是path ⚠️第二个接口是需要的且字段为page
scene: 'jobId=111111',//(string类型) page: 'pages/index/index' //此时字段是page注意前面不要加'/' ⚠️生成的小程序码都是只能跳转线上的小程序页面,如果线上没有页面是跳转不了的,当然跳转后需要在我要跳转的页面onLoad里拿到scene字段然后进行逻辑操作
使用如下代码可以获取到二维码中的 scene 字段的值。调试阶段可以使用开发工具的条件编译自定义参数 scene=xxxx 进行模拟,开发工具模拟时的 scene 的参数值需要进行 encodeUrl
Page({ onLoad: function(options) { // options 中的 scene 需要使用 decodeURIComponent 才能获取到生成二维码时传入的 scene var scene = decodeURIComponent(options.scene) } }) <view class="canvas-box" wx:if="{{isCanvas}}"> <canvas style="width: {{canvasWidth}}px; height: {{canvasHeight}}px; margin:0 auto;" canvas-id="mycanvas" /> </view> //将title绘制到canvas的固定位置 setName(context) { var unit = this.data.screenWidth / 375 var title = this.data.partJobVo.title context.setFontSize(18) context.setFillStyle('#333333') context.save() context.translate(24 * unit, 40 * unit) //必须先将旋转原点平移到文字位置 context.fillText(title, 0, 0) //必须为(0,0)原点 context.restore() context.stroke() }, //将金额绘制到canvas的固定 setMoney(context) { var unit = this.data.screenWidth / 375 var money = this.data.partJobVo.salary context.setFontSize(22) context.setFillStyle('#FF2A52') context.fillText(money, 24 * unit, 80 * unit) context.stroke() }, setQrcode(context) { var unit = this.data.screenWidth / 375 let path = this.data.qtPath context.drawImage(path, 200 * unit, 50 * unit, 120 * unit, 120 * unit) }, //将canvas转换为图片保存到本地,然后将图片路径传给image图片的src createNewImg() { var that = this var unit = this.data.screenWidth / 375 var context = wx.createCanvasContext('mycanvas') var path = that.data.qtPaths context.drawImage(path, 0, 0, 343 * unit, 220 * unit) that.setMoney(context) that.setName(context) that.setQrcode(context) //绘制图片 context.draw() context.save() //将生成好的图片保存到本地,需要延迟一会,绘制期间耗时 setTimeout(() => { wx.canvasToTempFilePath({ canvasId: 'mycanvas', success: function(res) { wx.hideLoading() that.setData({ imagePath: res.tempFilePath }) }, fail: function(res) { console.log(res.errMsg) } }) }, 2000) }, savePhoto() { var that = this wx.showLoading({ title: '正在保存...', mask: true }) setTimeout(() => { wx.saveImageToPhotosAlbum({ filePath: that.data.imagePath, success(res) { that.wetoast.toast({ title: '保存成功', duration: 1500 }) setTimeout(() => { wx.hideLoading() that.setData({ isCanvas: false, isXcxCode: false }) }, 300) }, fail() { that.wetoast.toast({ title: '保存失败,请重试', duration: 1500 }) setTimeout(() => { wx.hideLoading() that.setData({ isCanvas: false, isXcxCode: false }) }, 300) } }) }, 2000) } 测试(IOS6.5.22有问题,安卓6.5.23有问题)其他版本都是好的,微信客户端的问题,后端也是可以截图的,但是因为暂时没有资源,最后导致砍掉这个功能。
其他坑,也有很多小的坑,就不一一说了。遇到了你可以来问下我,万一我早就遇到并解决了呢。(联系方式就留在最下边吧,毕竟还要打一波广告)
1、模拟器可以在模拟器上看效果,上面讲到了运行底层不同,效果跟在手机上运行有些差异(感谢运营小姐姐的美图)
image.png 2.真机预览,点预览会生产一个二维码,用管理员微信号扫一扫就可以在真机上看实际效果
image.png
image.png 坑挺多的,不过业务前景还是挺不错的,小程序最近出了小游戏。看了一下源代码,头疼ing。
再推荐一波开源的demo:
招聘岗位:高级前端开发工程师P5及以上
坐标杭州市余杭区文一西路1380号金之源大厦11层
简历投递到:hr@qtshe.com||haochen@qtshe.com
职位描述:
1、建设工具、提炼组件、抽象框架,促进前端工程化、服务化,持续提升研发效率,保障线上产品质量
2、构建H5/PC应用基础设施,主导建设前端各种发布/监控等平台,指导落实解决方案
3、持续优化前端页面性能,维护前端代码规范,钻研各种前沿技术和创新交互,增强用户体验、开拓前端能力边界