项目结构 #
概述 #
良好的项目结构是构建可维护 Alpine.js 应用的基础。本章将介绍推荐的项目组织方式。
基础项目结构 #
CDN 项目 #
text
project/
├── index.html
├── css/
│ └── style.css
├── js/
│ ├── alpine-init.js
│ ├── components/
│ │ ├── dropdown.js
│ │ ├── modal.js
│ │ └── tabs.js
│ └── stores/
│ ├── user.js
│ └── cart.js
└── assets/
└── images/
NPM 项目 #
text
project/
├── src/
│ ├── index.js
│ ├── components/
│ │ ├── index.js
│ │ ├── dropdown.js
│ │ ├── modal.js
│ │ └── tabs.js
│ ├── stores/
│ │ ├── index.js
│ │ ├── user.js
│ │ └── cart.js
│ ├── plugins/
│ │ └── my-plugin.js
│ └── utils/
│ └── helpers.js
├── public/
│ └── index.html
├── package.json
└── vite.config.js
组件组织 #
单文件组件 #
javascript
export function dropdown() {
return {
open: false,
toggle() {
this.open = !this.open
},
close() {
this.open = false
}
}
}
export function dropdownTemplate() {
return `
<div x-data="dropdown()" class="dropdown">
<button @click="toggle()">菜单</button>
<div x-show="open" @click.away="close()">
<slot></slot>
</div>
</div>
`
}
组件注册 #
javascript
import { dropdown } from './components/dropdown'
import { modal } from './components/modal'
import { tabs } from './components/tabs'
document.addEventListener('alpine:init', () => {
Alpine.data('dropdown', dropdown)
Alpine.data('modal', modal)
Alpine.data('tabs', tabs)
})
组件索引 #
javascript
export { dropdown } from './dropdown'
export { modal } from './modal'
export { tabs } from './tabs'
export function registerComponents(Alpine) {
Alpine.data('dropdown', dropdown)
Alpine.data('modal', modal)
Alpine.data('tabs', tabs)
}
Store 组织 #
单个 Store 文件 #
javascript
export const userStore = {
data: null,
token: null,
get isAuthenticated() {
return !!this.token && !!this.data
},
async login(credentials) {
const res = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(credentials)
})
const data = await res.json()
this.token = data.token
this.data = data.user
localStorage.setItem('token', data.token)
},
logout() {
this.data = null
this.token = null
localStorage.removeItem('token')
}
}
export function registerUserStore(Alpine) {
Alpine.store('user', userStore)
}
Store 索引 #
javascript
import { registerUserStore } from './user'
import { registerCartStore } from './cart'
import { registerNotificationStore } from './notification'
export function registerStores(Alpine) {
registerUserStore(Alpine)
registerCartStore(Alpine)
registerNotificationStore(Alpine)
}
入口文件 #
完整入口示例 #
javascript
import Alpine from 'alpinejs'
import { registerComponents } from './components'
import { registerStores } from './stores'
import { registerPlugins } from './plugins'
window.Alpine = Alpine
document.addEventListener('alpine:init', () => {
registerComponents(Alpine)
registerStores(Alpine)
registerPlugins(Alpine)
})
Alpine.start()
Laravel 集成 #
Blade 组件 #
html
@props(['open' => false])
<div
x-data="{ open: {{ $open ? 'true' : 'false' }} }"
class="dropdown"
>
<button @click="open = !open">
{{ $slot->title }}
</button>
<div x-show="open" @click.away="open = false">
{{ $slot->content }}
</div>
</div>
使用组件 #
html
<x-dropdown>
<x-slot:title>
菜单
</x-slot:title>
<x-slot:content>
<a href="#">选项 1</a>
<a href="#">选项 2</a>
</x-slot:content>
</x-dropdown>
Rails 集成 #
ERB 组件 #
erb
<div
x-data="{ open: <%= open ? 'true' : 'false' %> }"
class="dropdown"
>
<button @click="open = !open">
<%= title %>
</button>
<div x-show="open" @click.away="open = false">
<%= content %>
</div>
</div>
命名约定 #
组件命名 #
javascript
Alpine.data('userDropdown', () => ({ }))
Alpine.data('productCard', () => ({ }))
Alpine.data('searchInput', () => ({ }))
Store 命名 #
javascript
Alpine.store('user', { })
Alpine.store('cart', { })
Alpine.store('notification', { })
事件命名 #
javascript
$dispatch('user:login')
$dispatch('user:logout')
$dispatch('cart:add')
$dispatch('cart:remove')
目录结构示例 #
中型项目 #
text
project/
├── src/
│ ├── index.js
│ ├── components/
│ │ ├── ui/
│ │ │ ├── button.js
│ │ │ ├── input.js
│ │ │ └── modal.js
│ │ ├── forms/
│ │ │ ├── contact-form.js
│ │ │ └── search-form.js
│ │ └── layout/
│ │ ├── header.js
│ │ ├── sidebar.js
│ │ └── footer.js
│ ├── stores/
│ │ ├── user.js
│ │ ├── cart.js
│ │ └── ui.js
│ ├── plugins/
│ │ ├── persist.js
│ │ └── toast.js
│ ├── utils/
│ │ ├── api.js
│ │ ├── format.js
│ │ └── validation.js
│ └── styles/
│ └── main.css
└── public/
└── index.html
大型项目 #
text
project/
├── src/
│ ├── index.js
│ ├── modules/
│ │ ├── auth/
│ │ │ ├── components/
│ │ │ │ ├── login-form.js
│ │ │ │ └── register-form.js
│ │ │ ├── stores/
│ │ │ │ └── auth.js
│ │ │ └── index.js
│ │ ├── products/
│ │ │ ├── components/
│ │ │ │ ├── product-card.js
│ │ │ │ └── product-list.js
│ │ │ ├── stores/
│ │ │ │ └── products.js
│ │ │ └── index.js
│ │ └── cart/
│ │ ├── components/
│ │ │ ├── cart-item.js
│ │ │ └── cart-summary.js
│ │ ├── stores/
│ │ │ └── cart.js
│ │ └── index.js
│ ├── shared/
│ │ ├── components/
│ │ ├── stores/
│ │ └── utils/
│ └── plugins/
└── public/
最佳实践 #
1. 按功能组织 #
text
features/
├── auth/
│ ├── components/
│ ├── stores/
│ └── utils/
├── products/
└── cart/
2. 保持组件独立 #
javascript
export function counter(initial = 0) {
return {
count: initial,
increment() { this.count++ },
decrement() { this.count-- }
}
}
3. 使用索引文件 #
javascript
export * from './components'
export * from './stores'
export * from './utils'
4. 配置外部化 #
javascript
const config = {
apiUrl: import.meta.env.VITE_API_URL,
timeout: 5000
}
export function useApi() {
return {
async fetch(endpoint) {
return fetch(config.apiUrl + endpoint)
}
}
}
小结 #
项目结构要点:
- 按功能模块组织代码
- 使用索引文件简化导入
- 保持组件独立性
- 统一命名约定
- 适配后端框架
下一章,我们将学习 Alpine.js 与 TypeScript 集成。
最后更新:2026-03-28