生命周期 #
概述 #
Alpine.js 组件从创建到销毁经历一系列阶段,称为生命周期。理解生命周期可以帮助你在正确的时机执行代码。
生命周期阶段 #
text
创建 → 初始化 → 挂载 → 更新 → 销毁
init 钩子 #
基本用法 #
init 在组件初始化时执行:
html
<div x-data="{
message: '',
init() {
this.message = 'Hello!'
console.log('组件已初始化')
}
}">
<p x-text="message"></p>
</div>
加载数据 #
html
<div x-data="{
users: [],
loading: false,
async init() {
await this.loadUsers()
},
async loadUsers() {
this.loading = true
const res = await fetch('/api/users')
this.users = await res.json()
this.loading = false
}
}">
<div x-show="loading">加载中...</div>
<template x-for="user in users">
<p x-text="user.name"></p>
</template>
</div>
设置监听器 #
html
<div x-data="{
scrollY: 0,
onScroll() {
this.scrollY = window.scrollY
},
init() {
window.addEventListener('scroll', this.onScroll.bind(this))
}
}">
滚动位置: <span x-text="scrollY"></span>px
</div>
初始化第三方库 #
html
<div x-data="{
editor: null,
init() {
this.$nextTick(() => {
this.editor = new Quill(this.$refs.editor, {
theme: 'snow'
})
})
}
}">
<div x-ref="editor"></div>
</div>
x-init 指令 #
基本用法 #
html
<div x-data="{ count: 0 }" x-init="count = 10">
<span x-text="count"></span>
</div>
调用方法 #
html
<div x-data="{
items: [],
loadItems() {
this.items = ['a', 'b', 'c']
}
}" x-init="loadItems()">
</div>
与 init 方法配合 #
x-init 先于 init 方法执行:
html
<div x-data="{
count: 0,
init() {
console.log('init 方法, count:', this.count)
}
}" x-init="count = 5; console.log('x-init, count:', count)">
</div>
输出:
text
x-init, count: 5
init 方法, count: 5
destroy 钩子 #
基本用法 #
destroy 在组件销毁时执行:
html
<div x-data="{
timer: null,
init() {
this.timer = setInterval(() => {
console.log('Tick')
}, 1000)
},
destroy() {
clearInterval(this.timer)
console.log('组件已销毁')
}
}">
<p>定时器运行中</p>
</div>
清理事件监听 #
html
<div x-data="{
scrollY: 0,
onScroll: null,
init() {
this.onScroll = () => {
this.scrollY = window.scrollY
}
window.addEventListener('scroll', this.onScroll)
},
destroy() {
window.removeEventListener('scroll', this.onScroll)
}
}">
滚动位置: <span x-text="scrollY"></span>px
</div>
清理第三方库 #
html
<div x-data="{
editor: null,
init() {
this.editor = new Quill(this.$refs.editor)
},
destroy() {
if (this.editor) {
this.editor = null
}
}
}">
<div x-ref="editor"></div>
</div>
x-effect #
响应式副作用 #
x-effect 在依赖数据变化时执行:
html
<div x-data="{ count: 0 }" x-effect="console.log('count:', count)">
<button @click="count++">增加</button>
</div>
初始化时执行 #
x-effect 在组件初始化时也会执行一次:
html
<div x-data="{ name: 'John' }" x-effect="document.title = name">
<input x-model="name">
</div>
与 $watch 的区别 #
| 特性 | x-effect | $watch |
|---|---|---|
| 自动追踪依赖 | 是 | 需要指定 |
| 初始执行 | 是 | 否 |
| 获取旧值 | 否 | 是 |
Alpine.effect #
全局副作用 #
javascript
Alpine.effect(() => {
console.log('Store count:', Alpine.store('app').count)
})
清理副作用 #
javascript
const dispose = Alpine.effect(() => {
console.log('effect')
})
dispose()
实用示例 #
数据获取组件 #
html
<div x-data="{
data: null,
loading: false,
error: null,
async init() {
await this.fetch()
},
async fetch() {
this.loading = true
this.error = null
try {
const res = await fetch('/api/data')
this.data = await res.json()
} catch (e) {
this.error = e.message
} finally {
this.loading = false
}
}
}">
<div x-show="loading">加载中...</div>
<div x-show="error" x-text="error"></div>
<div x-show="data">
<pre x-text="JSON.stringify(data, null, 2)"></pre>
</div>
</div>
定时器组件 #
html
<div x-data="{
time: null,
timer: null,
init() {
this.updateTime()
this.timer = setInterval(() => this.updateTime(), 1000)
},
destroy() {
if (this.timer) {
clearInterval(this.timer)
}
},
updateTime() {
this.time = new Date().toLocaleTimeString()
}
}">
当前时间: <span x-text="time"></span>
</div>
WebSocket 连接 #
html
<div x-data="{
socket: null,
messages: [],
connected: false,
init() {
this.connect()
},
destroy() {
this.disconnect()
},
connect() {
this.socket = new WebSocket('wss://example.com/ws')
this.socket.onopen = () => {
this.connected = true
}
this.socket.onclose = () => {
this.connected = false
}
this.socket.onmessage = (event) => {
this.messages.push(JSON.parse(event.data))
}
},
disconnect() {
if (this.socket) {
this.socket.close()
}
},
send(message) {
if (this.socket && this.connected) {
this.socket.send(JSON.stringify(message))
}
}
}">
<p>状态: <span x-text="connected ? '已连接' : '未连接'"></span></p>
<template x-for="msg in messages">
<p x-text="msg.text"></p>
</template>
</div>
窗口尺寸监听 #
html
<div x-data="{
width: 0,
height: 0,
onResize: null,
init() {
this.updateSize()
this.onResize = () => this.updateSize()
window.addEventListener('resize', this.onResize)
},
destroy() {
window.removeEventListener('resize', this.onResize)
},
updateSize() {
this.width = window.innerWidth
this.height = window.innerHeight
}
}">
窗口尺寸: <span x-text="width"></span> x <span x-text="height"></span>
</div>
键盘快捷键 #
html
<div x-data="{
shortcuts: {
's': () => this.save(),
'n': () => this.newItem(),
'd': () => this.delete()
},
onKeyDown: null,
init() {
this.onKeyDown = (e) => {
if (e.ctrlKey || e.metaKey) {
const handler = this.shortcuts[e.key]
if (handler) {
e.preventDefault()
handler()
}
}
}
window.addEventListener('keydown', this.onKeyDown)
},
destroy() {
window.removeEventListener('keydown', this.onKeyDown)
},
save() { console.log('保存') },
newItem() { console.log('新建') },
delete() { console.log('删除') }
}">
<p>快捷键: Ctrl+S 保存, Ctrl+N 新建, Ctrl+D 删除</p>
</div>
本地存储同步 #
html
<div x-data="{
theme: 'light',
storageKey: 'app-theme',
init() {
this.loadFromStorage()
this.$watch('theme', () => this.saveToStorage())
},
loadFromStorage() {
const saved = localStorage.getItem(this.storageKey)
if (saved) {
this.theme = saved
}
},
saveToStorage() {
localStorage.setItem(this.storageKey, this.theme)
}
}">
<select x-model="theme">
<option value="light">浅色</option>
<option value="dark">深色</option>
</select>
</div>
$nextTick #
DOM 更新后执行 #
html
<div x-data="{
items: [],
addItem() {
this.items.push('New Item')
this.$nextTick(() => {
console.log('DOM 已更新')
this.$refs.list.lastElementChild?.scrollIntoView()
})
}
}">
<ul x-ref="list">
<template x-for="item in items">
<li x-text="item"></li>
</template>
</ul>
<button @click="addItem()">添加</button>
</div>
聚焦新元素 #
html
<div x-data="{
showInput: false,
focusInput() {
this.showInput = true
this.$nextTick(() => {
this.$refs.input.focus()
})
}
}">
<button @click="focusInput()">显示输入框</button>
<input x-ref="input" x-show="showInput">
</div>
生命周期流程 #
text
1. x-data 创建响应式数据
2. x-init 执行(如果存在)
3. init 方法执行(如果存在)
4. x-effect 执行(如果存在)
5. 首次 DOM 渲染
6. 数据变化时 DOM 更新
7. x-if 为 false 或元素移除时 destroy 执行
最佳实践 #
1. 在 init 中初始化 #
javascript
{
init() {
this.loadData()
this.setupListeners()
}
}
2. 在 destroy 中清理 #
javascript
{
init() {
this.timer = setInterval(...)
},
destroy() {
clearInterval(this.timer)
}
}
3. 使用 $nextTick 操作 DOM #
javascript
{
showElement() {
this.visible = true
this.$nextTick(() => {
this.$refs.element.focus()
})
}
}
4. 避免在 init 中阻塞 #
javascript
{
async init() {
this.loading = true
try {
this.data = await this.fetch()
} finally {
this.loading = false
}
}
}
小结 #
生命周期要点:
init在组件初始化时执行destroy在组件销毁时执行x-init指令先于init方法x-effect在依赖变化时执行$nextTick在 DOM 更新后执行- 记得清理事件监听和定时器
下一章,我们将学习高级特性。
最后更新:2026-03-28