内置指令
Vitarx 提供了一组内置指令,用于处理常见的 DOM 操作场景。这些指令可以直接在 JSX 中使用,无需额外注册。
v-show
v-show 通过切换 display: none 来控制元素的显示与隐藏。与 v-if 不同,v-show 不会销毁和重建 DOM 元素,只是简单地切换 CSS 属性。
基本用法
import { ref, createApp } from 'vitarx'
function App() {
const visible = ref(true)
return (
<div>
<button
onClick={() => {
visible.value = !visible.value
}}
>
{visible.value ? '隐藏' : '显示'}
</button>
<div v-show={visible}>这段内容可以显示或隐藏</div>
</div>
)
}
createApp(App).mount('#app')v-show 与 v-if 的区别
| 特性 | v-show | v-if |
|---|---|---|
| 切换方式 | CSS display: none | 销毁和重建 DOM |
| 初始渲染 | 始终渲染 DOM | 条件为假时不渲染 |
| 切换开销 | 低(仅切换样式) | 高(重建 DOM) |
| 适用场景 | 频繁切换显示/隐藏 | 条件很少改变 |
简单来说:需要频繁切换用 v-show,条件基本不变用 v-if。
v-html
v-html 用于将 HTML 字符串渲染到元素内部,相当于设置 innerHTML。
基本用法
import { ref, createApp } from 'vitarx'
function App() {
const content = ref('<strong>加粗文本</strong> 和 <em>斜体文本</em>')
return (
<div>
<div v-html={content} />
<p>原始 HTML:{content}</p>
</div>
)
}
createApp(App).mount('#app')WARNING
v-html 会直接将字符串作为 HTML 插入页面,存在 XSS 攻击风险。不要将用户输入的内容直接传给 v-html,务必先进行安全过滤。
INFO
v-html 应该用在没有子节点的元素上。如果元素已经有子节点,框架会发出警告。
v-text
v-text 用于设置元素的文本内容,相当于设置 textContent。与 {} 表达式不同,v-text 会替换元素内的所有内容。
基本用法
import { ref, createApp } from 'vitarx'
function App() {
const message = ref('Hello Vitarx')
return (
<div>
<p v-text={message} />
<button
onClick={() => {
message.value = '你好,Vitarx'
}}
>
切换文本
</button>
</div>
)
}
createApp(App).mount('#app')INFO
v-text 应该用在没有子节点的元素上。如果元素已经有子节点,框架会发出警告。大多数情况下,使用 {} 表达式更直观:<p>{message}</p>。
v-if / v-else-if / v-else
v-if、v-else-if、v-else 是条件渲染指令,根据条件决定是否渲染 DOM 元素。条件为假时,元素不会被创建(页面中只会留下一个注释占位符)。
基本用法
import { ref, createApp } from 'vitarx'
function App() {
const type = ref<'admin' | 'user' | 'guest'>('guest')
return (
<div>
<div v-if={type.value === 'admin'}>管理员面板</div>
<div v-else-if={type.value === 'user'}>用户中心</div>
<div v-else>访客页面</div>
<div style={{ marginTop: '12px' }}>
<button
onClick={() => {
type.value = 'admin'
}}
>
管理员
</button>
<button
onClick={() => {
type.value = 'user'
}}
>
用户
</button>
<button
onClick={() => {
type.value = 'guest'
}}
>
访客
</button>
</div>
</div>
)
}
createApp(App).mount('#app')v-if 与 v-else 配合
v-if 和 v-else 必须紧邻使用,中间不能插入其他元素:
// ✅ 正确:v-if 和 v-else 紧邻
<div v-if={show}>显示内容</div>
<div v-else>隐藏内容</div>
// ❌ 错误:中间插入了其他元素,v-else 无法匹配 v-if
<div v-if={show}>显示内容</div>
<p>其他元素</p>
<div v-else>隐藏内容</div>INFO
v-if / v-else-if / v-else 是编译器指令,由 @vitarx/plugin-vite 在编译阶段处理。条件为假的分支不会创建 DOM,切换时会销毁和重建 DOM 元素。
v-bind
v-bind 用于将一个对象的所有属性批量绑定到元素上,常用于属性透传场景。
对象形式
将整个对象的属性展开到元素上:
import { createApp } from 'vitarx'
function App() {
const attrs = {
id: 'my-input',
placeholder: '请输入',
maxLength: 100
}
return <input v-bind={attrs} />
}
createApp(App).mount('#app')上面的代码等同于:
<input id="my-input" placeholder="请输入" maxLength={100} />数组形式(排除属性)
如果你想在展开时排除某些属性,可以使用数组形式,第二个元素为要排除的属性名列表:
import { createApp } from 'vitarx'
function MyInput(props: { class?: string; value?: string; onInput?: (e: Event) => void }) {
return (
<input
v-bind={[props, ['onInput']]} // 透传 props,但排除 onInput
onInput={(e) => {
/* 自定义处理逻辑 */
}}
/>
)
}class 和 style 的合并行为
v-bind 会智能合并 class 和 style 属性,不会覆盖元素上已有的值:
// class 和 style 会合并,而不是覆盖
<div class="base" style={{ color: 'red' }} v-bind={{ class: 'extra', style: { fontSize: '16px' } }}>
内容
</div>
// 最终结果:class="base extra",style 同时包含 color 和 fontSizeWARNING
v-bind 不能用于绑定全局属性(如 ref、children)和其他 v- 开头的属性,这些属性会被自动忽略。
完整示例
下面是一个综合运用各种内置指令的完整示例:
import { ref, createApp } from 'vitarx'
function App() {
const visible = ref(true)
const type = ref<'admin' | 'user' | 'guest'>('guest')
const richContent = ref('<em>这是一段富文本内容</em>')
const plainText = ref('纯文本内容')
const attrs = {
title: '属性透传示例',
'data-role': 'container'
}
return (
<div style={{ padding: '20px', maxWidth: '600px', margin: '0 auto' }}>
<h2>内置指令示例</h2>
{/* v-show:控制显示/隐藏 */}
<section style={{ marginBottom: '20px' }}>
<h3>v-show</h3>
<button
onClick={() => {
visible.value = !visible.value
}}
>
{visible.value ? '隐藏' : '显示'}
</button>
<p v-show={visible} style={{ marginTop: '8px' }}>
这段内容通过 v-show 控制显示与隐藏
</p>
</section>
{/* v-if / v-else-if / v-else:条件渲染 */}
<section style={{ marginBottom: '20px' }}>
<h3>v-if / v-else-if / v-else</h3>
<div v-if={type.value === 'admin'} style={{ color: '#e74c3c' }}>
管理员面板:拥有所有权限
</div>
<div v-else-if={type.value === 'user'} style={{ color: '#3498db' }}>
用户中心:查看个人信息
</div>
<div v-else style={{ color: '#95a5a6' }}>
访客页面:请先登录
</div>
<div style={{ marginTop: '8px' }}>
<button
onClick={() => {
type.value = 'admin'
}}
>
管理员
</button>
<button
onClick={() => {
type.value = 'user'
}}
>
用户
</button>
<button
onClick={() => {
type.value = 'guest'
}}
>
访客
</button>
</div>
</section>
{/* v-html:渲染 HTML */}
<section style={{ marginBottom: '20px' }}>
<h3>v-html</h3>
<div v-html={richContent} style={{ border: '1px solid #ddd', padding: '8px' }} />
</section>
{/* v-text:设置文本 */}
<section style={{ marginBottom: '20px' }}>
<h3>v-text</h3>
<p v-text={plainText} />
</section>
{/* v-bind:属性透传 */}
<section>
<h3>v-bind</h3>
<div v-bind={attrs} style={{ border: '1px solid #ddd', padding: '8px' }}>
鼠标悬停查看 title 属性
</div>
</section>
</div>
)
}
createApp(App).mount('#app')下一步
- 自定义指令 — 学习如何编写和使用自定义指令