x-if 条件渲染 #
什么是 x-if? #
x-if 指令根据条件决定是否将元素渲染到 DOM 中。与 x-show 不同,x-if 会真正地添加或移除 DOM 元素,而不是简单地切换显示状态。
基本语法 #
x-if 必须在 <template> 标签上使用:
html
<template x-if="条件表达式">
<div>条件内容</div>
</template>
基本用法 #
简单条件 #
html
<div x-data="{ show: false }">
<button @click="show = !show">切换</button>
<template x-if="show">
<div>这段内容会被添加或移除</div>
</template>
</div>
条件分支 #
html
<div x-data="{ score: 75 }">
<input type="number" x-model="score">
<template x-if="score >= 90">
<p style="color: green">优秀</p>
</template>
<template x-if="score >= 60 && score < 90">
<p style="color: blue">及格</p>
</template>
<template x-if="score < 60">
<p style="color: red">不及格</p>
</template>
</div>
使用函数 #
html
<div x-data="{
user: null,
isLoggedIn() {
return this.user !== null
}
}">
<template x-if="isLoggedIn()">
<div>欢迎, <span x-text="user.name"></span></div>
</template>
<template x-if="!isLoggedIn()">
<div>请登录</div>
</template>
</div>
为什么需要 template 标签? #
x-if 必须在 <template> 标签上使用,原因如下:
- DOM 规范:
<template>标签的内容默认不会被渲染 - 单一根元素:确保条件内容有明确的边界
- 性能优化:Alpine.js 可以高效地管理模板内容的添加和移除
html
<template x-if="condition">
<div class="card">
<h2>标题</h2>
<p>内容</p>
</div>
</template>
x-if vs x-show #
关键区别 #
| 特性 | x-if | x-show |
|---|---|---|
| DOM 操作 | 添加/移除元素 | 切换 display |
| 初始渲染 | 条件为真才渲染 | 始终渲染 |
| 切换成本 | 高(DOM 操作) | 低(CSS 切换) |
| 内存占用 | 条件为假时不占用 | 始终占用 |
| 事件监听器 | 移除时销毁 | 保留 |
| 生命周期 | 有创建/销毁过程 | 无 |
使用 x-if 的场景 #
html
<div x-data="{ showDetails: false }">
<button @click="showDetails = true">显示详情</button>
<template x-if="showDetails">
<div>
大量内容,很少需要显示
<img src="large-image.jpg" alt="大图片">
<video src="video.mp4"></video>
</div>
</template>
</div>
使用 x-show 的场景 #
html
<div x-data="{ active: false }">
<button @click="active = !active">切换</button>
<div x-show="active">
频繁切换的内容
</div>
</div>
高级用法 #
嵌套条件 #
html
<div x-data="{
user: { role: 'admin', status: 'active' }
}">
<template x-if="user">
<div>
<template x-if="user.role === 'admin'">
<div>
<template x-if="user.status === 'active'">
<p>活跃管理员</p>
</template>
<template x-if="user.status === 'inactive'">
<p>非活跃管理员</p>
</template>
</div>
</template>
<template x-if="user.role === 'user'">
<p>普通用户</p>
</template>
</div>
</template>
</div>
条件渲染列表 #
html
<div x-data="{
items: [
{ id: 1, name: 'Apple', available: true },
{ id: 2, name: 'Banana', available: false },
{ id: 3, name: 'Orange', available: true }
]
}">
<template x-for="item in items">
<div>
<template x-if="item.available">
<span style="color: green" x-text="item.name + ' (可购买)'"></span>
</template>
<template x-if="!item.available">
<span style="color: gray" x-text="item.name + ' (缺货)'"></span>
</template>
</div>
</template>
</div>
异步内容 #
html
<div x-data="{
loading: true,
data: null,
error: null,
async fetchData() {
this.loading = true
try {
const res = await fetch('/api/data')
this.data = await res.json()
} catch (e) {
this.error = e.message
} finally {
this.loading = false
}
}
}" x-init="fetchData()">
<template x-if="loading">
<div class="loading">加载中...</div>
</template>
<template x-if="error">
<div class="error" x-text="'错误: ' + error"></div>
</template>
<template x-if="data && !loading">
<div class="content">
<template x-for="item in data">
<p x-text="item.name"></p>
</template>
</div>
</template>
</div>
实用示例 #
登录状态切换 #
html
<div x-data="{
user: null,
form: { email: '', password: '' },
async login() {
const res = await fetch('/api/login', {
method: 'POST',
body: JSON.stringify(this.form)
})
this.user = await res.json()
},
logout() {
this.user = null
}
}">
<template x-if="!user">
<form @submit.prevent="login()">
<input type="email" x-model="form.email" placeholder="邮箱">
<input type="password" x-model="form.password" placeholder="密码">
<button type="submit">登录</button>
</form>
</template>
<template x-if="user">
<div>
<span x-text="'欢迎, ' + user.name"></span>
<button @click="logout()">退出</button>
</div>
</template>
</div>
权限控制 #
html
<div x-data="{
user: {
role: 'admin',
permissions: ['read', 'write', 'delete']
},
can(permission) {
return this.user.permissions.includes(permission)
}
}">
<template x-if="can('read')">
<button>查看</button>
</template>
<template x-if="can('write')">
<button>编辑</button>
</template>
<template x-if="can('delete')">
<button>删除</button>
</template>
</div>
表单步骤 #
html
<div x-data="{
step: 1,
form: {
name: '',
email: '',
address: ''
},
nextStep() {
if (this.step < 3) this.step++
},
prevStep() {
if (this.step > 1) this.step--
}
}">
<template x-if="step === 1">
<div>
<h2>步骤 1: 基本信息</h2>
<input x-model="form.name" placeholder="姓名">
<input x-model="form.email" placeholder="邮箱">
<button @click="nextStep()">下一步</button>
</div>
</template>
<template x-if="step === 2">
<div>
<h2>步骤 2: 地址信息</h2>
<input x-model="form.address" placeholder="地址">
<button @click="prevStep()">上一步</button>
<button @click="nextStep()">下一步</button>
</div>
</template>
<template x-if="step === 3">
<div>
<h2>步骤 3: 确认</h2>
<p>姓名: <span x-text="form.name"></span></p>
<p>邮箱: <span x-text="form.email"></span></p>
<p>地址: <span x-text="form.address"></span></p>
<button @click="prevStep()">上一步</button>
<button @click="submit()">提交</button>
</div>
</template>
</div>
空状态处理 #
html
<div x-data="{
items: [],
addItem() {
this.items.push({ id: Date.now(), name: '新项目' })
},
removeItem(id) {
this.items = this.items.filter(item => item.id !== id)
}
}">
<button @click="addItem()">添加项目</button>
<template x-if="items.length === 0">
<div class="empty-state">
<p>暂无数据</p>
<p>点击上方按钮添加项目</p>
</div>
</template>
<template x-if="items.length > 0">
<ul>
<template x-for="item in items">
<li>
<span x-text="item.name"></span>
<button @click="removeItem(item.id)">删除</button>
</li>
</template>
</ul>
</template>
</div>
错误处理 #
html
<div x-data="{
errors: {},
hasErrors() {
return Object.keys(this.errors).length > 0
},
validate(field, value) {
if (!value) {
this.errors[field] = '此字段必填'
} else {
delete this.errors[field]
}
}
}">
<input
@blur="validate('name', $el.value)"
placeholder="姓名"
>
<template x-if="errors.name">
<p class="error" x-text="errors.name"></p>
</template>
<template x-if="hasErrors()">
<p class="error-summary">请修正表单中的错误</p>
</template>
</div>
过渡动画 #
x-if 也支持过渡动画:
html
<div x-data="{ show: false }">
<button @click="show = !show">切换</button>
<template x-if="show">
<div x-transition>
带过渡动画的内容
</div>
</template>
</div>
自定义过渡 #
html
<template x-if="show">
<div
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 transform scale-90"
x-transition:enter-end="opacity-100 transform scale-100"
x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100 transform scale-100"
x-transition:leave-end="opacity-0 transform scale-90"
>
内容
</div>
</template>
注意事项 #
1. 必须使用 template #
html
<div x-if="condition"></div>
错误!必须使用 <template>:
html
<template x-if="condition">
<div></div>
</template>
2. 单一根元素 #
<template> 内部应该只有一个根元素:
html
<template x-if="condition">
<div>元素1</div>
<div>元素2</div>
</template>
推荐使用包装元素:
html
<template x-if="condition">
<div>
<div>元素1</div>
<div>元素2</div>
</div>
</template>
3. 键值优化 #
在循环中使用 x-if 时,确保有正确的 :key:
html
<template x-for="item in items" :key="item.id">
<template x-if="item.visible">
<div x-text="item.name"></div>
</template>
</template>
小结 #
x-if 指令要点:
- 必须在
<template>标签上使用 - 真正地添加或移除 DOM 元素
- 适合条件很少改变的场景
- 适合包含大量内容的条件渲染
- 支持过渡动画
下一章,我们将学习 x-for 指令进行列表渲染。
最后更新:2026-03-28