x-data 数据声明 #
什么是 x-data? #
x-data 是 Alpine.js 最核心的指令,用于声明一个组件的响应式数据作用域。所有 Alpine.js 组件都必须以 x-data 开始。
基本语法 #
html
<div x-data="{ 属性名: 值, 方法名() { ... } }">
<!-- 组件内容 -->
</div>
基本用法 #
声明简单数据 #
html
<div x-data="{ message: 'Hello Alpine!' }">
<p x-text="message"></p>
</div>
声明多个属性 #
html
<div x-data="{
name: 'John',
age: 25,
city: 'Beijing'
}">
<p>姓名: <span x-text="name"></span></p>
<p>年龄: <span x-text="age"></span></p>
<p>城市: <span x-text="city"></span></p>
</div>
声明方法 #
html
<div x-data="{
count: 0,
increment() { this.count++ },
decrement() { this.count-- },
reset() { this.count = 0 }
}">
<p>计数: <span x-text="count"></span></p>
<button @click="increment()">增加</button>
<button @click="decrement()">减少</button>
<button @click="reset()">重置</button>
</div>
声明计算属性 #
使用 getter 定义计算属性:
html
<div x-data="{
firstName: 'John',
lastName: 'Doe',
get fullName() {
return `${this.firstName} ${this.lastName}`
}
}">
<p x-text="fullName"></p>
</div>
数据类型 #
基本类型 #
html
<div x-data="{
string: 'Hello',
number: 42,
boolean: true,
null: null,
undefined: undefined
}">
</div>
对象类型 #
html
<div x-data="{
user: {
name: 'John',
email: 'john@example.com',
address: {
city: 'Beijing',
country: 'China'
}
}
}">
<p x-text="user.name"></p>
<p x-text="user.address.city"></p>
</div>
数组类型 #
html
<div x-data="{
items: ['Apple', 'Banana', 'Orange'],
users: [
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' }
]
}">
<template x-for="item in items">
<p x-text="item"></p>
</template>
</div>
使用函数初始化 #
内联函数 #
html
<div x-data="{
count: 0,
items: [],
init() {
this.items = ['a', 'b', 'c']
}
}">
</div>
外部函数 #
html
<div x-data="userComponent()">
<p x-text="name"></p>
</div>
<script>
function userComponent() {
return {
name: 'John',
email: 'john@example.com',
greet() {
alert(`Hello, ${this.name}!`)
}
}
}
</script>
带参数的函数 #
html
<div x-data="counter(10)">
<span x-text="count"></span>
<button @click="increment()">+</button>
</div>
<script>
function counter(initialValue) {
return {
count: initialValue,
increment() {
this.count++
}
}
}
</script>
Alpine.data() 注册组件 #
注册全局组件 #
javascript
document.addEventListener('alpine:init', () => {
Alpine.data('dropdown', () => ({
open: false,
toggle() {
this.open = !this.open
},
close() {
this.open = false
}
}))
})
使用注册的组件 #
html
<div x-data="dropdown">
<button @click="toggle()">切换</button>
<div x-show="open" @click.away="close()">
下拉内容
</div>
</div>
带参数的组件 #
javascript
Alpine.data('counter', (initial = 0) => ({
count: initial,
increment() { this.count++ },
decrement() { this.count-- }
}))
html
<div x-data="counter(100)">
<span x-text="count"></span>
</div>
作用域与继承 #
作用域范围 #
x-data 创建一个作用域,子元素可以访问父作用域的数据:
html
<div x-data="{ message: 'Hello' }">
<p x-text="message"></p>
<div>
<p x-text="message"></p>
</div>
</div>
作用域覆盖 #
子 x-data 可以覆盖父作用域的同名属性:
html
<div x-data="{ name: 'Parent' }">
<p x-text="name"></p>
<div x-data="{ name: 'Child' }">
<p x-text="name"></p>
</div>
</div>
作用域隔离 #
独立的 x-data 组件之间互不影响:
html
<div x-data="{ count: 0 }">
<button @click="count++">计数: <span x-text="count"></span></button>
</div>
<div x-data="{ count: 100 }">
<button @click="count++">计数: <span x-text="count"></span></button>
</div>
访问 this #
在方法中,this 指向当前组件的数据对象:
html
<div x-data="{
name: 'John',
greet() {
console.log(this.name)
},
updateName(newName) {
this.name = newName
}
}">
<button @click="greet()">问候</button>
<button @click="updateName('Jane')">改名</button>
</div>
箭头函数注意事项 #
箭头函数没有自己的 this,在箭头函数中访问数据需要使用普通函数:
javascript
Alpine.data('example', () => ({
count: 0,
increment: () => {
this.count++
},
decrement() {
this.count--
}
}))
推荐使用普通函数:
javascript
Alpine.data('example', function() {
return {
count: 0,
increment() {
this.count++
}
}
})
实用示例 #
表单组件 #
html
<form x-data="{
form: {
name: '',
email: '',
message: ''
},
errors: {},
submit() {
this.errors = {}
if (!this.form.name) this.errors.name = '请输入姓名'
if (!this.form.email) this.errors.email = '请输入邮箱'
if (Object.keys(this.errors).length === 0) {
console.log('提交:', this.form)
}
}
}" @submit.prevent="submit()">
<div>
<input x-model="form.name" placeholder="姓名">
<span x-show="errors.name" x-text="errors.name" style="color: red"></span>
</div>
<div>
<input x-model="form.email" placeholder="邮箱">
<span x-show="errors.email" x-text="errors.email" style="color: red"></span>
</div>
<button type="submit">提交</button>
</form>
标签页组件 #
html
<div x-data="{
tabs: ['首页', '关于', '联系'],
activeTab: '首页',
setActive(tab) {
this.activeTab = tab
}
}">
<div class="tabs">
<template x-for="tab in tabs">
<button
@click="setActive(tab)"
:class="{ active: activeTab === tab }"
x-text="tab"
></button>
</template>
</div>
<div class="content">
<div x-show="activeTab === '首页'">首页内容</div>
<div x-show="activeTab === '关于'">关于内容</div>
<div x-show="activeTab === '联系'">联系内容</div>
</div>
</div>
手风琴组件 #
html
<div x-data="{
items: [
{ title: '标题1', content: '内容1', open: false },
{ title: '标题2', content: '内容2', open: false },
{ title: '标题3', content: '内容3', open: false }
],
toggle(index) {
this.items[index].open = !this.items[index].open
}
}">
<template x-for="(item, index) in items">
<div class="accordion-item">
<button @click="toggle(index)" x-text="item.title"></button>
<div x-show="item.open" x-text="item.content"></div>
</div>
</template>
</div>
最佳实践 #
1. 保持数据扁平化 #
javascript
Alpine.data('user', () => ({
user: {
profile: {
name: '',
email: ''
}
}
}))
2. 分离复杂逻辑 #
javascript
Alpine.data('form', () => ({
data: {},
validators: {},
errors: {},
validate(field) {
const validator = this.validators[field]
if (validator) {
this.errors[field] = validator(this.data[field])
}
},
validateAll() {
Object.keys(this.validators).forEach(field => this.validate(field))
return Object.values(this.errors).every(e => !e)
}
}))
3. 使用初始化钩子 #
javascript
Alpine.data('asyncData', () => ({
loading: false,
data: null,
error: null,
async init() {
await this.fetch()
},
async fetch() {
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-data 是 Alpine.js 的核心指令:
- 定义组件的响应式数据作用域
- 支持属性、方法、计算属性
- 可以使用函数或
Alpine.data()初始化 - 子元素继承父作用域
- 注意箭头函数的
this问题
下一章,我们将学习 x-show 指令控制元素的显示和隐藏。
最后更新:2026-03-28