语法

罗大富 BigRich大约 7 分钟前端

WXML 语法

对比 HTML 语法,WXML 语法除了标签/组件存在差异以外,渲染界面的方式也不一样。WXML 具有以下几种能力:

  1. 数据绑定
  2. 条件渲染
  3. 列表渲染
  4. 模板
  5. 引用

无论是数据绑定、条件渲染还是列表渲染,我们都需要用到页面中的 js 文件。我们可以打开任意一个页面文件夹下的 js 文件,都可以看到以下的这种结构:

// pages/page2/page2.js
Page({

    /* 页面的初始数据 */
    data: {

    },
    /* 生命周期函数--监听页面加载 */
    onLoad(options) {

    },

    /* 生命周期函数--监听页面初次渲染完成 */
    onReady() {

    },

    /* 生命周期函数--监听页面显示 */
    onShow() {

    },

    /* 生命周期函数--监听页面隐藏 */
    onHide() {

    },

    /* 生命周期函数--监听页面卸载 */
    onUnload() {

    },

    /* 页面相关事件处理函数--监听用户下拉动作 */
    onPullDownRefresh() {

    },

    /* 页面上拉触底事件的处理函数 */
    onReachBottom() {

    },

    /* 用户点击右上角分享 */
    onShareAppMessage() {

    }
})

Page() 是一个页面构造器,作用就是注册小程序中的一个页面。它接受一个 Object 类型参数,其指定页面的初始数据、生命周期回调、事件处理函数等。

data 是页面第一次渲染使用的初始数据。页面加载时,data 将会以 JSON 字符串的形式由逻辑层传至渲染层,因此 data 中的数据必须是可以转成 JSON 的类型:字符串,数字,布尔值,对象,数组。渲染层可以通过 WXML 对数据进行绑定。例如:

<view>{{text}}</view>
<view>{{array[0].msg}}</view>
Page({
    data: {
        text: 'init data',
        array: [{msg: '1'}, {msg: '2'}]
    }
})

1. 数据绑定

数据绑定使用 Mustache 语法(双大括号{{ }}),Mustache 语法是一种简单的模板语言,它使用大括号语法{{}}来进行变量替换和逻辑控制,例如:

//index.js 
Page({
    data: {
        message: "Hello, 微信小程序"
    }
}) 
<!--index.wxml-->
<view> {{ message }} </view> 

微信小程序是通过状态模式进行数据绑定的。状态模式定义一个对象,通过管理其状态的变化,从而让界面做出相应的变化。

简单地讲,只要对象状态发生变化,就通知页面更新视图元素。 通过以下三个步骤 可以实现:

  • 识别哪个 UI 元素被绑定了相应的对象
  • 监视对象状态的变化
  • 将所有变化传播到绑定的视图上

.wxml 文件中的动态数据均来自对应页面的 .js 文件中 Pagedata 对象。 一旦 data 对象中的数据发生变化,界面就会发生相应的变化。

绑定数据可以作用于三个位置 - 内容组件属性控制属性,而且还可以处理一些关键字。

  1. 内容

    <view> {{message}} </view> 
    
     //index.js 
     Page({ 
         data: { 
             message: "Hello, 微信小程序"
          } 
     }) 
    
  2. 组件属性(需要在双引号内):

    <!--index.wxml-->
    <view class="box box-{{color}}"></view> 
    <view class="box box-{{color2}}"></view> 
    
    //index.js 
    Page({ 
        data: { 
            color: "blue",
            color2: "red"
         } 
    }) 
    
    /* pages/index/index.wxss */
    .box {
        weight: 200rpx;
        height: 50rpx;
    }
    .box-blue {
        background-color: blue;
    }
    .box-red {
        background-color: red;
    }
    
  3. 控制属性(需要在双引号之内):

    <!--index.wxml-->
    <view wx:if=”{{condition}}”> </view> 
    
    //index.js
    Page({
        data: {
            condition: false
        }    
    })
    

    wx:if 是条件渲染用到的语法,后面会介绍到。.wxml 文件中常用的关键字有 true、false,是 boolean 类型,分别表示真和假。

其实我们可以在 Mustache (双大括号如 {{ }})内进行简单的运算,支持下面几种方式:

  1. 算数运算

    <!--index.wxml-->
    <view> {{a + b}} + {{c}} + d </view>
    <view> {{ name + id }} </view>
    
    //index.js
    Page({
        data: {
            a: 1,
            b: 2,
            c: 3,
            name: "罗大富",
            id: 123456
        }    
    })
    
  2. 数据路径运算

    //index.js
    Page({
        data: {
            array: [1, 2, 3, 4, 5, 6],
            student: {
                name: "罗大富"
            }        
        }    
    })
    

2. 列表渲染 - wx:for

相信大家都有过网上购物的经历,我们打开任意一个网购平台,就可以看到数不完的商品。对于前端工程师来说,每个商品他就对应了很多品牌和型号,那我们就需要把每个品牌对应的一个商品信息展示给用户。当我们商品数量比较小的时候,我们可以去一行一行的写类似的 wxml 标签。但是如果说我们的商品数量比较多,而且商品数量不固定的时候。那我们肯定不能这样一行一行的去写 wxml 标签了,这个时候,我们就需要用到微信小程序中的列表渲染。

在组件上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item,例如:

<view wx:for="{{array}}">
  {{index}}: {{item}}
</view>
Page({
  data: {
    array: ['a', 'b', 'c', 'd', 'e', 'f', 'g']
  }
})

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

<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="name">
  {{idx}}: {{name}}
</view>

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

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

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

当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。

:::tips

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

:::

block 标签

学习完控制属性 wx:for 之后,我们还需要补充一个小的知识点 block 标签,这个标签比较特殊。在写代码的时候,他是存在的,但是不会渲染在页面上,最终不能成为真正的 DOM 元素。

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

如果把上方代码中的 view 替换成 block,如下:

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

页面中就会出现一个 view 标签包裹着所有的循环内容,我们可以简单的把 block 标签理解为是一个占位符,在写代码的时候,我们可以看到。但是在页面中,就会被移除掉。

当你要使用列表、条件渲染某些数据的时候,如果不想额外添加一层节点(或者说标签),我们就可以使用 block 标签起到一层占位的作用。

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

3. 条件渲染 - wx:if

在框架中,使用 wx:if="" 来判断是否需要渲染该代码块:

<view wx:if="{{condition}}"> True </view>

也可以用 wx:elifwx:else 来添加一个 else 块:

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

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

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

wx:if vs hidden

因为 wx:if 之中的模板也可能包含数据绑定,所以当 wx:if 的条件值切换时,框架有一个局部渲染的过程,因为它会确保条件块在切换时销毁或重新渲染。

同时 wx:if 也是惰性的,如果在初始渲染条件为 false,框架什么也不做,在条件第一次变成真的时候才开始局部渲染。

相比之下,hidden 就简单的多,组件始终会被渲染,只是简单的控制显示与隐藏。

一般来说,wx:if 有更高的切换消耗而 hidden 有更高的初始渲染消耗。因此,如果需要频繁切换的情景下,用 hidden 更好,如果在运行时条件不大可能改变则 wx:if 较好。

上次编辑于:
贡献者: 罗大富 BigRich