1. wxml
1.1 数据绑定
小程序中视图和数据绑定 对象数据变化直接影响视图,视图变化必须同过事件驱动才能改变对象数据
WXML中的动态数据均来自对应的
Page
的data
。数据绑定使用 Mustache 语法(双大括号将变量包起来)。
-
基本使用
<view> {{ message }} </view>
Page({ data: { message: 'Hello MINA!', name: "李白", status: 3 } })
-
绑定属性
<view data-name="{{name}}"></view>
-
支持表达式
<view hidden="{{status > 5}}">是否显示</view> <view class="{{status === 3 ? 'red' : 'blue'}}"></view> <view> {{'hello' + name}}</view>
-
更多使用方式 查看
1.2 列表渲染
<view wx:for="{{array}}">
{{index}}: {{item.message}}
</view>
Page({
data: {
array: [
{
message: 'foo',
},
{
message: 'bar'
}]
}
})
使用
wx:for-item
可以指定数组当前元素的变量名,使用wx:for-index
可以指定数组当前下标的变量名:
<view wx:for="{{array}}" wx:key="{{idx}}" wx:for-index="idx" wx:for-item="itemName">
{{idx}}: {{itemName.message}}
</view>
1.2.1 wx:key
如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 input 中的输入内容,switch 的选中状态),需要使用 wx:key 来指定列表中项目的唯一的标识符。
wx:key 的值以两种形式提供
- 字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。
- 保留关键字 *this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字。
当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。
如不提供 wx:key,会报一个 warning, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略。
<switch wx:for="{{objectArray}}" wx:key="unique" style="display: block;"> {{item.id}} </switch>
<switch wx:for="{{numberArray}}" wx:key="*this" style="display: block;"> {{item}} </switch>
objectArray: [
{id: 5, unique: 'unique_5'},
{id: 4, unique: 'unique_4'},
{id: 3, unique: 'unique_3'},
{id: 2, unique: 'unique_2'},
{id: 1, unique: 'unique_1'},
{id: 0, unique: 'unique_0'},
]
1.3 条件渲染
满足条件将会显示,不满足将会隐藏
- wx:if
<view wx:if="{{condition}}"> True </view>
也可以用
wx:elif
和wx:else
来添加一个 else 块:
<view wx:if="{{isLogin}}">已登录</view>
<view wx:else>请登录</view>
<view wx:if="{{module == 'A'}}"> A </view>
<view wx:elif="{{module == 'B'}}"> B </view>
<view wx:else> C </view>
- hidden属性
注意:hidden为true时,对应部分将隐藏,这与wx:if相反<view hidden="{{status > 5}}">是否显示</view>
1,4 class及style绑定
-
class 动态绑定
<view class="{{ isAddClass ? 'red' : '' }}"> 根据isAddClass属性是否添加red类名 </view> <button type="primary" bindtap="toggleClassName"> 点击切换类名 </button>
.red { color: red; }
Page({ data: { isAddClass: false }, toggleClassName() { this.setData({ isAddClass: !this.data.isAddClass }) } })
-
style 动态绑定
<view style="color:{{isAddRed ? 'red' : ''}}"> 根据isAddClass属性是否添加red类名 </view> <button type="primary" bindtap="toggleColor"> 点击切换颜色 </button>
Page({ data: { isAddRed: false }, toggleClassName() { this.setData({ isAddRed: !this.data.isAddRed }) } })
1.5 组件属性
-
ID/class
ID名/类名 -
style
行内样式 -
hidden
组件是否显示 -
data-*
自定义属性可以通过事件的
e.target.dataset.*
来获取设置的自定义属性<!-- wxml --> <view bindtap="clickMe" data-testId="{{testId}}"></view> // js Page({ clickMe: function(event) { var testId = event.target.dataset.testid; } })
-
注意:不要直接写 hidden=”false” , 其计算结果是一个字符串,转成 boolean 类型后代表真值。现在可以不带花括号,建议加上
-
wx:if
和hidden
都可以实现组件的显示和隐藏效果;区分场景:如果需要频繁切换,用hidden
更好;如果执行条件不大可能改变则使用wx:if
较好
1.6 组件类型
2. wxss
2.1 尺寸单位 rpx
可以根据屏幕宽度进行自适应。小程序规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
rpx 是相对于基准宽度的单位,可以根据屏幕宽度进行自适应。微信小程序 规定屏幕基准宽度 750rpx。
开发者可以通过设计稿基准宽度计算页面元素 rpx 值,设计稿 1px 与框架样式 1rpx 转换公式如下:
设计稿 1px / 设计稿基准宽度 = 框架样式 1rpx / 750rpx
换言之,页面元素宽度在 uni-app 中的宽度计算公式:
750 * 元素在设计稿中的宽度 / 设计稿基准宽度
2.1.1 举例说明:
-
若设计稿宽度为 750px,元素 A 在设计稿上的宽度为 100px,那么元素 A 在 微信小程序 里面的宽度应该设为:750 * 100 / 750,结果为:100rpx。
-
若设计稿宽度为 640px,元素 A 在设计稿上的宽度为 100px,那么元素 A 在 微信小程序 里面的宽度应该设为:750 * 100 / 640,结果为:117rpx。
-
若设计稿宽度为 375px,元素 B 在设计稿上的宽度为 200px,那么元素 B 在 微信小程序 里面的宽度应该设为:750 * 200 / 375,结果为:400rpx。
2.1.2 Tips
-
注意 rpx 是和宽度相关的单位,屏幕越宽,该值实际像素越大。如不想根据屏幕宽度缩放,则应该使用 px 单位。
-
如果开发者在字体或高度中也使用了 rpx ,那么需注意这样的写法意味着随着屏幕变宽,字体会变大、高度会变大。如果你需要固定高度,则应该使用 px 。
2.2 样式导入
使用@import
语句可以导入外联样式表,@import
后跟需要导入的外联样式表的相对路径,用;
表示语句结束。
/** common.wxss **/
.small-p {
padding:5px;
}
/** app.wxss **/
@import "common.wxss";
.middle-p {
padding:15px;
}
2.3 选择器
wxss 选择器的类型和优先级与 css 中的相同,但是伪类选择器不会在调试器的 wxml 中显示
注意:本地资源图片无法通过 WXSS 获取,可以使用网络图片,或者 base64,或者使用 image 标签
3. 小程序的事件
事件是视图层到逻辑层的通讯方式,可以将用户的行为反馈到逻辑层进行处理。事件可以绑定在组件上,触发事件后,就会执行逻辑层中对应的事件处理函数。小程序的事件对象可以查看自定义属性的值
3.1 常见事件类型
类型 | 触发条件 |
---|---|
touchstart | 手指触摸动作开始 |
touchmove | 手指触摸后移动 |
touchcancel | 手指触摸动作被打断,如来电提醒,弹窗 |
touchend | 手指触摸动作结束 |
tap | 手指触摸后马上离开 |
longpress | 手指触摸后,超过350ms再离开,如果指定了事件回调函数并触发了这个事件,tap事件将不被触发 |
longtap | 手指触摸后,超过350ms再离开(推荐使用longpress事件代替) |
3.2 事件对象
当事件回调触发的时候,会收到一个事件对象,对象的详细属性如下表所示。
属性 | 类型 | 说明 |
---|---|---|
type | String | 事件类型 |
timeStamp | Integer | 页面打开到触发事件所经过的毫秒数 |
target | Object | 触发事件的组件的一些属性值集合 |
currentTarget | Object | 当前组件的一些属性值集合 |
detail | Object | 额外的信息 |
touches | Array | 触摸事件,当前停留在屏幕中的触摸点信息的数组 |
changedTouches | Array | 触摸事件,当前变化的触摸点信息的数组 |
3.3 bind和catch
小程序通过 bind*/catch*
(*代表事件类型) 给组件添加事件;bind
方式绑定的事件会向上冒泡,catch
方式绑定的事件不会向上冒泡
<!-- 点击 inner view 会先后调用handleTap3和handleTap2(因为tap事件会冒泡到 middle view,而 middle view 阻止了 tap 事件冒泡,不再向父节点传递),点击 middle view 会触发handleTap2,点击 outer view 会触发handleTap1 -->
<view id="outer" bindtap="handleTap1">
outer view
<view id="middle" catchtap="handleTap2">
middle view
<view id="inner" bindtap="handleTap3">
inner view
</view>
</view>
</view>
常见事件类型:toushstart touchmove touchcancel touchend tap longpress longtap transitionend animationstart animationiteration animationend touchforcechange
小程序表单、swiper等组件有自己的事件类型,详情参见官方API各组件详细内容事件介绍
通过事件改变页面 data
对象内容的方式
<!-- index.wxml -->
<button bindtap="changeCount">{{count}}</button>
<!-- index.js -->
page({
data{
count: 0
},
changeCount: function (){
this.setData({
count: this.data.count ++
})
}
})
3.4 事件的捕获阶段
需要在捕获阶段监听事件时,可以采用capture-bind
、capture-catch
关键字,后者将中断捕获阶段和取消冒泡阶段
在下面的代码中,点击 inner view 会先后调用handleTap2
、handleTap4
、handleTap3
、handleTap1
<view id="outer" bind:touchstart="handleTap1" capture-bind:touchstart="handleTap2">
outer view
<view id="inner" bind:touchstart="handleTap3" capture-bind:touchstart="handleTap4">
inner view
</view>
</view>
如果将上面代码中的第一个capture-bind
改为capture-catch
,将只触发handleTap2
<view id="outer" bind:touchstart="handleTap1" capture-catch:touchstart="handleTap2">
outer view
<view id="inner" bind:touchstart="handleTap3" capture-bind:touchstart="handleTap4">
inner view
</view>
</view>
3.5 小程序传参
小程序在组件上绑定事件后,传递参数的方式不同于前端开发其他场景中直接加参数的方式,小程序在参数的传递时,采用事件对象的自定义属性的方式,具体实现如下:
wxml:
<view bindtap="passQuery" data-index="1">点击事件传参</view>
js中:
passQuery: function(e){
// 传递的参数
let query = e.currentTarget.dataset['index'];
}
这里我们需要注意一个部分,获取传递的参数可以通过下面两种方式:
1. target
触发事件的对象
2. currentTarget
绑定事件的对象
区别如下:
<view class="box" data-value="parent" bindtap="boxEvents">
父元素
<view class="inner" data-value="child">
子元素
</view>
</view>
boxEvents(e){
console.log(e)
//当点击文字为"父元素"的元素时:e.target.dataset.value结果为parent
// e.currentTarget.dataset.value结果为parent
//当点击文字为"子元素"的元素时:e.target.dataset.value结果为child
// e.currentTarget.dataset.value结果为child
// 所有 如果想要获取parent的结果 那么必须使用currentTarget去进行获取
},
3.6 小程序修改数组中某一条数据
<view wx:for="{{ arr }}" data-index = "{{index}}" bindtap="upt">
{{ item.name }}
</view>
data: {
arr:[
{
name:"张三"
},
{
name:"李四"
},
{
name:"王五"
},
]
},
upt(e){
var index = e.currentTarget.dataset.index;
var val = `arr[${index}].name`
this.setData({
[val]:"赵六"
})
},