赞
踩
小程序包含一个描述整体程序的 app 和多个描述各自页面的 page。
一个小程序主体部分由三个文件组成,必须放在项目的根目录:
app.js描述小程序逻辑。其中App() 函数用来注册一个小程序,接受一个 Object 参数,其指定小程序的生命周期回调,该函数只会调用一次,一般会在小程序启动时调用。
app.json是小程序公共配置。app.json 文件用来对微信小程序进行全局配置,决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等。
以谷坡家小程序代码为例:
页面文件路径:
窗口表现:
设置多 tab:
app.wxss是小程序公共样式表。定义小程序全局样式,作用于每一个页面。
一个小程序页面由四个文件组成,分别是:
js描述页面逻辑。通过Page(Object) 函数用来注册一个页面。接受一个 Object 类型参数,其指定页面的初始数据、生命周期回调、事件处理函数等。
以谷坡家登录界面为例:
页面初始数据:
生命周期回调:
事件处理函数:
wxml描述页面结构。WXML(WeiXin Markup Language)是框架设计的一套标签语言,结合基础组件、事件系统,可以构建出页面的结构。类似android中的.xml文件。
json文件用于当前页面配置。每一个小程序页面可以使用.json文件来对本页面的窗口表现进行配置。页面的配置只能设置 app.json 中部分 window 配置项的内容,页面中配置项会覆盖 app.json 的 window 中相同的配置项。
WXSS
WXSS(WeiXin Style Sheets)是一套样式语言,用于描述 WXML 的组件样式。
WXSS 用来决定 WXML 的组件应该怎么显示。
为了适应广大的前端开发者,WXSS 具有 CSS 大部分特性。同时为了更适合开发微信小程序,WXSS 对 CSS 进行了扩充以及修改。
与 CSS 相比,WXSS 扩展的特性有:
尺寸单位
样式导入
尺寸单位
rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
px与rpx之间转换的公式:px = rpx / 750 * wx.getSystemInfoSync().windowWidth;
样式导入
使用@import语句可以导入外联样式表,@import后跟需要导入的外联样式表的相对路径,用;表示语句结束。
示例代码:
/** common.wxss **/
.small-p {
padding:5px;
}
/** app.wxss **/
@import "common.wxss";
.middle-p {
padding:15px;
}
下图说明了 Page 实例的生命周期。
onLoad(Object query)
页面加载时触发。一个页面只会调用一次,可以在 onLoad 的参数中获取打开当前页面路径中的参数。
onShow()
页面显示/切入前台时触发。
onReady()
页面初次渲染完成时触发。一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互。
onHide()
页面隐藏/切入后台时触发。 如 navigateTo 或底部 tab 切换到其他页面,小程序切入后台等。
onUnload()
页面卸载时触发。如redirectTo或navigateBack到其他页面时。
事件是视图层到逻辑层的通讯方式。
事件可以将用户的行为反馈到逻辑层进行处理。
事件可以绑定在组件上,当达到触发事件,就会执行逻辑层中对应的事件处理函数。
事件对象可以携带额外信息,如 id, dataset, touches。
事件的使用方式
在组件中绑定一个事件处理函数。
如bindtap,当用户点击该组件的时候会在该页面对应的Page中找到相应的事件处理函数。
在相应的Page定义中写上相应的事件处理函数,参数是req。
可以看到log出来的信息大致如下:
{
"type":"tap",
"timeStamp":7996,
"target":{
"id":"",
"offsetLeft":50,
"offsetTop":322,
"dataset":{
}
},
"currentTarget":{
"id":"",
"offsetLeft":50,
"offsetTop":322,
"dataset":{
}
},
"detail":{
"x":299,
"y":353
},
"touches":[
{
"identifier":0,
"pageX":299,
"pageY":353,
"clientX":299,
"clientY":353,
"force":1
}
],
"changedTouches":[
{
"identifier":0,
"pageX":299,
"pageY":353,
"clientX":299,
"clientY":353,
"force":1
}
],
"_requireActive":true
}
事件分为冒泡事件和非冒泡事件:
冒泡事件:当一个组件上的事件被触发后,该事件会向父节点传递。
非冒泡事件:当一个组件上的事件被触发后,该事件不会向父节点传递。
WXML的冒泡事件列表:
除上表之外的其他组件自定义事件如无特殊声明都是非冒泡事件,如<form/>的submit事件,<input/>的input事件,<scroll-view/>的scroll事件。
事件绑定的写法同组件的属性,以 key、value 的形式。
key 以bind或catch开头,然后跟上事件的类型,如bindtap、catchtouchstart。自基础库版本 1.5.0 起,在非原生组件中,bind和catch后可以紧跟一个冒号,其含义不变,如bind:tap、catch:touchstart。
value 是一个字符串,需要在对应的 Page 中定义同名的函数。不然当触发事件的时候会报错。
bind事件绑定不会阻止冒泡事件向上冒泡,catch事件绑定可以阻止冒泡事件向上冒泡。
观察下面的例子
<view class="outer" bindtap="handleTap1">
outer view
<view class="middle" bindtap="handleTap2">
middle view
<view class="inner" bindtap="handleTap3">inner view</view>
</view>
</view>
首先,对outer view、middle view、inner view绑定bindtap事件,点击inner view,打印log如下:
从上面的log发现点击inner view不仅触发了inner view的tap事件,同时还触发了middle view和 outer view的tap事件。
修改middle view为catchtap:
<view class="outer" bindtap="handleTap1">
outer view
<view class="middle" catchtap="handleTap2">
middle view
<view class="inner" bindtap="handleTap3">inner view</view>
</view>
</view>
此时点击inner view,打印log如下:
从上面的log发现点击inner view只触发了inner view和middle view 的tap事件。
自基础库版本 1.5.0 起,触摸类事件支持捕获阶段。捕获阶段位于冒泡阶段之前,且在捕获阶段中,事件到达节点的顺序与冒泡阶段恰好相反。需要在捕获阶段监听事件时,可以采用capture-bind、capture-catch关键字,后者将中断捕获阶段和取消冒泡阶段。
<view class="outer" bind:touchstart="handleTap1" capture-bind:touchstart="handleTap2">
outer view
<view class="inner" bind:touchstart="handleTap3" capture-bind:touchstart="handleTap4">inner view</view>
</view>
上上面log发现点击 inner view 会先后调用handleTap2、handleTap4、handleTap3、handleTap1
如果将上面代码中的第一个capture-bind改为capture-catch,将只触发handleTap2。
<view class="outer" bind:touchstart="handleTap1" capture-catch:touchstart="handleTap2">
outer view
<view class="inner" bind:touchstart="handleTap3" capture-bind:touchstart="handleTap4">inner view</view>
</view>
从上述log发现,只触发了handleTap2。
如无特殊说明,当组件触发事件时,逻辑层绑定该事件的处理函数会收到一个事件对象。
BaseEvent 基础事件对象属性列表:
type代表事件的类型。timeStamp页面打开到触发事件所经过的毫秒数。target触发事件的源组件。其中target对象的dataset属性表示事件源组件上由data-开头的自定义属性组成的集合。currentTarget事件绑定的当前组件。说明: target 和 currentTarget 可以参考上例中,点击 inner view 时,handleTap3 收到的事件对象 target 和 currentTarget 都是 inner,而 handleTap2 收到的事件对象 target 就是 inner,currentTarget 就是 middle。
dataset
在组件中可以定义数据,这些数据将会通过事件传递给 SERVICE。 书写方式: 以data-开头,多个单词由连字符-链接,不能有大写(大写会自动转成小写)如data-element-type,最终在 event.currentTarget.dataset 中会将连字符转成驼峰elementType。
detail
自定义事件所携带的数据,如表单组件的提交事件会携带用户的输入,媒体的错误事件会携带错误信息,详见组件定义中各个事件的定义。
点击事件的detail 带有的 x, y 同 pageX, pageY 代表距离文档左上角的距离。
touches
touches 是一个数组,每个元素为一个 Touch 对象(canvas 触摸事件中携带的 touches 是 CanvasTouch 数组)。 表示当前停留在屏幕上的触摸点。
Page.prototype.setData(Object data, Function callback)
setData 函数用于将数据从逻辑层发送到视图层(异步),同时改变对应的 this.data 的值(同步)。
Object 以 key: value 的形式表示,将 this.data 中的 key 对应的值改变成 value。
注意:
直接修改 this.data 而不调用 this.setData 是无法改变页面的状态的,还会造成数据不一致。
仅支持设置可 JSON 化的数据。
单次设置的数据不能超过1024kB,请尽量避免一次设置过多的数据。
请不要把 data 中任何一项的 value 设为 undefined ,否则这一项将不被设置并可能遗留一些潜在问题。
在小程序中所有页面的路由全部由框架进行管理。
框架以栈的形式维护了当前的所有页面。 当发生路由切换的时候,页面栈的表现如下:
getCurrentPages()
getCurrentPages() 函数用于获取当前页面栈的实例,以数组形式按栈的顺序给出,第一个元素为首页,最后一个元素为当前页面。
注意:
不要尝试修改页面栈,会导致路由以及页面状态错误。
不要在 App.onLaunch 的时候调用 getCurrentPages(),此时 page 还没有生成。
对于路由的触发方式以及页面生命周期函数如下:
注意:
navigateTo, redirectTo 只能打开非 tabBar 页面。
switchTab 只能打开 tabBar 页面。
reLaunch 可以打开任意页面。
页面底部的 tabBar 由页面决定,即只要是定义为 tabBar 的页面,底部都有 tabBar。
调用页面路由带的参数可以在目标页面的onLoad中获取。
WXML 中的动态数据均来自对应 Page 的 data。
数据绑定使用(双大括号)将变量包起来,可以作用于:
组件属性(需要在双引号之内)
<view id="item-{{id}}"></view>
Page({
data: {
id: 0
}
})
控制属性(需要在双引号之内)
关键字(需要在双引号之内)
true:boolean 类型的 true,代表真值。
false: boolean 类型的 false,代表假值。
<checkbox checked="{{false}}"></checkbox>
特别注意:不要直接写 checked="false",其计算结果是一个字符串,转成 boolean 类型后代表真值。
可以在 {{}} 内进行简单的运算,支持的有如下几种方式:
三元运算
算数运算
<view>{{a + b}} + {{c}} + d</view>
Page({
data: {
a: 1,
b: 2,
c: 3
}
})
view中的内容为 3 + 3 + d。
逻辑判断
wx:for
在组件上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。
默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item
使用 wx:for-item 可以指定数组当前元素的变量名;
使用 wx:for-index 可以指定数组当前下标的变量名;
wx:for 也可以嵌套
wx:key
如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 <input> 中的输入内容,<switch> 的选中状态),需要使用 wx:key 来指定列表中项目的唯一的标识符。
wx:key 的值以两种形式提供
字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。
保留关键字 *this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字,如:
当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。
如不提供 wx:key,会报一个 warning, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略。
注意:
当 wx:for 的值为字符串时,会将字符串解析成字符串数组
<view wx:for="array">{{item}}</view>
等同于
<view wx:for="{{['a','r','r','a','y']}}">{{item}}</view>
条件渲染
在框架中,使用 wx:if="{{condition}}" 来判断是否需要渲染该代码块:
<view wx:if="{{condition}}">True</view>
也可以用 wx:elif 和 wx:else 来添加一个 else 块:
<view wx:if="{{length > 5}}">1</view>
<view wx:elif="{{length > 2}}">2</view>
<view wx:else>3</view>
wx:if vs hidden
因为 wx:if 之中的模板也可能包含数据绑定,所以当 wx:if 的条件值切换时,框架有一个局部渲染的过程,因为它会确保条件块在切换时销毁或重新渲染。
同时 wx:if 也是惰性的,如果在初始渲染条件为 false,框架什么也不做,在条件第一次变成真的时候才开始局部渲染。
相比之下,hidden 就简单的多,组件始终会被渲染,只是简单的控制显示与隐藏。
一般来说,wx:if 有更高的切换消耗而 hidden 有更高的初始渲染消耗。因此,如果需要频繁切换的情景下,用 hidden 更好,如果在运行时条件不大可能改变则 wx:if 较好。
WXML提供模板(template),可以在模板中定义代码片段,然后在不同的地方调用。
定义模板
使用 name 属性,作为模板的名字。然后在<template/>内定义代码片段,如:
<!--
index: int
msg: string
time: string
-->
<template name="msgItem">
<view>
<text>{{index}}: {{msg}}</text>
<text>Time: {{time}}</text>
</view>
</template>
使用模板
使用 is 属性,声明需要的使用的模板,然后将模板所需要的 data 传入,如:
<template is="msgItem" data="{{...item}}" />
Page({
data: {
item: {
index: 0,
msg: 'this is a template',
time: '2016-09-15'
}
}
})
is 属性可以使用 Mustache 语法,来动态决定具体需要渲染哪个模板:
<template name="odd">
<view>odd</view>
</template>
<template name="even">
<view>even</view>
</template>
<block wx:for="{{[1, 2, 3, 4, 5]}}">
<template is="{{item % 2 == 0 ? 'even' : 'odd'}}" />
</block>
WXS
WXS(WeiXin Script)是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构。
注意
wxs 不依赖于运行时的基础库版本,可以在所有版本的小程序中运行。
wxs 与 javascript 是不同的语言,有自己的语法,并不和 javascript 一致。
wxs 的运行环境和其他 javascript 代码是隔离的,wxs 中不能调用其他 javascript 文件中定义的函数,也不能调用小程序提供的API。
wxs 函数不能作为组件的事件回调。
由于运行环境的差异,在 iOS 设备上小程序内的 wxs 会比 javascript 代码快 2 ~ 20 倍。在 android 设备上二者运行效率无差异。
在.wxml中使用:
某些情况下,开发者需要将小程序划分成不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载。
在构建小程序分包项目时,构建会输出一个或多个分包。每个使用分包小程序必定含有一个主包。所谓的主包,即放置默认启动页面/TabBar 页面,以及一些所有分包都需用到公共资源/JS 脚本;而分包则是根据开发者的配置进行划分。
在小程序启动时,默认会下载主包并启动主包内页面,当用户用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示。
目前小程序分包大小有以下限制:
整个小程序所有分包大小不超过 8M
单个分包/主包大小不能超过 2M
对小程序进行分包,可以优化小程序首次启动的下载时间,以及在多团队共同开发时可以更好的解耦协作。
配置方法
假设支持分包的小程序目录结构如下:
开发者通过在 app.json subpackages 字段声明项目分包结构:
subpackages 中,每个分包的配置有以下几项:
开发者可以通过配置,在进入小程序某个页面时,由框架自动预下载可能需要的分包,提升进入后续分包页面时的启动速度。对于独立分包,也可以预下载主包。
配置方法
预下载分包行为在进入某个页面时触发,通过在 app.json 增加 preloadRule 配置来控制。
独立分包是小程序中一种特殊类型的分包,可以独立于主包和其他分包运行。从独立分包中页面进入小程序时,不需要下载主包。当用户进入普通分包或主包内页面时,主包才会被下载。
开发者可以按需将某些具有一定功能独立性的页面配置到独立分包中。当小程序从普通的分包页面启动时,需要首先下载主包;而独立分包不依赖主包即可运行,可以很大程度上提升分包页面的启动速度。
一个小程序中可以有多个独立分包。
配置方法
假设小程序目录结构如下:
开发者通过在app.json的subpackages字段中对应的分包配置项中定义independent字段声明对应分包为独立分包。
1. 服务器域名配置
每个微信小程序需要事先设置一个通讯域名,小程序只可以跟指定的域名与进行网络通信。包括普通 HTTPS 请求(wx.request)、上传文件(wx.uploadFile)、下载文件(wx.downloadFile) 和 WebSocket 通信(wx.connectSocket)
配置流程
服务器域名请在 「小程序后台-设置-开发设置-服务器域名」 中进行配置,配置时需要注意:
域名只支持 https (wx.request、wx.uploadFile、wx.downloadFile) 和 wss (wx.connectSocket) 协议。
2. 网络请求
超时时间
默认超时时间和最大超时时间都是 60s;
超时时间可以在 app.json 中配置。
RequestTask wx.request(Object object)用于发起 HTTPS 网络请求。
参数
UploadTask wx.uploadFile(Object object)将本地资源上传到服务器。客户端发起一个 HTTPS POST 请求,其中 content-type 为 multipart/form-data。
wx.getStorageInfo(Object object)用于异步获取当前storage的相关信息。
参数:
object.success 回调函数的参数:
Object wx.getStorageInfoSync()是wx.getStorageInfo(Object object)同步版本。
wx.setStorage(Object object)
将数据存储在本地缓存中指定的 key 中。会覆盖掉原来该 key 对应的内容。数据存储生命周期跟小程序本身一致,即除用户主动删除或超过一定时间被自动清理,否则数据都一直可用。单个 key 允许存储的最大数据长度为 1MB,所有数据存储上限为 10MB。
参数:
wx.setStorageSync(string key, any data)是wx.setStorage 的同步版本。
wx.getStorage(Object object) 从本地缓存中异步获取指定 key 的内容。
参数:
object.success 回调函数的参数:
any wx.getStorageSync(string key)是wx.getStorage 的同步版本。
wx.startPullDownRefresh(Object object) 开始下拉刷新。调用后触发下拉刷新动画,效果与用户手动下拉刷新一致。
参数:
wx.stopPullDownRefresh(Object object) 停止当前页面下拉刷新。
参数:
wx.chooseImage(Object object)从本地相册选择图片或使用相机拍照。
参数:
object.sizeType 的合法值
object.success 回调函数的参数Object res:
res.tempFiles 的结构:
InnerAudioContext wx.createInnerAudioContext()
InnerAudioContext
InnerAudioContext 实例,可通过 wx.createInnerAudioContext 接口获取实例。
属性
string src
音频资源的地址,用于直接播放。2.2.3 开始支持云文件ID
number startTime
开始播放的位置(单位:s),默认为 0
boolean autoplay
是否自动开始播放,默认为 false
boolean loop
是否循环播放,默认为 false
boolean obeyMuteSwitch
是否遵循系统静音开关,默认为 true。当此参数为 false 时,即使用户打开了静音开关,也能继续发出声音
number volume
基础库 1.9.90 开始支持,低版本需做兼容处理。
音量。范围 0~1。默认为 1
number duration
当前音频的长度(单位 s)。只有在当前有合法的 src 时返回(只读)
number currentTime
当前音频的播放位置(单位 s)。只有在当前有合法的 src 时返回,时间保留小数点后 6 位(只读)
boolean paused
当前是是否暂停或停止状态(只读)
number buffered
音频缓冲的时间点,仅保证当前播放时间点到此时间点内容已缓冲(只读)
方法
InnerAudioContext.play()
播放
InnerAudioContext.pause()
暂停。暂停后的音频再播放会从暂停处开始播放
InnerAudioContext.stop()
停止。停止后的音频再播放会从头开始播放。
InnerAudioContext.seek(number position)
跳转到指定位置
InnerAudioContext.destroy()
销毁当前实例
InnerAudioContext.onCanplay(function callback)
监听音频进入可以播放状态的事件。但不保证后面可以流畅播放
InnerAudioContext.onPlay(function callback)
监听音频播放事件
InnerAudioContext.onPause(function callback)
监听音频暂停事件
InnerAudioContext.offPause(function callback)
取消监听音频暂停事件
InnerAudioContext.offStop(function callback)
取消监听音频停止事件
InnerAudioContext.onEnded(function callback)
监听音频自然播放至结束的事件
InnerAudioContext.onTimeUpdate(function callback)
监听音频播放进度更新事件
RecorderManager wx.getRecorderManager() 获取全局唯一的录音管理器 RecorderManager。
RecorderManager
全局唯一的录音管理器
方法
RecorderManager.start(Object object)
开始录音
RecorderManager.pause()
暂停录音
RecorderManager.resume()
继续录音
RecorderManager.stop()
停止录音
RecorderManager.onStart(function callback)
监听录音开始事件
RecorderManager.onResume(function callback)
监听录音继续事件
RecorderManager.onPause(function callback)
监听录音暂停事件
RecorderManager.onStop(function callback)
监听录音结束事件
wx.getUserInfo(Object object)获取用户信息。
参数:
object.lang 的合法值:
object.success 回调函数的参数Object res:
多端统一开发框架 - Taro
Taro 是什么?
Taro 是由凹凸实验室打造的一套遵循 React 语法规范的 多端开发 解决方案。现如今市面上端的形态多种多样,Web、React-Native、微信小程序等各种端大行其道,当业务要求同时在不同的端都要求有所表现的时候,针对不同的端去编写多套代码的成本显然非常高,这时候只编写一套代码就能够适配到多端的能力就显得极为需要。
使用 Taro,我们可以只书写一套代码,再通过 Taro 的编译工具,将源代码分别编译出可以在不同端(微信/百度/支付宝/字节跳动小程序、H5、React-Native 等)运行的代码。
现代前端开发流程
和微信自带的小程序框架不一样,Taro 积极拥抱社区现有的现代开发流程,包括但不限于:
NPM 包管理系统
ES6+ 语法
自由的资源引用
CSS 预处理器和后处理器(SCSS、Less、PostCSS)
快速开发微信小程序
Taro 立足于微信小程序开发,众所周知小程序的开发体验并不是非常友好,比如小程序中无法使用 npm 来进行第三方库的管理,无法使用一些比较新的 ES 规范等等,针对小程序端的开发弊端,Taro 具有以下的优秀特性:
white_check_mark 支持使用 npm/yarn 安装管理第三方依赖。
white_check_mark 支持使用 ES7/ES8 甚至更加新的 ES 规范,一切都可自行配置。
white_check_mark 支持使用 CSS 预编译器,例如 Sass 等。
white_check_mark 支持使用 Redux 进行状态管理。
white_check_mark 支持使用 Mobx 进行状态管理。
white_check_mark 小程序 API 优化,异步 API Promise 化等等。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。