网站已运行 162 · 20小时 · 41 · 13
目录

微信小程序 wx:if 与 hidden 怎么选?条件渲染实作

微信小程序 wx:if 与 hidden 条件渲染差异示意图

微信小程序 wx:ifhidden 都能让一块内容暂时不显示,但两者控制的并不是同一件事。wx:if 决定节点是否存在;hidden 保留节点,只改变它是否可见。选错通常不会立刻报错,却可能让表单状态、组件生命周期和频繁切换时的开销变得难以判断。

本文用一个可复制的原生小程序页面,把两种写法放在同一个状态变量下对照。示例适用于原生 WXML 与 JavaScript 项目,不依赖 UI 组件库。

微信小程序 wx:if 与 hidden 的核心区别

wx:if="{{condition}}" 根据条件创建或移除对应的节点。条件为 false 时,这个分支不在当前渲染结果中。

hidden="{{condition}}" 是布尔属性。值为 true 时组件被隐藏,但节点仍然保留。这里最容易写反:如果页面状态叫 showPanel,通常要写成 hidden="{{!showPanel}}"

对比项wx:ifhidden
控制对象节点是否存在节点是否可见
条件为 false / hidden 为 true分支不渲染节点保留但隐藏
适合场景权限分支、空状态、一次性步骤展开面板、标签内容、频繁显隐
状态命名canEdithasDatashowPanel 配合取反

这张表是选择起点,不是绝对性能结论。复杂自定义组件、媒体资源或长列表仍应在真实页面和目标设备上验证。

建一个最小可复现页面

先在 app.json 注册页面:

{
  "pages": [
    "pages/toggle/index"
  ],
  "window": {
    "navigationBarTitleText": "条件渲染示例"
  }
}

页面 JavaScript 只维护一个布尔状态。点击按钮时,把 showPanel 取反:

Page({
  data: {
    showPanel: true
  },

  togglePanel() {
    this.setData({
      showPanel: !this.data.showPanel
    })
  }
})

然后在同一个 WXML 页面里并排写出两种控制方式:

<view class="page">
  <button bindtap="togglePanel">切换内容</button>

  <view class="section">
    <text class="label">wx:if:条件为 false 时节点不存在</text>
    <view wx:if="{{showPanel}}" class="panel">
      这块内容由 wx:if 控制
    </view>
  </view>

  <view class="section">
    <text class="label">hidden:节点保留,只切换显隐</text>
    <view hidden="{{!showPanel}}" class="panel">
      这块内容由 hidden 控制
    </view>
  </view>
</view>

两个区域最终看起来会一起显示或隐藏,但语义不同。第一块由 wx:if 决定是否进入渲染分支;第二块一直存在,hidden 只根据取反后的值控制可见性。

为什么 hidden 经常写反

hidden 的属性名表达的是“是否隐藏”,而业务状态经常表达“是否显示”。这两个布尔值方向相反:

<!-- showPanel 为 true 时应显示,所以 hidden 必须为 false -->
<view hidden="{{!showPanel}}">面板内容</view>

不建议写成下面这样:

<!-- showPanel 为 true 时反而隐藏,语义相反 -->
<view hidden="{{showPanel}}">面板内容</view>

另一个常见误区是把字符串当布尔值。官方文档特别说明:布尔属性如果没有使用数据绑定,即使写成 hidden="false",也会按真值处理。动态布尔值应始终放进双花括号:

<view hidden="{{false}}">这里不会被隐藏</view>

什么时候优先用 wx:if

以下场景更符合“节点是否应该存在”的语义:

  • 登录后才出现的账户操作;
  • 有数据时渲染列表,没有数据时渲染空状态;
  • 多步骤流程里尚未进入的步骤;
  • 不希望未满足条件的分支继续保留输入状态时。

多个互斥分支可以使用 wx:ifwx:elifwx:else,让条件关系留在 WXML 中:

<view wx:if="{{loading}}">正在加载</view>
<view wx:elif="{{errorMessage}}">{{errorMessage}}</view>
<view wx:else>内容已就绪</view>

