《二》微信小程序中的 WXML

WXML 用于描述页面的结构。类似于 HTML,支持写成单标签或者双标签,但是必须有严格的闭合,并且大小写敏感。

数据绑定:

WXML 中的动态数据均来自对应 Page 的 data。数据绑定使用 Mustache 语法(双大括号)将变量包起来,可以作用于:

  1. 内容:
    <view> {{ message }} </view>
    
    Page({
      data: {
        message: 'Hello MINA!'
      }
    })
    
  2. 属性:
    <view wx:if="{{condition}}"> </view>
    <view id="item-{{id}}"> </view>
    <checkbox checked="{{false}}"> </checkbox>
    
    Page({
      data: {
      	condition: true,
        id: 0,
      }
    })
    
  3. 运算:可以在 {{}} 内进行简单的运算,支持的有如下几种方式:
    • 三元运算:
      <view hidden="{{flag ? true : false}}"> Hidden </view>
      
    • 算数运算:
      <view> {{a + b}} + {{c}} + d </view>
      
    • 逻辑判断:
      <view wx:if="{{length > 5}}"> </view>
      
    • 字符串运算:
      <view>{{"hello" + name}}</view>
      
    • 数据路径运算:
      <view>{{object.key}} {{array[0]}}</view>
      
  4. 组合:也可以在 Mustache 内直接进行组合,构成新的数组或对象。
    // 数组:
    <view wx:for="{{[zero, 1, 2, 3, 4]}}"> {{item}} </view>
    // 对象
    <template is="objectCombine" data="{{for: a, bar: b}}"></template>
    

双向绑定:

在 WXML 中,普通属性的绑定是单向的。如果使用 this.setData({ value: 'Hello'}) 来更新 value ,this.data.value 和输入框的中显示的值都会被更新为 Hello ;但如果用户修改了输入框里的值,却不会同时改变 this.data.value

<input value="{{value}}" />

如果需要在用户输入的同时改变 this.data.value,需要借助双向绑定机制。此时,可以在对应项目之前加入 model: 前缀:

双向绑定同样可以使用在自定义组件上。

<input model:value="{{value}}" />

这样,如果输入框的值被改变了,this.data.value 也会同时改变,同时, WXML 中所有绑定了 value 的位置也会被一同更新, 数据监听器也会被正常触发。

双向绑定的限制:

用于双向绑定的表达式只能是一个单一字段的绑定。

// 非法
<input model:value="值为 {{value}}" />
<input model:value="{{ a + b }}" />
<input model:value="{{ a.b }}" />
自定义组件中使用双向绑定:

双向绑定同样可以使用在自定义组件上。

// custom-component.js
Component({
  properties: {
    transferValue: String
  }
})

<!-- custom-component.wxml -->
<input model:value="{{transferValue}}" />

<!-- index.wxml -->
<custom-component model:transfer-value="{{pageValue}}" />

当自定义组件的输入框的值变更时,自定义组件的 transferValue 属性会同时变更,页面的 this.data.pageValue 也会同时变更,页面 WXML 中所有绑定了 pageValue 的位置也会被一同更新。

列表渲染:

可以使用 wx:for 遍历一个数组,即可使用数组中各项的数据重复渲染组件。数组当前项的下标默认为 index,数组当前项的变量名默认为 item。

wx:for 遍历的值是字符串时,会将字符串解析成字符串数组。
wx:for 遍历的值是数字时,会从 1 开始遍历该数字。
wx:for 遍历的值是对象时,index 对应的就是 key,item 对应的就是 value。

<view wx:for="{{array}}">
  {{index}}: {{item.message}}
</view>

使用 wx:for-item 可以指定数组当前元素的变量名,使用 wx:for-index 可以指定数组当前下标的变量名。

<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
  {{idx}}: {{itemName.message}}
</view>
block wx:for

可以将 wx:for 用在 <block/> 标签上,以渲染一个包含多节点的结构块。

<block/> 就是一个占位符,自己本身并不会被渲染到页面上。

<block wx:for="{{[1, 2, 3]}}">
  <view> {{index}}: </view>
  <view> {{item}} </view>
</block>
wx:key

如果列表中项目的位置会动态改变或者会有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态,需要使用 wx:key 来指定列表中项目的唯一的标识符。

如果不提供 wx:key,会报一个 warning, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略。

wx:key 的值以两种形式提供:

  1. 字符串:表示 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。
  2. 保留关键字 *this: 表示 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字,不能是数组或对象。

和 React、Vue 类似,小程序内部也是用了虚拟 DOM,当某一层有很多相同的节点时,希望插入、删除节点时,可以更好地复用节点,因此需要 key 属性。

