微信小程序开发【一】-- 初识小程序 传送门
微信小程序开发【二】-- 小程序入门 传送门
微信小程序开发【三】-- 项目结构概述 传送门
微信小程序开发【四】-- 配置详解 传送门
微信小程序开发【五】-- wxml详解 传送门
微信小程序开发【六】-- wxss详解 传送门
微信小程序开发【七】-- js详解 传送门
微信小程序开发【八】-- 页面栈和模块化 传送门
微信小程序开发【九】-- 初识小程序云开发 传送门
微信小程序开发【十】-- 云函数/云数据库/云存储 传送门
框架的视图层由WXMKL(WeiXin Markup language)与WXSS(WeiXin Style Sheet)编写,由组件进行展示。
微信小程序在逻辑层将数据进行处理后发送给视图层展现出来,同时接受视图层的事件反馈。
WXML是框架设计的一套类似HTML的标签语言,结合基础组件、事件系统,可以构建出页面的结构,即.wxml文件。
.wxml文件第一行建议写<!--页面名.wxml-->
<!--logs.wxml-->
<view class="container log-list">
<block wx:for="{{logs}}" wx:for-item="log">
<text class="log-item">{{index+1}}.{{log}}</text>
</block>
</view>
通过view组件控制页面内容展现,通过block组件与text组件实现页面数据绑定。
WXML具有数据绑定、列表渲染、条件渲染、模板及事件绑定的能力。
.wxml文件中的动态数据均来自对应页面的.js文件中Page的data对象。
<!--wxml-->
<view>{{message}}</view>
//page.js
Page({
date:{
message:'Hello MINA!'
}
})
<!--wxml-->
<view id="item-{{id}}"></view>
//page.js
Page({
data:{
id:0
}
})
<!--wxml-->
<view wx:if="{{condition}}"></view>
//page.js
Page({
data:{
condition:true
}
})
<!--wxml-->
<!--①-->
<view hidden="{{flag ? true : false}}">Hidden</view>
<!--②-->
<view>{{a + b}} + {{c}} + d </view>
//page.js
Page({
data:{
a:1,
b:2,
c:3
}
})
<!--③-->
<view wx:if="{{length > 5}}"></view>
<!--④-->
<view>{{"hello" + name}}</view>
//page.js
Page({
data:{
name:'MINA'
}
})
<!--⑤-->
<view>{{object.key}}{{array[0]}}</view>
//page.js
Page({
data:{
object:{
key:'Hello'
},
array:['MINA']
}
})
<!--wxml-->
<view wx:for="{{zero,1,2,3,4}}">{{item}}</view>
//page.js
Page({
data:{
zero:0
}
})
最终组合成数组[0,1,2,3,4]。
<!--wxml-->
<template is="objectCombine" data="{{for:a,bar:b}}"></template>
//page.js
Page({
data:{
a:1,
b:2
}
})
最终组合成的对象是{{for:1,bar:2}}。
列表语句可用于.wxml中进行列表渲染,将列表中的各项数据进行重复渲染。
<!--wxml-->
<view wx:for="{{items}}">
{{index}}:{{item.message}}
</view>
//page.js
Page({
data:{
items:[{
message:'foo'
},{
message:'bar'
}]
}
})
<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
{{idx}}:{{itemName.message}}
</view>
<view wx:for="{{[1,2,3,4,5,6,7,8,9]}}" wx:for-item="i">
<view wx:for="{{[1,2,3,4,5,6,7,8,9]}}" wx:for-item="j">
<view wx:if="{{i<=j}}">
{{i}} * {{j}} = {{i*j}}
</view>
</view>
</view>
条件语句可用于.wxml中进行条件渲染,不同的条件进行不同的渲染。
<!--wxml-->
<view wx:if="{{view == 'WEBVIEW'}}">WEBVIEW</view>
<view wx:elif="{{view == 'APP'}}">APP</view>
<view wx:else="{{view == 'MINA'}}">MINA</view>
//page.js
Page({
data:{
view:'MINA'
}
})
<block wx:if="{{true}}">
<view> view1 </view>
<view> view2 </view>
</block>
注:<block/>并不是一个组件,他仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性。
wx:if 和 hidden的区别:
因为wx:if之中的模块也可能包含数据绑定,所以当wx:if的条件值切换时,框架由一个局部渲染的过程,从而确保条件块在切换时销毁或重新渲染。
同时wx:if也是惰性的,如果在初始渲染条件为false,框架什么也不做,在条件第一次变成真的时候才开始局部渲染。相比之下,hidden就简单的多,组件始终会被渲染,只需简单地控制显示与隐藏。
一般来说,wx:if有更高的切换消耗,而hidden有更高的初始渲染消耗。因此,如果需要频繁切换的情况下,用hidden更好;如果运行时条件不大可能改变,则wx:if较好。
WXML支持模板(template),可以在模板中定义代码片段,然后在不同的地方调用。
<!--wxml-->
<template name="staffName">
<view>
FirstName:{{firstName}},LastName:{{lastName}}
</view>
</template>
<template is="staffName" data="{{...staffA}}"></template>
<template is="staffName" data="{{...staffB}}"></template>
<template is="staffName" data="{{...staffC}}"></template>
//page.js
Page({
data:{
staffA:{firstName:'Hulk',lastName:'Hu'},
staffB:{firstName:'Shang',lastName:'You'},
staffC:{firstName:'Gideon',lastName:'Lin'},
}
})
“…”为扩展运算符,用来展开一个对象,如staffA对象。
<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>
模板拥有自己的作用域,只能使用data传入的数据。
我们小程序与用户交互,多数情况下是通过事件来进行的。首先,在组件中绑定一个事件处理函数。在下面代码中,我们使用bindtap,当用户点击该组件view时会在该页面对应Page中找到相应的事件处理函数add。
<!--wxml-->
<!--指定view组件的唯一标识tapTest;自定义属性hi,其值为MINA;绑定事件add-->
<view id="tapTest" data-hi="MINA" bindtap="add">{{count}}</view>
注:应将bindtap理解为:bind+tap,即绑定冒泡事件tap(手指触摸后离开)。
其次,在相应的Page定义中写上相应的事件处理函数。
//page.js
Page({
data:{
count:1
},
add:function(e){
this.setData({
count:this.data.count + 1
})
}
})
微信小程序里的事件分为冒泡事件和非冒泡事件:
类型 | 触发条件 |
---|---|
touchstart | 手指触摸动作开始 |
touchmove | 手指触摸后移动 |
touchcancel | 手指触摸动作被打断,如来电提醒、弹窗 |
touchend | 手指触摸动作结束 |
tap | 手指触摸后马上离开 |
longtap | 手指触摸后,超过350ms再离开 |
除上表之外的其他组件自定义时间都是非冒泡事件。
事件绑定的写法同组件属性,以key,value的形式。
注:bind事件绑定不会阻止冒泡事件向上冒泡,catch事件绑定可以阻止冒泡事件向上冒泡。
举例:
<view id="outter" bindtap="handleTap1">
outer view
<view id="middle" catchtap="handleTap2">
middle view
<view id="inner" catchtap="handleTap3">
inner view
</view>
</view>
</view>
点击id为inner的组件会先后触发handleTap3和handleTap2,不会触发handleTap1。
如无特殊说明,当组件触发事件时,逻辑层绑定该事件的处理函数会收到一个事件对象,事件对象具有属性如下:
属性 | 类型 | 说明 |
---|---|---|
type | String | 事件类型 |
timeStamp | Integer | 事件生成时的时间戳 |
target | Object | 触发事件的组件的一些属性值集合 |
currentTarget | Object | 当前组件的一些属性值集合 |
属性 | 类型 | 说明 |
---|---|---|
detail | Object | 额外的信息 |
属性 | 类型 | 说明 |
---|---|---|
touches | Array | 触摸事件,当前停留在屏幕中的触摸点信息数组 |
changedTouches | Array | 触摸事件,当前变化的触摸点信息数组 |
type:通用事件类型。
timeStamp:页面打开到触发事件所经过的毫秒数
target:触发事件的源组件。是一个对象,具有以下三个属性:
属性 | 类型 | 说明 |
---|---|---|
id | String | 事件源组件id |
tagName | String | 当前组件的类型 |
dataset | Object | 事件源组件上由data-开头的自定义属性组成的集合 |
currentTarget:事件绑定的当前组件。与target类似,是一个对象,同样具有上表三个属性。
touches:触摸点数组,每个触摸点包含以下属性。
属性 | 类型 | 说明 |
---|---|---|
identifier | Number | 触摸点的标识符 |
pageX,pageY | Number | 距离文档左上角的距离,文档的左上角为原点,横向为X轴,纵向为Y轴 |
clientX,clientY | Number | 距离页面可显示区域(屏幕除去导航条)左上角距离,横向为X轴,纵向为Y轴 |
changedTouches:数据格式同touches。表示有变化的触摸点。
detail:指特殊事件所携带的数据。如表单组件的提交事件会携带用户的输入,媒体的错误事件会携带错误信息。
WXML提供两种文件引入方式:import和include。
<!--item.wxml-->
<template name="item">
<text>{{text}}</text>
</template>
<import src="item.wxml">
<template is="item" data="{{text:'forbar'}}"/>
import有作用域,只会引用目标文件中定义的template,而不会引用目标文件嵌套import的template。
<!--index.wxml-->
<include src="header.wxml"/>
<view> body</view>
<include src="footer.wxml"/>
<!--header.wxml-->
<view> header </view>
<!--footer.wxml-->
<view> footer </view>
对于微信小程序而言,视图层就是所有.wxml文件与.wxss文件的集合。视图层以给定的样式展现数据并将时间反馈给逻辑层,而数据展现是以组件来进行的。组件(Component)是视图的基本单元,是构建.wxml文件必不可少的。
对于小程序的WXML编码开发,我们基本上可以认为就是使用组件、结合事件系统,构建页面结构的过程。.wxml文件中所绑定的数据,均来自于对应页的.js文件中Page方法的data对象。