# Alpine.js Directives

> [Alpine.js Directives](https://www.ftls.xyz/docs/alpine.js/alpinejs-2-directives/)
> Penned by [恐咖兵糖](https://www.ftls.xyz/) on 0001-01-01


## 概述

Alpine.js 的核心通过一系列指令（Directives）来实现响应式 DOM 操作。这些属性以 `x-` 为前缀，可以直接写在 HTML 元素上，无需编写任何 JavaScript 代码即可实现复杂的前端交互。

---

## x-data

### 说明

`x-data` 是 Alpine.js 最核心的指令，用于声明一个响应式数据对象。它定义了组件的内部状态，所有在该作用域内的其他 `x-` 指令都可以访问这些数据。

### 适用范围

- 用于包装整个组件的根元素
- 可以嵌套使用，形成父子组件数据继承
- 数据可以是任何 JavaScript 类型：字符串、数字、布尔值、数组、对象等

### 语法

```html
<div x-data="{ message: 'Hello Alpine', count: 0 }">
    <p x-text="message"></p>
    <button @click="count++">点击次数: <span x-text="count"></span></button>
</div>
```

### 注意事项

- `x-data` 的值必须是对象字面量或返回对象的函数
- 如果需要从函数初始化数据，可以使用 `x-data="myComponent()"`
- 嵌套的 `x-data` 会继承父级数据，但子级同名属性会覆盖父级

---

## x-init

### 说明

`x-init` 用于在元素初始化时执行一段代码。它在 Alpine.js 初始化该元素的数据后立即执行，常用于设置初始状态、调用 API 或与其他库集成。

### 适用范围

- 组件初始化逻辑
- 第三方库的初始化
- 异步数据的预加载

### 语法

```html
<div x-data="{ users: [] }" x-init="users = ['Alice', 'Bob', 'Charlie']">
    <ul>
        <template x-for="user in users">
            <li x-text="user"></li>
        </template>
    </ul>
</div>
```

### 注意事项

- `x-init` 中的 `this` 指向当前组件的数据对象
- 如果 `x-init` 中有异步操作，注意数据更新可能不会立即反映到 DOM
- 避免在 `x-init` 中执行过重的计算，会影响首屏渲染

---

## x-show

### 说明

`x-show` 根据表达式的布尔值控制元素的显示与隐藏。它通过 CSS 的 `display` 属性来实现元素的显示切换。

### 适用范围

- 条件渲染
- 模态框的显示/隐藏
- 折叠面板
- 标签页切换

### 语法

```html
<div x-data="{ open: false }">
    <button @click="open = !open">切换显示</button>
    <div x-show="open" style="padding: 10px; background: #f0f0f0;">
        这是一个可以显示/隐藏的内容块
    </div>
</div>
```

### 注意事项

- 元素默认存在，只是通过 `display: none` 隐藏
- 需要配合 `x-transition` 才能实现过渡动画
- 如果需要完全移除 DOM 元素，应使用 `x-if`

---

## x-bind

### 说明

`x-bind` 用于动态绑定 HTML 元素的属性、class、style 等。它允许表达式的结果影响元素的属性值。

### 适用范围

- 动态绑定 class（`x-bind:class` 或 `:class`）
- 动态绑定 style（`x-bind:style` 或 `:style`）
- 动态绑定任意 HTML 属性
- 绑定自定义组件的 props

### 语法

```html
<!-- 绑定普通属性 -->
<img x-bind:src="imageUrl" alt="动态图片">

<!-- 绑定 class -->
<div :class="{ 'active': isActive, 'disabled': isDisabled }"></div>

<!-- 绑定 style -->
<div :style="{ color: textColor, fontSize: fontSize + 'px' }"></div>

<!-- 绑定布尔属性 -->
<button :disabled="isSubmitting">提交</button>
```

### 注意事项

- 可以简写为冒号 `:` 开头的形式
- `class` 和 `style` 支持对象语法和数组语法
- 绑定的属性值会被实时响应式更新

---

## x-on

### 说明

`x-on` 用于监听 DOM 事件并执行相应的 JavaScript 代码。它是处理用户交互的主要方式。

### 适用范围

- 点击事件
- 表单提交
- 键盘事件
- 自定义事件
- 窗口/文档级别的事件

### 语法

```html
<!-- 监听点击事件 -->
<button x-on:click="count++">点击</button>

<!-- 简写形式 -->
<button @click="count++">点击</button>

<!-- 获取事件对象 -->
<button @click="handleClick($event)">点击</button>

<!-- 监听多种事件 -->
<div @click="doSomething" @mouseenter="onHover">交互</div>

<!-- 阻止默认行为 -->
<form @submit.prevent="submitForm">
    <button type="submit">提交</button>
</form>
```

### 事件修饰符

- `.prevent` - 阻止默认行为
- `.stop` - 停止冒泡
- `.capture` - 使用捕获模式
- `.once` - 只触发一次
- `.debounce` - 防抖
- `.throttle` - 节流

### 注意事项

- 推荐使用简写形式 `@click` 代替 `x-on:click`
- `$event` 是特殊变量，代表原生 DOM 事件对象
- 修饰符可以链式使用，如 `@click.stop.prevent`

---

## x-text

### 说明

`x-text` 用于设置元素的文本内容。表达式的返回值会被设置为元素的 `textContent`。

### 适用范围

- 动态显示文本内容
- 数字、布尔值的展示
- 模板文本的拼接

### 语法

```html
<div x-data="{ name: 'Alpine' }">
    <p x-text="name"></p>
    <p x-text="'Hello ' + name"></p>
    <p x-text="status ? '在线' : '离线'"></p>
</div>
```

### 注意事项

- 只设置文本内容，不会解析 HTML
- 表达式结果会自动转换为字符串
- 空白值（如 `null`、`undefined`、`''`）会显示为空字符串

---

## x-html

### 说明

`x-html` 用于设置元素的 HTML 内容。与 `x-text` 不同，它会解析并渲染 HTML 标记。

### 适用范围

- 动态渲染 HTML 内容
- 富文本内容的展示
- 安全可靠的内部 HTML 渲染

### 语法

```html
<div x-data="{ content: '<strong>加粗文字</strong>' }">
    <div x-html="content"></div>
</div>
```

### 注意事项

- **安全风险**：绝对不要将用户输入直接用于 `x-html`，可能导致 XSS 攻击
- 仅用于可信内容的渲染
- 如果只需要纯文本，优先使用 `x-text`

---

## x-model

### 说明

`x-model` 实现表单输入与数据的双向绑定。它会自动同步输入元素的值与 Alpine.js 数据。

### 适用范围

- 文本输入框
- 文本域
- 下拉选择框
- 复选框和单选按钮
- 自定义输入组件

### 语法

```html
<!-- 文本输入 -->
<input type="text" x-model="name">
<p>输入的值: <span x-text="name"></span></p>

<!-- 复选框 -->
<input type="checkbox" x-model="agree">
<p>是否同意: <span x-text="agree ? '是' : '否'"></span></p>

<!-- 下拉选择 -->
<select x-model="selected">
    <option value="">请选择</option>
    <option value="a">选项 A</option>
    <option value="b">选项 B</option>
</select>

<!-- 修饰符 -->
<input x-model.lazy="name">     <!-- 失去焦点时同步 -->
<input x-model.number="age">    <!-- 转换为数字 -->
<input x-model.trim="email">   <!-- 去除首尾空格 -->
```

### 注意事项

- 默认是实时同步（input 事件）
- 可以配合修饰符改变同步时机和行为
- 复选框和单选框的 `x-model` 绑定的值类型需要注意

---

## x-modelable

### 说明

`x-modelable` 用于在子组件中暴露可被父组件通过 `x-model` 绑定的属性。它是实现可复用组件的重要机制。

### 适用范围

- 创建可复用的自定义组件
- 组件间数据双向绑定
- 封装复杂的 UI 组件

### 语法

```html
<!-- 子组件 my-modal.html -->
<div x-data="{
    _isOpen: false,
    open() { this._isOpen = true },
    close() { this._isOpen = false },
    isOpen: $modelable('_isOpen')
}">
    <!-- 模态框内容 -->
</div>

<!-- 父组件使用 -->
<my-modal x-model="modalOpen"></my-modal>
```

### 注意事项

- 需要配合 `$modelable` 函数使用
- 暴露的属性名通常以下划线开头表示内部状态
- 这是 Alpine.js 3.x 以上版本的功能

---

## x-for

### 说明

`x-for` 用于列表渲染，基于数组或对象生成多个 DOM 元素。它会为数组的每个元素或对象的每个键值对创建一个 DOM 副本。

### 适用范围

- 列表展示
- 表格行渲染
- 菜单项生成
- 动态卡片列表

### 语法

```html
<!-- 基础列表 -->
<ul>
    <template x-for="item in items" :key="item.id">
        <li x-text="item.name"></li>
    </template>
</ul>

<!-- 带索引的循环 -->
<template x-for="(item, index) in items" :key="item.id">
    <li>
        <span x-text="index + 1"></span>. <span x-text="item.name"></span>
    </li>
</template>

<!-- 遍历对象 -->
<template x-for="(value, key) in object" :key="key">
    <div>
        <span x-text="key"></span>: <span x-text="value"></span>
    </div>
</template>

<!-- 嵌套循环 -->
<template x-for="category in categories">
    <div>
        <h3 x-text="category.name"></h3>
        <ul>
            <template x-for="product in category.products" :key="product.id">
                <li x-text="product.name"></li>
            </template>
        </ul>
    </div>
</template>
```

### 注意事项

- 必须使用 `<template>` 标签包裹循环体
- 强烈建议使用 `:key` 指定唯一键，用于 Vue/React 类似的虚拟 DOM _diff 优化
- 不支持循环原始数值，可以使用 `Array.from()` 转换

---

## x-transition

### 说明

`x-transition` 用于为元素添加过渡动画。当元素显示或隐藏时，Alpine.js 会自动应用 CSS 类来实现平滑过渡。

### 适用范围

- 模态框动画
- 下拉菜单
- 折叠面板
- 列表项的进入/离开动画

### 语法

```html
<!-- 基础使用 -->
<div x-show="show" x-transition>
    内容
</div>

<!-- 自定义过渡类 -->
<div x-show="show" x-transition:enter="transition ease-out duration-300"
     x-transition:enter-start="opacity-0 transform -translate-y-4"
     x-transition:enter-end="opacity-100 transform translate-y-0"
     x-transition:leave="transition ease-in duration-200"
     x-transition:leave-start="opacity-100 transform translate-y-0"
     x-transition:leave-end="opacity-0 transform -translate-y-4">
    内容
</div>

<!-- 过渡时长 -->
<div x-show="show" x-transition.duration.500ms>
    内容
</div>
```

### 注意事项

- 需要配合 CSS 定义过渡效果
- Alpine.js 会自动注入过渡类，可以在全局 CSS 中预定义
- 可以使用工具类（如 Tailwind CSS）简化过渡配置

---

## x-effect

### 说明

`x-effect` 用于监听数据变化并执行相应代码。它会在依赖的数据发生变化时立即运行，类似 Vue 的 `watch`。

### 适用范围

- 数据变化时的副作用处理
- 与第三方库同步
- 复杂的响应式逻辑

### 语法

```html
<div x-data="{
    count: 0,
    doubled: 0
}" x-effect="doubled = count * 2">
    <button @click="count++">增加</button>
    <p>原始值: <span x-text="count"></span></p>
    <p>双倍值: <span x-text="doubled"></span></p>
</div>
```

### 注意事项

- 当依赖的数据变化时会重新执行
- 避免在 `x-effect` 中修改自身依赖的数据，可能导致无限循环
- 首次渲染时也会执行一次

---

## x-ignore

### 说明

`x-ignore` 用于阻止 Alpine.js 处理某个元素及其子元素。它会让该元素完全脱离 Alpine.js 的管理。

### 适用范围

- 嵌入第三方 HTML 内容
- 遗留代码隔离
- 性能优化（避免处理大量静态内容）

### 语法

```html
<div x-data="{ message: 'Alpine 管理的' }">
    <p x-text="message"></p>

    <div x-ignore>
        <!-- 这里的内容不会被 Alpine.js 处理 -->
        <p x-text="message">这段不会显示</p>
    </div>
</div>
```

### 注意事项

- 使用后该元素内部的所有 Alpine 指令都会失效
- 常用于嵌入服务端渲染或静态生成的内容
- 需要确保该区域内不需要任何交互功能

---

## x-ref

### 说明

`x-ref` 用于获取 DOM 元素的引用。通过 `$refs` 对象可以在 JavaScript 代码中访问这些元素。

### 适用范围

- 获取 DOM 元素进行操作
- 与第三方库集成
- 需要程序化操作元素（如聚焦、滚动）

### 语法

```html
<div x-data="{
    focusInput() {
        $refs.inputField.focus()
    }
}">
    <input type="text" x-ref="inputField">
    <button @click="focusInput()">聚焦输入框</button>

    <!-- 获取多个 ref -->
    <div x-ref="container"></div>
    <button @click="$refs.container.style.background = 'red'">改变颜色</button>
</div>
```

### 注意事项

- `x-ref` 定义的引用通过 `$refs` 对象访问
- 可以在任意 JavaScript 表达式中使用 `$refs`
- ref 名称推荐使用有意义的命名

---

## x-cloak

### 说明

`x-cloak` 用于防止页面加载时出现未渲染的 Alpine.js 模板。它通过 CSS 隐藏带有 `x-cloak` 的元素，直到 Alpine.js 初始化完成。

### 适用范围

- 所有使用 Alpine.js 的页面
- 防止闪烁问题
- 首屏体验优化

### 语法

```html
<!-- 在 HTML 中添加 x-cloak -->
<div x-data="{ message: 'Hello' }" x-cloak>
    <p x-text="message"></p>
</div>

<!-- 需要配合 CSS -->
<style>
    [x-cloak] { display: none !important; }
</style>
```

### 注意事项

- 必须配合 CSS 规则 `[x-cloak] { display: none; }` 使用
- Alpine.js 初始化后会自动移除 `x-cloak` 属性
- 推荐在全局 CSS 中添加此规则

---

## x-teleport

### 说明

`x-teleport` 用于将元素移动到 DOM 的其他位置。这对于实现模态框、下拉菜单等需要突破父元素overflow 限制的组件非常有用。

### 适用范围

- 模态框（移动到 body 下）
- 下拉菜单
- 工具提示
- 固定定位的元素

### 语法

```html
<!-- 移动到 body -->
<div x-data="{ show: false }">
    <button @click="show = true">打开模态框</button>

    <template x-teleport="body">
        <div x-show="show" style="position: fixed; inset: 0; background: rgba(0,0,0,0.5);">
            <div style="background: white; padding: 20px; margin: 100px auto; max-width: 400px;">
                <p>这是一个模态框</p>
                <button @click="show = false">关闭</button>
            </div>
        </div>
    </template>
</div>

<!-- 移动到指定选择器的元素 -->
<template x-teleport="#modal-container">
    <div>内容</div>
</template>
```

### 注意事项

- 必须使用 `<template>` 标签包裹被移动的元素
- 目标位置可以是 `body` 或任意 CSS 选择器
- 移动后的事件监听和样式可能需要重新考虑

---

## x-if

### 说明

`x-if` 用于条件渲染，与 `x-show` 不同的是，它会真正地从 DOM 中添加或移除元素，而不是简单地切换显示状态。

### 适用范围

- 条件性的 DOM 节点
- 需要配合 `<template>` 使用
- 大型列表的条件过滤

### 语法

```html
<div x-data="{ loggedIn: false }">
    <template x-if="loggedIn">
        <div class="user-panel">
            <p>欢迎回来！</p>
            <button @click="loggedIn = false">退出</button>
        </div>
    </template>

    <template x-if="!loggedIn">
        <div class="login-prompt">
            <p>请登录</p>
            <button @click="loggedIn = true">登录</button>
        </div>
    </template>
</div>
```

### 注意事项

- 必须配合 `<template>` 标签使用
- 不支持过渡动画（需要使用 `x-show`）
- 每次条件变化时元素会重新创建，而不是显示/隐藏

---

## x-id

### 说明

`x-id` 用于生成唯一的 ID 字符串，常用于为可访问性（a11y）属性生成唯一标识符。

### 适用范围

- 表单标签与输入框的关联
- 生成唯一的 ARIA 属性值
- 动态创建可访问的 UI 组件

### 语法

```html
<div x-data x-id="['text-input', 'text-label']">
    <label :for="$id('text-input')" x-text="$id('text-label')"></label>
    <input type="text" :id="$id('text-input')">
</div>
```

### 注意事项

- `$id()` 生成的 ID 具有确定性，相同名称会生成相同 ID
- 可以生成多个不同的 ID
- 主要用于提高网页的可访问性

---

## 总结

Alpine.js 的魔法属性共同构成了一个轻量级的响应式 DOM 操作框架。通过这些指令的组合使用，可以实现大多数前端交互需求，而无需编写冗长的 JavaScript 代码。掌握这些指令的使用方法，能够快速构建出简洁、高效的 Web 应用程序。