Page({
  data: {
    uniques: [
      {id: 4, unique: 'unique_4'},
      {id: 3, unique: 'unique_3'},
      {id: 2, unique: 'unique_2'},
      {id: 1, unique: 'unique_1'},
    ],
    numbers: [1, 2, 3, 4]
  },
})

<view wx:for="{{uniques}}" wx:key="unique"> {{item.id}} </view>
<view wx:for="{{numbers}}" wx:key="*this"> {{item}} </view>

条件渲染:

使用 wx:if 来判断是否需要渲染该代码块,也可以用 wx:elifwx:else 来添加一个 else 块。

<view wx:if="{{length > 5}}"> 1 </view>
<view wx:elif="{{length > 2}}"> 2 </view>
<view wx:else> 3 </view>
block wx:if

因为 wx:if 是一个控制属性,需要将它添加到一个标签上。如果要一次性判断多个组件标签,可以使用一个 <block/> 标签将多个组件包装起来,并在上边使用 wx:if 控制属性。

<block/> 并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性。

<block wx:if="{{true}}">
  <view> view1 </view>
  <view> view2 </view>
</block>
wx:if vs hidden:

hidden 是所有组件默认都拥有的属性。

  1. wx:if:如果条件为 true,则渲染条件块;如果条件为 false,则什么也不做。也就是说,当 wx:if 的条件值切换时,条件块会一直销毁或重新渲染,有更高的切换消耗。
  2. hidden:不论条件为 true 或者为 false,组件始终会被渲染,只是通过 display 控制显示与隐藏。有更高的初始渲染消耗。
    因此,如果需要频繁切换的情景下,用 hidden 更好,如果在运行时条件不大可能改变则 wx:if 较好。

模板:

WXML 提供模板 template,可以在模板中定义代码片段,然后在不同的地方调用。

模板拥有自己的作用域,只能使用 data 传入的数据以及模板定义文件中定义的 <wxs /> 模块。

定义模板:

<template/>内定义代码片段,使用 name 属性,作为模板的名字。

<!-- template.wxml -->
<template name="msgItem">
  <view>
    <text bindtap="handleClick"> {{index}}: {{msg}} </text>
    <text> Time: {{time}} </text>
  </view>
</template>
使用模板:
  1. 模版的引用需要用 <import> 标签,该标签的 src 属性为需要引用模版的路径。
  2. 模版的使用需要用 <template> 标签,使用 is 属性来区别模版文件中定义的模版。
  3. 在调用页面的 wxml 文件中使用 data 传入模版页面中所需要的数据。
  4. 在调用页面的 wxml 中引用了 template.wxml 后,模版的样式并不会引用, 需要在调用页面的 wxss 文件中引用 template.wxss 文件。
  5. 在调用页面的 js 文件中定义模板页面中的绑定方法。
<!-- inex.wxml -->
<import src="../tpls/template.wxml" />
<template is="msgItem" data="{{...item}}"/>

// index.js
Page({
  data: {
    item: {
      index: 0,
      msg: 'this is a template',
      time: '2016-09-15'
    }
  },
  handleClick: function(){}
})

/* index.wxss */
@import "../tpls/template.wxss"

引用:

可以对 WXML 文件进行拆分,通过 import 和 include 这两种方式进行引用。

  1. include:可以将目标文件中的除了 <template/> <wxs/> 外的整个代码引入,相当于是直接将代码拷贝到 include 所在的位置。
    // index.js
    Page({
    	data: {
    		content: '我是引入的其他 wxml 文件中的 content',
    	},
    })
    <!-- index.wxml -->
    <view>header</view>
    <include src="content.wxml"/> // include 就相当于是直接将代码拷贝过来
    <view>footer</view>
    
    <!-- content.wxml -->
    <view>{{content}}</view> // index.js data 中的数据在 content.wxml 中可以直接使用
    
    // 就相当于是:
    <!-- index.wxml -->
    <view>header</view>
    <view>我是引入的其他 wxml 文件中的 content</view>
    <view>footer</view>
    
  2. import:可以在调用文件中使用目标文件中定义的 template 模板。

    import 有作用域的概念,即只会 import 目标文件中定义的 template,而不会 import 目标文件 import 的 template。
    例如:C import B,B import A,在 C 中可以使用 B 定义的 template,在 B 中可以使用 A 定义的 template,但是 C 不能使用 A 定义的 template。

    // index.js
    Page({
    	data: {
    		content: '我是引入的其他 wxml 文件中的 content',
    	},
    })
    <!-- index.wxml -->
    <view>header</view>
    <import src="content.wxml"/>
    <template is="content" data="{{content: content}}"/>
    <view>footer</view>
    
    <!-- content.wxml -->
    <template name="content">
      <text>{{content}}</text> // 不可以直接使用 index.js data 中的数据,需要通过 data 传递进来
    </template>
    
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值