《二》微信小程序中的 WXML

本文详细介绍了WXML的基本概念、数据绑定、列表渲染、条件渲染及模板的使用等特性。通过实例展示了如何利用WXML构建动态页面。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 循环中 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>
    
<think>好的,用户想了解如何在微信小程序中使用wxml2canvas来生成画布的流程,包括教程和示例。我需要先确认wxml2canvas是否是小程序官方支持的库。根据提供的引用内容,微信小程序的canvas API需要直接操作CanvasContext,但用户提到的wxml2canvas可能是一个第三方库,用于将WXML结构转换为Canvas绘图。 首先,我需要回忆一下是否有相关的第三方库。例如,wxml2canvas可能类似于html2canvas在网页中的功能,将DOM元素转换为Canvas。但小程序环境不同,可能实现方式也不同。根据引用[2],小程序中每个canvas-id必须唯一,这可能影响多个canvas实例的使用。 接下来,我需要检查用户提供的引用内容是否有相关信息。引用[1]提到了使用原生Canvas API生成海报,引用[3]展示了drawImage的用法。但用户的问题是关于wxml2canvas的,这可能需要引入第三方库,而非原生API。 可能需要解释原生Canvas的使用流程,同时提到第三方库如wxml-to-canvas,因为微信小程序官方可能没有直接提供wxml2canvas,但可能有类似的解决方案。例如,微信小程序社区可能有开发者开发的库,或者官方文档中有相关组件,如使用WXML到Canvas的渲染方法。 根据我的知识,微信小程序有一个官方组件wxml-to-canvas,允许将WXML模板转换为Canvas图像,这可能正是用户需要的。因此,我需要整理使用wxml-to-canvas的步骤,包括安装、配置WXML模板、JS调用方法,以及生成图片的流程。 需要确保步骤正确,例如引入组件的路径、模板定义、数据绑定、渲染方法和导出图片。同时,结合引用中的注意事项,如canvas-id的唯一性,可能需要提醒用户避免重复ID的问题。 最后,生成相关问题,可能涉及性能优化、常见错误处理、动态内容加载等,帮助用户深入理解。</think>### 如何在微信小程序中使用 wxml-to-canvas? 微信小程序可通过第三方库`wxml-to-canvas`将WXML结构转换为Canvas绘图,实现动态生成海报等功能。以下是具体使用流程: --- #### 1. **安装与引入** - 通过npm安装: ```bash npm install --save wxml-to-canvas ``` - 在页面JSON中引入组件: ```json { "usingComponents": { "wxml-to-canvas": "wxml-to-canvas" } } ``` --- #### 2. **定义WXML模板** 在页面WXML中编写模板,绑定动态数据: ```html <wxml-to-canvas id="wxml-canvas"></wxml-to-canvas> <view class="hide"> <view class="container"> <text class="title">{{title}}</text> <image class="qrcode" src="{{qrcodeUrl}}"></image> </view> </view> ``` > 注:`.hide`类用于隐藏模板,仅作渲染源使用[^3]。 --- #### 3. **配置Canvas渲染** 在JS中定义模板样式和数据: ```javascript Page({ data: { title: '扫码参与活动', qrcodeUrl: '/images/qr.png' }, onReady() { const { width, height } = this.getCanvasSize(); // 自定义计算画布尺寸 this.setData({ width, height }); }, renderToCanvas() { const component = this.selectComponent('#wxml-canvas'); component.renderToCanvas({ template: 'container', styles: { container: { width: 300, backgroundColor: '#fff' }, title: { fontSize: 16, color: '#333' }, qrcode: { width: 100, height: 100 } }, data: this.data }).then(() => { component.canvasToTempFilePath({ fileType: 'png', success: (res) => { this.setData({ imagePath: res.tempFilePath }); } }); }); } }); ``` --- #### 4. **生成图片** 调用`canvasToTempFilePath`将Canvas转为图片路径,用于预览或分享: ```javascript // 上述代码已包含生成逻辑 // 生成的图片路径保存在this.data.imagePath中 ``` --- #### **注意事项** - **canvas-id唯一性**:同一页面避免重复`canvas-id`,否则可能导致渲染失败[^2]。 - **图片加载**:确保图片资源为本地路径或已下载到临时目录,网络图片需先调用`wx.getImageInfo`处理。 - **性能优化**:复杂海报建议分步渲染,避免一次性绘制过多元素。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值