Claude Code Vue.js:Claude Code 实战指南
了解claude code vue.js:Claude Code 实战. 包含实用技巧和代码示例。
Vue.js开发でClaude Code 活躍する場面
Vue.jsはComposition APIやPiniaストアなど、モダンな设计パターンが豊富です。Claude Code 这らのパターンを理解した上で、类型安全で可维护性の高いVue组件を高效地生成可以。
Composition API组件の生成
> Vue 3のComposition APIで数据表格组件创建。
> 排序、筛选、分页機能实现。
> TypeScriptで类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类类型安全にして。
<script setup lang="ts">
import { ref, computed } from 'vue';
interface Column<T> {
key: keyof T;
label: string;
sortable?: boolean;
}
interface Props<T> {
data: T[];
columns: Column<T>[];
pageSize?: number;
}
const props = withDefaults(defineProps<Props<Record<string, unknown>>>(), {
pageSize: 10,
});
const sortKey = ref<string>('');
const sortOrder = ref<'asc' | 'desc'>('asc');
const filterText = ref('');
const currentPage = ref(1);
const filteredData = computed(() => {
if (!filterText.value) return props.data;
const query = filterText.value.toLowerCase();
return props.data.filter(row =>
Object.values(row).some(val =>
String(val).toLowerCase().includes(query)
)
);
});
const sortedData = computed(() => {
if (!sortKey.value) return filteredData.value;
return [...filteredData.value].sort((a, b) => {
const aVal = a[sortKey.value];
const bVal = b[sortKey.value];
const cmp = String(aVal).localeCompare(String(bVal));
return sortOrder.value === 'asc' ? cmp : -cmp;
});
});
const paginatedData = computed(() => {
const start = (currentPage.value - 1) * props.pageSize;
return sortedData.value.slice(start, start + props.pageSize);
});
const totalPages = computed(() =>
Math.ceil(filteredData.value.length / props.pageSize)
);
function handleSort(key: string) {
if (sortKey.value === key) {
sortOrder.value = sortOrder.value === 'asc' ? 'desc' : 'asc';
} else {
sortKey.value = key;
sortOrder.value = 'asc';
}
}
</script>
<template>
<div>
<input
v-model="filterText"
type="text"
placeholder="検索..."
class="mb-4 w-full rounded border px-3 py-2"
@input="currentPage = 1"
/>
<table class="w-full border-collapse">
<thead>
<tr>
<th
v-for="col in columns"
:key="String(col.key)"
class="cursor-pointer border-b px-4 py-2 text-left"
@click="col.sortable && handleSort(String(col.key))"
>
{{ col.label }}
<span v-if="sortKey === col.key">
{{ sortOrder === 'asc' ? ' ↑' : ' ↓' }}
</span>
</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, i) in paginatedData" :key="i" class="hover:bg-gray-50">
<td v-for="col in columns" :key="String(col.key)" class="border-b px-4 py-2">
{{ row[col.key] }}
</td>
</tr>
</tbody>
</table>
<div class="mt-4 flex items-center justify-between">
<span class="text-sm text-gray-600">
{{ filteredData.length }}件中 {{ (currentPage - 1) * pageSize + 1 }}〜{{ Math.min(currentPage * pageSize, filteredData.length) }}件
</span>
<div class="flex gap-2">
<button
:disabled="currentPage <= 1"
class="rounded border px-3 py-1 disabled:opacity-50"
@click="currentPage--"
>
Previous
</button>
<button
:disabled="currentPage >= totalPages"
class="rounded border px-3 py-1 disabled:opacity-50"
@click="currentPage++"
>
Next
</button>
</div>
</div>
</div>
</template>
Piniaストアの生成
> Piniaでショッピングカートストア创建。
> 商品添加、数量更改、合計金額計算实现。
// stores/cart.ts
import { defineStore } from 'pinia';
interface CartItem {
productId: string;
name: string;
price: number;
quantity: number;
image: string;
}
export const useCartStore = defineStore('cart', {
state: () => ({
items: [] as CartItem[],
}),
getters: {
totalItems: (state) =>
state.items.reduce((sum, item) => sum + item.quantity, 0),
totalPrice: (state) =>
state.items.reduce((sum, item) => sum + item.price * item.quantity, 0),
formattedTotal(): string {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
}).format(this.totalPrice);
},
},
actions: {
addItem(product: Omit<CartItem, 'quantity'>) {
const existing = this.items.find(i => i.productId === product.productId);
if (existing) {
existing.quantity++;
} else {
this.items.push({ ...product, quantity: 1 });
}
},
updateQuantity(productId: string, quantity: number) {
const item = this.items.find(i => i.productId === productId);
if (!item) return;
if (quantity <= 0) {
this.removeItem(productId);
} else {
item.quantity = quantity;
}
},
removeItem(productId: string) {
this.items = this.items.filter(i => i.productId !== productId);
},
clearCart() {
this.items = [];
},
},
persist: true,
});
コンポーザブルの创建
> APIフェッチ用のコンポーザブル创建。
> ローディング、错误、リトライ機能付きで。
// composables/useFetch.ts
import { ref, watchEffect, type Ref } from 'vue';
interface UseFetchOptions<T> {
immediate?: boolean;
defaultValue?: T;
transform?: (data: unknown) => T;
}
export function useFetch<T>(
url: string | Ref<string>,
options: UseFetchOptions<T> = {}
) {
const data = ref<T | null>(options.defaultValue ?? null) as Ref<T | null>;
const error = ref<Error | null>(null);
const loading = ref(false);
async function execute() {
loading.value = true;
error.value = null;
try {
const resolvedUrl = typeof url === 'string' ? url : url.value;
const res = await fetch(resolvedUrl);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json = await res.json();
data.value = options.transform ? options.transform(json) : json;
} catch (err) {
error.value = err as Error;
} finally {
loading.value = false;
}
}
async function retry() {
await execute();
}
if (options.immediate !== false) {
if (typeof url !== 'string') {
watchEffect(() => execute());
} else {
execute();
}
}
return { data, error, loading, execute, retry };
}
Nuxt.jsでの服务器APIルート
// server/api/products/index.get.ts
export default defineEventHandler(async (event) => {
const query = getQuery(event);
const page = Number(query.page) || 1;
const limit = Number(query.limit) || 20;
const products = await prisma.product.findMany({
skip: (page - 1) * limit,
take: limit,
orderBy: { createdAt: 'desc' },
});
const total = await prisma.product.count();
return {
items: products,
total,
page,
totalPages: Math.ceil(total / limit),
};
});
测试
import { describe, it, expect } from 'vitest';
import { setActivePinia, createPinia } from 'pinia';
import { useCartStore } from '@/stores/cart';
describe('Cart Store', () => {
beforeEach(() => {
setActivePinia(createPinia());
});
it('should add item to cart', () => {
const cart = useCartStore();
cart.addItem({ productId: '1', name: 'Test', price: 1000, image: '/test.jpg' });
expect(cart.items).toHaveLength(1);
expect(cart.totalItems).toBe(1);
});
it('should increment quantity for existing item', () => {
const cart = useCartStore();
cart.addItem({ productId: '1', name: 'Test', price: 1000, image: '/test.jpg' });
cart.addItem({ productId: '1', name: 'Test', price: 1000, image: '/test.jpg' });
expect(cart.items).toHaveLength(1);
expect(cart.items[0].quantity).toBe(2);
});
it('should calculate total price', () => {
const cart = useCartStore();
cart.addItem({ productId: '1', name: 'A', price: 1000, image: '' });
cart.addItem({ productId: '2', name: 'B', price: 2000, image: '' });
expect(cart.totalPrice).toBe(3000);
});
});
总结
借助 Claude Code,Vue.js / Nuxt.jsの组件、ストア、コンポーザブル、APIルートを类型安全かつ高效地开发可以。Vue特有のComposition APIパターンやPiniaの设计もClaude Code 熟知しています。プロンプトの書き方次第で品質が変わるため、プロンプトテクニック完全指南。项目のVue規約はCLAUDE.mdに記述しておくとよいでしょう。
Claude Code 的详细信息请参阅Anthropic官方文档。Vue.jsの公式指南はVue.js官方网站。
#Claude Code
#Vue.js
#Nuxt.js
#Pinia
#Composition API
Related Posts
Use Cases
Use Cases
用 Claude Code 加速个人项目开发【附实战案例】
详解如何用 Claude Code 大幅提升个人项目的开发速度。包含从创意到上线的完整实战案例和工作流。
Use Cases
Use Cases
如何用 Claude Code 自动化代码重构
详解如何利用 Claude Code 高效完成代码重构自动化。包含实用提示词和真实项目中的重构模式。
Use Cases
Use Cases
Complete CORS Configuration Guide:Claude Code 实战指南
了解complete cors configuration guide:Claude Code 实战. 包含实用技巧和代码示例。