如果一个条件需要同时控制多个相邻节点,可以把条件写在 <block> 上。block 只是分组容器,不会额外生成一个可见组件节点:

<block wx:if="{{hasPermission}}">
  <text>编辑模式</text>
  <button bindtap="save">保存</button>
</block>

什么时候优先用 hidden

当同一块界面需要反复展开和收起,而且你希望保留节点本身时,hidden 更贴近意图,例如筛选面板、标签页内容和临时折叠区域。

但不要把 hidden 当成所有组件的通用性能捷径。复杂组件即使不可见,也仍然保留;如果内容很重、首次无需展示,先用 wx:if 避免创建往往更容易控制。最终应结合组件复杂度、切换频率和真机表现判断。

自定义组件状态为什么会有差异

假设分支中包含一个自定义表单组件:

<profile-form wx:if="{{editing}}" />

editingtrue 变为 false,这个分支会被移除;再次变为 true 时重新进入渲染流程。依赖组件内部临时状态时,不要默认它会一直保留,重要值应提升到页面 data、store 或其他明确的数据源。

如果改成:

<profile-form hidden="{{!editing}}" />

组件节点仍保留,更适合需要在短时间内反复切换并继续使用当前输入的界面。是否保留内部状态仍应以实际组件实现和目标基础库为准,避免只靠视觉结果下结论。

用脚本检查示例有没有写反

下面的脚本不模拟小程序运行时,它只做六项静态检查:页面路由、wx:ifhidden 的取反、点击事件、初始状态和状态切换。把脚本保存为项目根目录的 verify-conditional-rendering.mjs,即可直接运行,不依赖本文之外的文件。

import assert from 'node:assert/strict'
import { readFile } from 'node:fs/promises'

const wxml = await readFile(
  new URL('./pages/toggle/index.wxml', import.meta.url),
  'utf8'
)
const js = await readFile(
  new URL('./pages/toggle/index.js', import.meta.url),
  'utf8'
)
const app = JSON.parse(
  await readFile(new URL('./app.json', import.meta.url), 'utf8')
)

assert.equal(app.pages[0], 'pages/toggle/index')
assert.match(wxml, /wx:if="{{showPanel}}"/)
assert.match(wxml, /hidden="{{!showPanel}}"/)
assert.match(wxml, /bindtap="togglePanel"/)
assert.match(js, /showPanel:s*true/)
assert.match(js, /showPanel:s*!this.data.showPanel/)

console.log('6 checks passed: page route, wx:if, hidden, event and state toggle')

执行命令:

node verify-conditional-rendering.mjs

这类静态检查适合防止属性方向写反或示例漏文件,但不能代替微信开发者工具和真机对生命周期、内存及动画流畅度的验证。

一套更稳的选择顺序

实际写页面时,可以按下面的顺序判断:

  1. 先问“条件不满足时,这个节点还应该存在吗?”不应该存在就用 wx:if
  2. 如果节点应该保留,再看是不是需要频繁显隐;需要时考虑 hidden
  3. 如果内部状态很重要,明确状态放在哪里,不要只依赖组件是否还在页面中。
  4. 如果包含长列表、视频、地图或复杂自定义组件,在微信开发者工具和至少一台真机上测试。
  5. 状态名用正向语义,例如 showPanelhasPermission,并让 hidden 的取反关系一眼可读。

对于大多数普通页面,这套判断比背诵“哪个性能更好”更可靠。微信小程序 wx:ifhidden 的核心区别首先是渲染语义,其次才是具体页面中的性能取舍。

条件渲染最终仍由页面数据驱动;如果显隐状态来自嵌套对象或列表项,建议只同步变化字段。具体写法可参考微信小程序 setData 局部路径更新与性能优化实作

继续阅读

如果还不熟悉页面文件如何组织,可以先看微信小程序项目目录结构详解;需要确认页面 JSON 与全局配置的覆盖关系,可继续看微信小程序全局配置与页面配置;列表条件和稳定 key 组合使用时,可参考微信小程序 wx:for 列表渲染

官方资料:条件渲染WXML 基础基础组件与布尔属性

数臻源码猫咪图标
目录
数臻源码猫咪图标

目录

标签云: