# Alpine.js Globals

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


## 概述

Alpine.js 提供了一系列全局 API（Global Functions），这些函数可以直接通过 `Alpine` 对象访问，用于定义可复用组件、管理全局状态、绑定行为等。这些全局 API 是构建大型应用程序的基础设施，能够帮助开发者组织代码结构、实现状态共享和创建可复用的 UI 组件。

---

## Alpine.data()

### 说明

`Alpine.data()` 用于注册可复用的数据组件。它允许开发者将一组数据、方法和计算属性封装为一个可命名的组件，之后可以在 HTML 中通过 `x-data` 指令引用。这是一种将逻辑封装和复用的机制，类似于 Vue.js 中的组件系统。

### 适用范围

- 创建可复用的 UI 组件
- 封装业务逻辑和数据
- 在多个页面或位置重复使用相同组件逻辑
- 组织大型项目的代码结构
- 主题化组件的注册

### 语法

```javascript
// 注册一个数据组件
Alpine.data('组件名称', () => ({
    // 数据属性
    message: 'Hello World',
    count: 0,

    // 方法
    increment() {
        this.count++
    },

    // 计算属性（通过 getter）
    get doubled() {
        return this.count * 2
    },

    // 生命周期钩子
    init() {
        console.log('组件初始化')
    }
}))
```

```html
<!-- 在 HTML 中使用注册的组件 -->
<div x-data="组件名称()">
    <p x-text="message"></p>
    <p>计数: <span x-text="count"></span></p>
    <p>双倍: <span x-text="doubled"></span></p>
    <button @click="increment()">增加</button>
</div>
```

### 嵌套组件

```javascript
// 注册包含嵌套组件的数据
Alpine.data('dropdown', () => ({
    open: false,

    toggle() {
        this.open = !this.open
    }
}))
```

```html
<!-- 使用组件 -->
<div x-data="dropdown()">
    <button @click="toggle()">切换</button>
    <div x-show="open" x-transition>
        下拉内容
    </div>
</div>
```

### 依赖注入

```javascript
// 组件可以使用其他组件
Alpine.data('userCard', (userService) => ({
    user: null,
    loading: true,

    async init() {
        this.user = await userService.getCurrentUser()
        this.loading = false
    }
}), ['userService']) // 依赖注入
```

### 注意事项

- 组件注册需要在 Alpine.js 初始化之前完成，建议使用 `alpine:init` 事件
- 组件名称推荐使用有意义的命名，如 `modal`、`dropdown`、`userProfile` 等
- `Alpine.data()` 接收一个返回对象的工厂函数，每次 `x-data` 调用时会创建新的实例
- 可以传递额外的依赖参数，用于依赖注入
- 组件内部可以通过 `this` 访问自身的数据和方法
- 避免在组件中定义过大的对象，保持组件职责单一

---

## Alpine.store()

### 说明

`Alpine.store()` 用于创建和管理全局状态存储。它提供了一个响应式的全局数据容器，可以在页面的任何组件中访问和修改。store 非常适合用于管理跨组件共享的数据，如用户认证状态、主题设置、全局配置等。

### 适用范围

- 用户认证状态管理
- 主题切换（亮色/暗色模式）
- 全局配置和设置
- 购物车数据
- 消息通知系统
- 多组件间的数据共享
- 实时数据同步

### 语法

```javascript
// 注册全局 store
document.addEventListener('alpine:init', () => {
    // 定义单个 store
    Alpine.store('user', {
        name: '访客',
        isLoggedIn: false,
        email: '',

        login(name, email) {
            this.name = name
            this.email = email
            this.isLoggedIn = true
        },

        logout() {
            this.name = '访客'
            this.email = ''
            this.isLoggedIn = false
        }
    })

    // 定义主题 store
    Alpine.store('theme', {
        mode: 'light',
        colors: {
            primary: '#3490dc',
            secondary: '#656d4a'
        },

        toggle() {
            this.mode = this.mode === 'light' ? 'dark' : 'light'
        },

        setMode(mode) {
            this.mode = mode
        }
    })

    // 定义购物车 store
    Alpine.store('cart', {
        items: [],
        total: 0,

        addItem(item) {
            this.items.push(item)
            this.calculateTotal()
        },

        removeItem(index) {
            this.items.splice(index, 1)
            this.calculateTotal()
        },

        calculateTotal() {
            this.total = this.items.reduce((sum, item) => sum + item.price, 0)
        },

        clear() {
            this.items = []
            this.total = 0
        }
    })
})
```

```html
<!-- 在组件中使用 store -->
<div x-data>
    <!-- 用户状态 -->
    <div x-show="$store.user.isLoggedIn">
        欢迎，<span x-text="$store.user.name"></span>！
        <button @click="$store.user.logout()">退出</button>
    </div>

    <div x-show="!$store.user.isLoggedIn">
        <button @click="$store.user.login('张三', 'zhangsan@example.com')">登录</button>
    </div>

    <!-- 主题切换 -->
    <button @click="$store.theme.toggle()">
        切换到<span x-text="$store.theme.mode === 'light' ? '暗色' : '亮色'"></span>模式
    </button>

    <!-- 购物车 -->
    <div>
        购物车: <span x-text="$store.cart.items.length"></span> 件商品
        总价: ¥<span x-text="$store.cart.total"></span>
    </div>
</div>
```

### 响应式特性

```javascript
// store 是响应式的，修改会自动更新所有引用
Alpine.store('counter', {
    count: 0
})

// 在任何地方修改都会响应式更新
Alpine.store('counter').count++

// 或者在组件中修改
<div x-data>
    <button @click="$store.counter.count++">增加</button>
</div>
```

### 注意事项

- store 必须在 `alpine:init` 事件触发前定义，该事件在 Alpine.js 初始化时触发
- store 中的数据是响应式的，修改后所有使用 `$store` 的地方都会自动更新
- store 可以包含方法，用于封装业务逻辑
- 多个 store 之间可以相互引用
- store 适合存储相对稳定的数据，频繁变化的数据建议使用组件局部状态
- store 的设计理念类似于 Vuex/Redux，但更加轻量简单
- 可以使用 `Alpine.store('name')` 获取 store 的引用进行编程式操作
- 在使用 store 之前，确保已经正确注册

---

## Alpine.bind()

### 说明

`Alpine.bind()` 用于创建可复用的属性绑定配置。它允许开发者定义一组属性绑定规则，然后在多个元素上复用这些规则。这是一种 DRY（Don't Repeat Yourself）原则的实践，可以减少重复的属性定义代码。

### 适用范围

- 复用相同的属性绑定模式
- 创建统一的按钮样式和行为
- 标准化表单元素配置
- 封装复杂的绑定逻辑
- 创建可配置的组件模板

### 语法

```javascript
// 定义绑定配置
document.addEventListener('alpine:init', () => {
    // 定义一个按钮绑定
    Alpine.bind('button', () => ({
        '@click'() {
            console.log('按钮被点击')
        },
        ':class'() {
            return 'btn btn-primary'
        },
        ':disabled'() {
            return this.loading
        }
    }))

    // 定义输入框绑定
    Alpine.bind('input', () => ({
        ':class'() {
            return 'form-control ' + (this.error ? 'is-invalid' : '')
        },
        '@focus'() {
            this.focused = true
        },
        '@blur'() {
            this.focused = false
        }
    }))
})
```

```html
<!-- 使用绑定的属性 -->
<div x-data="{ loading: false, error: false }">
    <button x-bind>点击我</button>
    <input x-bind>
</div>
```

### 传递参数

```javascript
Alpine.bind('button', (params = {}) => ({
    ':class'() {
        return params.variant || 'btn-primary'
    },
    ':disabled'() {
        return params.disabled || false
    }
}))
```

```html
<!-- 使用时传递参数 -->
<button x-bind :variant="'btn-success'" :disabled="isLoading">确认</button>
```

### 高级用法

```javascript
// 动态绑定配置
Alpine.bind('card', () => {
    const defaultBindings = {
        ':class'() {
            return 'card shadow-sm'
        }
    }

    // 根据条件添加额外绑定
    if (this.hoverable) {
        defaultBindings['@mouseenter'] = () => {
            this.$el.classList.add('hover')
        }
        defaultBindings['@mouseleave'] = () => {
            this.$el.classList.remove('hover')
        }
    }

    return defaultBindings
})
```

### 注意事项

- `Alpine.bind()` 的第一个参数是元素选择器，匹配该选择器的元素会自动应用定义的属性
- 绑定配置可以包含任何 `x-bind` 支持的属性
- 绑定函数内部的 `this` 指向当前元素所在组件的数据对象
- 绑定配置是静态定义的，不支持动态参数传递（可以通过表达式间接实现）
- 过度使用 `Alpine.bind()` 可能导致代码可读性下降，建议仅用于确实需要复用的大段配置
- 绑定配置在 Alpine.js 初始化时应用，之后不会重新评估

---

## Alpine.start()

### 说明

`Alpine.start()` 用于手动启动 Alpine.js，通常用于需要控制初始化时机的场景。

### 适用范围

- 延迟加载 Alpine.js
- 动态注入内容后的初始化
- 与其他框架集成时的时序控制

### 语法

```javascript
// 手动启动 Alpine.js
document.addEventListener('DOMContentLoaded', () => {
    Alpine.start()
})

// 或者延迟启动
setTimeout(() => {
    Alpine.start()
}, 1000)

```

### 注意事项

- 默认情况下，Alpine.js 会在 DOMContentLoaded 时自动启动
- 手动启动时，确保在 DOM 加载完成后调用
- 动态添加内容后，可能需要调用相关初始化方法

---

## Alpine.version

### 说明

`Alpine.version` 是 Alpine.js 的版本属性，返回当前使用的 Alpine.js 版本号。

### 语法

```javascript
console.log(Alpine.version) // 例如: "3.13.3"

// 根据版本执行不同逻辑
if (Alpine.version.startsWith('3.')) {
    console.log('使用 Alpine.js 3.x')
}
```

---

## 总结

Alpine.js 的全局 API 为开发者提供了强大的工具集，用于组织代码结构、管理全局状态和创建可复用的组件。通过 `Alpine.data()` 可以封装可复用的组件逻辑，通过 `Alpine.store()` 可以管理跨组件共享的全局状态，通过 `Alpine.bind()` 可以创建可复用的属性绑定规则。这些 API 共同构成了 Alpine.js 应用程序的基础设施，使得构建复杂的前端应用变得更加简单和高效。掌握这些全局 API 的使用，能够帮助开发者更好地组织代码、提高代码复用性，并构建出更加健壮的应用程序。
