微信小程序从发布开始,可谓赚足了眼球,一度引发了开发界“全民学JavaScript”的梗。
为了跟上时代步伐,我们NOW直播团队也在发布后第一时间尝鲜,本文就来扒一扒这几天试水小程序开发的那些事。
想要开发微信小程序,首先必须要有一个微信公众平台小程序的帐号(目前帐号只有内测邀请唯一途径),此帐号用于获取app id、secret id、添加开发者等管理后台操作。
然后你需要下载官方提供的微信web开发者工具,这是一个集成了编码、调试、预览、发布功能的一个IDE。
编码功能:
调试功能,集成了chrome开发者工具,可以实现样式预览、JS断点调试等:
发布、预览功能,可以在此上传你的程序,预览生成二维码,提供在手机微信上预览小程序的功能;另外,开发者工具还集成了ES6编译、代码压缩等基础代码构建功能:
对于哪怕是只有一点点web前端经验的开发者来说,微信小程序的入门门槛简直是低到不能再低了。
一个小程序的主要文件目录简洁到如下:
├─ app.json
├─ app.wxss
├─ app.js
└── pages
├─ index
│ ├─ index.wxml
│ ├─ index.wxss
│ └─ index.js
└─ my-page
├─ my-page.json
├─ my-page.wxml
├─ my-page.wxss
└─ my-page.js
一个小程序大体上分为两大块:
应用实例app
页面pages
小程序会读取根目录的app.json
,app.js
,app.wxss
生成程序实例,当然样式文件不是必需的。
app.json
// app.json
{
"pages":[
"pages/index/index"
],
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "WeChat",
"navigationBarTextStyle":"black"
}
}
在这个文件里可以针对以下内容作小程序的全局配置:
页面文件的路径
网络超时时间
程序级tab配置
窗口颜色
手机导航栏、小程序标题栏的背景色、字体色,下图是设置了导航栏颜色为绿色的效果:
app.js
每一个小程序都是通过App({/*configs*/})
这样一个App方法来注册的,在其具体的配置中,我们可以监听并处理程序级的生命周期函数、声明全局变量。比如,需要设置程序启动、显示时的一些操作,设置一些程序全局的数据、变量、方法,都可以在这里完成。
//app.js
App({
onLaunch: function () {
// do something
},
global: {
data: null
}
})
在app.js
里声明的属性及方法,都可以在小程序的任意页面里访问到:
// page.js
//获取应用实例
var app = getApp()
Page({
doSth: function() {
console.log(app.globalData);
}
})
app.js里支持的的程序级的生命周期回调包括:
onLaunch 小程序初始化完成时触发
onShow 启动,从后台进入前台显示时触发
onHide 从前台进入后台时触发
一个页面简单讲可以理解成小程序的一个完整界面单元,每一次完整的界面切换就是page
之间的跳转,下图演示一个典型的页面切换、回退过程:
一个页面的组成部分包括:
视图层
WXML(WeiXin Markup language)
用于描述页面的结构
WXSS(WeiXin Style Sheet)
用于描述页面的样式,非必需
逻辑层
JS
控制页面行为及数据变化
JSON
页面级配置,非必需
视图层与逻辑层统一通过数据
和事件
相互联系起来,用一句话描述就是:数据驱动。
如果你有使用过React、Vue(或其他MVVM框架)等,对于“数据驱动”肯定一点都不陌生了,没错,小程序毫无疑问吸收了这一开发理念。
来看看一个简单页面的代码:
<!--index.wxml-->
<view bindtap="bindViewTap" class="userinfo">
<image class="userinfo-avatar" src="{{userInfo.avatarUrl}}"></image>
<text class="userinfo-nickname">
{{userInfo.nickName}}
</text>
</view>
//index.js
Page({
data: {
userInfo: {
nickName: 'test',
avatarUrl: 'https://a.com/test.png'
}
},
//事件处理函数
bindViewTap: function() {
console.log('触发了tap');
}
})
这段代码实现的是一个简单的页面效果:
可以看到出:
每一个“页面”,都是通过JS逻辑层的Page({/*configs*/})
方法来注册的;
WXML统一通过{{data}}
花括号的方式来引用逻辑层的数据;
视图层通过bind
+event key
来和逻辑层的事件回调实现绑定;
当逻辑层需要控制视图层变化时,统一通过关键函数setData
来驱动数据变化,间接改变视图,如:
//index.js
Page({
data: {
userInfo: {
nickName: 'test',
avatarUrl: 'https://a.com/test.png'
}
},
//事件处理函数
bindViewTap: function() {
console.log('触发了tap');
this.setData({
userInfo: {
nickName: 'test',
avatarUrl: 'https://a.com/change.png'
}
});
}
})
上述代码中,setData
调用后,页面图片就变化了。setData
与React中的setState
真的是有相当的相似之处。
其实,微信小程序是完全不支持DOM操作的,千万不要想着手动去控制DOM结构。简单的说,HTML5开发中BOM的那一整套API都没法使用,包括window、document ......
WXML在近似于HTML外,吸收了很多其他模板标记语言的优点,例如支持:
<view wx:if="{{length > 5}}"> 1 </view>
<view wx:elif="{{length > 2}}"> 2 </view>
<view wx:else> 3 </view>
<view wx:for="{{items}}">
{{index}}: {{item.message}}
</view>
前面已经提到过事件绑定,前端人对于事件还是非常熟悉的,事件是视图层到逻辑层的通讯方式。
小程序支持的事件类型包括有:
和web事件类似,小程序也支持冒泡事件和非冒泡事件,在绑定过程中通过bind
(冒泡)和catch
(非冒泡)区分:
<!--page.wxml-->
<view id="outter" bindtap="handleTap1">
outer view
<view id="middle" catchtap="handleTap2">
middle view
<view id="inner" bindtap="handleTap3">
inner view
<view id="inner-inner" bindtap="handleTap4">
inner-inner view
</view>
</view>
</view>
</view>
//page.js
Page({
data: {
},
handleTap1: function () {
console.log(1);
},
handleTap2: function () {
console.log(2);
},
handleTap3: function () {
console.log(3);
},
handleTap4: function () {
console.log(4);
}
})
上述程序中,middle view
是关键分割点,点击inner-inner view
,将会依次显示4,3,2
,因为middle view
中使用了catch
来绑定事件并阻止事件往上层冒泡,middle view
及其子组件的tap冒泡事件都会在它这一层被截断。
WXML文件中,组件是视图的基本组成单元,类似HTML的提供的各种标签,小程序提供了非常全面的组件:
UI容器
滚动UI容器
轮播组件
文本容器
视屏、音频
表单组件 (输入框、单/复选、滑动选择等等navtive表单组件),下图示例是一个在HTML环境中不好实现的picker组件,通过调用native,来实现丝般顺滑的体验:
弹窗
loading
地图展示
画布(canvas)
......
关于样式,其实没有什么好说的,作为小程序的UI描述语言,几乎与CSS无异,写法、支持的属性也一样。不过,样式文件不是必需的,并且,页面级的样式会优先于全局样式,即index.wxss
的样式声明优先级会高于app.wxss
。
前面有说到,页面作为小程序的界面单元,那么肯定就有页面间的切换、跳转、后退等。
以下程序是一个简单的通过tap动作触发页面切换程序:
<!--index.wxml-->
<view class="container">
<text class="a">index</text>
<text>go to </text>
<text class="link" bindtap="bindViewTap">my-page</text>
</view>
// index.js
Page({
data: {
},
//事件处理函数
bindViewTap: function() {
wx.navigateTo({
url: '../logs/logs'
})
}
})
除了使用wx.navigateTo
方法外,还可以使用wx. redirectTo
,这两者的区别是,前者打开的页面中,可以直接返回原来页面切换前的状态;而后者则是完全关闭当前页面打开新页面,返回时,原来的页面只能“重新渲染”。
区别于HTML5应用,小程序为每个页面提供了一些更强大的生命周期和用户操作回调函数:
以往的产品开发中,如果选用HTML5来开发,性能上一般会比native要差一些,而选用native开发,则一般有比较长的版本发布周期。
微信小程序的出现,使得我们在开发native应用的同时,再也不用忍受漫长的版本发布,只要我们编写好了小程序上传,微信就可以通过后台实现客户端的热更新,在产品性能、发布体验上,都达到了质的提升。
虽然开发小程序非常接近于HTML5开发,但是本质上,它已经不再是web,它更像是React Native这样的native开发框架,通过JSBridge
,串联起native底层和上层的JS、WXML逻辑。
它通过封装微信客户端提供的文件系统、网络通信、任务管理、数据安全等基础功能,对上层提供了一套完整的API,使得开发者能够非常方便的使用到微信客户端提供的各种基础功能,快速构建一个应用。
所以,在以前HTML5阶段无法实现或实现起来相当困难的一些功能,在小程序时代将会变得非常简单。
小程序为我们提供了丰富、简单的微信原生API,可以方便的调起微信提供的能力或一些系统原生能力:
http请求(ajax)
文件上传、下载
websocket
本地图片、音频、视频的预览、播放
本地音频的暂停、进度等控制
视频、音频录制、预览、上传
设备网络状态
系统信息(手机型号、设备像素比等)
设备重力感应
罗盘
地理位置信息
动画、绘图
数据缓存,类似HTML5的localstorage,同样有5M的数据存储限制
微信支付
模板消息(服务通知)
......
小程序严格限定了代码的文件、目录结构,即同名依赖识别:
├ pages
├─ index
│ ├─ index.wxml
│ ├─ index.wxss
│ └─ index.js
└─ my-page
├─ my-page.json
├─ my-page.wxml
├─ my-page.wxss
└─ my-page.js
至少在应用、页面的核心代码这一块,开发者没有必要也不允许自定义自己的目录结构;
另外,结合官方提供的开发者工具,无需操心ES6的编译、代码压缩等构建问题。
微信小程序的出现,给我们带来了接近HTML5、跨平台的开发体验,带来了接近原生应用的产品体验,然而在我们的实践中,还是品尝到了一些不是那么完美的体验。
小程序确实提供了类似HTML5的video
组件,用于视频播放,然而把它远远还没达到HTML5的video
那么强大:
个人直播业务,基本所有的主播信息、点赞、评论、礼物等等展示都是覆盖于视频之上,如下图:
可是目前的小程序里提供的video组件,会强制所有其他元素必须在其之下,类似CSS中的z-index值,它永远是最高的,这样想通过absolute定位等方式实现漂浮礼物动效等业务需求,变得不可行。
小程序提供了一个HTTP请求接口wx.request({/*configs*/})
,可以实现类似Ajax的功能,然而当我们使用现有的业务接口时,却遇到了困难。
在浏览器环境下,我们的后台接口作了很多安全限制,最基本的一项就是请求的referer限制,必须是本域请求才能通过。然而,微信小程序明确规定,wx.request
这个方法中不允许设置Referer。所以,如果你们的业务有类似我们的这样的后台接口时,会面临一些接口改造。
我们正常的web业务,前后端通信中,对cookie的依赖是无处不在的,但是,小程序作为本质上的native应用,请求是没有cookie的,我们的程序中,也没有办法拿到cookie,所以,对于很多现有的业务接口,直接兼容微信小程序,恐怕没那么简单。
小程序提供的唯一鉴权方案需要通过小程序客户端、业务服务端、微信平台服务器三方沟通来实现,具体可以看微信官方文档架构图:
其实,以上就是目前大部分开发平台使用的OAuth 2.0标准鉴权方案。
可能是小程序出于战略考虑,设计上还是相对封闭的,想通过小程序打通现有的业务,包括APP、HTML5网站等等,甚至微信公众号,都会受到一些限制。
我们曾想过在小程序里提供常见的长按公众号二维码识别进入关注界面的功能,目前是无法实现的;另外,想通过小程序打开现有的web页面、调起系统现有的APP等,目前也是不支持的。