x-init 初始化 #

什么是 x-init? #

x-init 指令在 Alpine.js 组件初始化时执行代码。它常用于加载数据、设置初始状态或执行其他启动逻辑。

基本语法 #

html
<div x-data="{ ... }" x-init="初始化代码">
</div>

基本用法 #

执行简单代码 #

html
<div x-data="{ message: '' }" x-init="message = 'Hello!'">
    <p x-text="message"></p>
</div>

调用方法 #

html
<div x-data="{
    items: [],
    loadItems() {
        this.items = ['Item 1', 'Item 2', 'Item 3']
    }
}" x-init="loadItems()">
    <template x-for="item in items">
        <p x-text="item"></p>
    </template>
</div>

使用 init 方法 #

x-data 中定义 init 方法,会自动执行:

html
<div x-data="{
    items: [],
    init() {
        this.items = ['Item 1', 'Item 2', 'Item 3']
    }
}">
    <template x-for="item in items">
        <p x-text="item"></p>
    </template>
</div>

异步初始化 #

加载远程数据 #

html
<div x-data="{
    users: [],
    loading: false,
    error: null,
    async init() {
        this.loading = true
        try {
            const res = await fetch('/api/users')
            this.users = 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>
    <template x-for="user in users">
        <p x-text="user.name"></p>
    </template>
</div>

链式异步操作 #

html
<div x-data="{
    data: null,
    async init() {
        const user = await this.fetchUser()
        const posts = await this.fetchPosts(user.id)
        this.data = { user, posts }
    },
    async fetchUser() {
        const res = await fetch('/api/user')
        return res.json()
    },
    async fetchPosts(userId) {
        const res = await fetch(`/api/posts?userId=${userId}`)
        return res.json()
    }
}">
</div>

x-init vs init 方法 #

x-init 属性 #

html
<div x-data="{ count: 0 }" x-init="count = 10">
</div>

init 方法 #

html
<div x-data="{
    count: 0,
    init() {
        this.count = 10
    }
}">
</div>

两者区别 #

特性 x-init 属性 init 方法
位置 HTML 属性 x-data 内部
可读性 适合简单代码 适合复杂逻辑
复用 不易复用 可随组件复用
调试 较难调试 易于调试

同时使用 #

两者可以同时使用,x-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

实用示例 #

从 localStorage 加载 #

html
<div x-data="{
    theme: 'light',
    init() {
        const saved = localStorage.getItem('theme')
        if (saved) {
            this.theme = saved
        }
    },
    setTheme(value) {
        this.theme = value
        localStorage.setItem('theme', value)
    }
}">
    <button @click="setTheme('light')">浅色</button>
    <button @click="setTheme('dark')">深色</button>
    <div :class="'theme-' + theme">
        当前主题: <span x-text="theme"></span>
    </div>
</div>

初始化表单 #

html
<div x-data="{
    form: {
        name: '',
        email: '',
        country: ''
    },
    countries: [],
    async init() {
        const res = await fetch('/api/countries')
        this.countries = await res.json()
    }
}">
    <input x-model="form.name" placeholder="姓名">
    <input x-model="form.email" placeholder="邮箱">
    <select x-model="form.country">
        <option value="">选择国家</option>
        <template x-for="country in countries">
            <option :value="country.code" x-text="country.name"></option>
        </template>
    </select>
</div>

设置定时器 #

html
<div x-data="{
    time: null,
    timer: null,
    init() {
        this.updateTime()
        this.timer = setInterval(() => this.updateTime(), 1000)
    },
    updateTime() {
        this.time = new Date().toLocaleTimeString()
    },
    destroy() {
        if (this.timer) {
            clearInterval(this.timer)
        }
    }
}">
    当前时间: <span x-text="time"></span>
</div>

条件初始化 #

html
<div x-data="{
    user: null,
    mode: 'view',
    init() {
        const saved = localStorage.getItem('user')
        if (saved) {
            this.user = JSON.parse(saved)
            this.mode = 'edit'
        }
    }
}">
    <template x-if="user">
        <div>
            <p>欢迎回来, <span x-text="user.name"></span></p>
        </div>
    </template>
    <template x-if="!user">
        <div>
            <p>请登录</p>
        </div>
    </template>
</div>

初始化计算值 #

html
<div x-data="{
    items: [],
    filteredItems: [],
    filter: '',
    init() {
        this.items = [
            { id: 1, name: 'Apple', category: 'fruit' },
            { id: 2, name: 'Carrot', category: 'vegetable' },
            { id: 3, name: 'Banana', category: 'fruit' }
        ]
        this.applyFilter()
    },
    applyFilter() {
        if (!this.filter) {
            this.filteredItems = this.items
        } else {
            this.filteredItems = this.items.filter(
                item => item.category === this.filter
            )
        }
    }
}">
    <select x-model="filter" @change="applyFilter()">
        <option value="">全部</option>
        <option value="fruit">水果</option>
        <option value="vegetable">蔬菜</option>
    </select>
    
    <template x-for="item in filteredItems" :key="item.id">
        <p x-text="item.name"></p>
    </template>
</div>

注册全局监听 #

html
<div x-data="{
    scrollY: 0,
    init() {
        window.addEventListener('scroll', this.onScroll.bind(this))
    },
    onScroll() {
        this.scrollY = window.scrollY
    }
}">
    滚动位置: <span x-text="scrollY"></span>px
</div>

初始化第三方库 #

html
<div x-data="{
    editor: null,
    init() {
        this.$nextTick(() => {
            this.editor = new Editor({
                target: this.$refs.editor,
                props: {
                    content: ''
                }
            })
        })
    }
}">
    <div x-ref="editor"></div>
</div>

Alpine.data 中的 init #

Alpine.data 中定义 init 方法:

javascript
Alpine.data('userList', () => ({
    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
    }
}))
html
<div x-data="userList">
    <template x-for="user in users">
        <p x-text="user.name"></p>
    </template>
</div>

初始化时机 #

执行顺序 #

text
1. x-data 创建响应式数据
2. x-init 执行(如果存在)
3. init 方法执行(如果存在)
4. x-effect 执行(如果存在)
5. DOM 更新

$nextTick #

在 DOM 更新后执行代码:

html
<div x-data="{
    items: [],
    init() {
        this.items = ['Item 1', 'Item 2']
        this.$nextTick(() => {
            console.log('DOM 已更新')
        })
    }
}">
</div>

注意事项 #

1. 避免阻塞 #

异步操作不会阻塞渲染:

html
<div x-data="{
    data: null,
    async init() {
        this.data = await fetch('/api/data').then(r => r.json())
    }
}">
    <div x-show="!data">加载中...</div>
    <div x-show="data">内容</div>
</div>

2. 错误处理 #

异步初始化应该处理错误:

html
<div x-data="{
    data: null,
    error: null,
    async init() {
        try {
            this.data = await this.fetchData()
        } catch (e) {
            this.error = e.message
        }
    }
}">
</div>

3. 清理资源 #

使用 Alpine.effect 或手动清理:

html
<div x-data="{
    timer: null,
    init() {
        this.timer = setInterval(() => {}, 1000)
    },
    destroy() {
        clearInterval(this.timer)
    }
}">
</div>

小结 #

x-init 指令要点:

  • 在组件初始化时执行代码
  • 可以使用属性或 init 方法
  • 支持异步操作
  • 常用于加载数据和设置初始状态
  • 注意错误处理和资源清理

下一章,我们将学习 x-ref 指令引用 DOM 元素。

最后更新:2026-03-28