Vue 3 实战:从零到一构建电商项目小兔鲜
1. 项目初始化与环境搭建
在开始构建小兔鲜电商项目前,我们需要先完成Vue 3开发环境的搭建。这里推荐使用Vite作为构建工具,它能提供极快的启动速度和热更新体验。打开终端执行以下命令:
npm init vue@latest xiaotuxian --template vue-ts这个命令会自动创建一个基于Vue 3和TypeScript的项目模板。安装完成后,进入项目目录安装必要依赖:
cd xiaotuxian npm install项目结构中最关键的是src/main.ts文件,这是整个应用的入口。我通常会在这里做三件事:初始化Vue应用实例、挂载全局组件/插件、设置全局样式。比如这样配置:
import { createApp } from 'vue' import App from './App.vue' import router from './router' import '@/styles/index.scss' const app = createApp(App) app.use(router) app.mount('#app')2. 核心功能模块开发
2.1 商品列表实现
商品列表是电商项目的核心页面,我们需要处理以下几个关键点:
- 数据获取:使用axios封装API请求
- 状态管理:用Pinia管理商品数据
- 列表渲染:结合v-for实现高效渲染
首先创建商品store:
// stores/goods.ts import { defineStore } from 'pinia' export const useGoodsStore = defineStore('goods', { state: () => ({ list: [] as GoodsItem[], loading: false }), actions: { async fetchGoodsList(params: Record<string, any>) { this.loading = true try { const res = await api.getGoodsList(params) this.list = res.data } finally { this.loading = false } } } })然后在组件中使用:
<script setup> import { useGoodsStore } from '@/stores/goods' const store = useGoodsStore() onMounted(() => { store.fetchGoodsList({ page: 1, size: 10 }) }) </script> <template> <div v-if="store.loading">加载中...</div> <ul v-else> <li v-for="item in store.list" :key="item.id"> {{ item.name }} - ¥{{ item.price }} </li> </ul> </template>2.2 购物车功能实现
购物车功能需要考虑几个技术难点:
- 本地存储:使用pinia-plugin-persistedstate持久化购物车数据
- 复杂计算:利用computed计算总价和选中状态
- 交互优化:防抖处理频繁的数量修改
购物车store示例:
export const useCartStore = defineStore('cart', { state: () => ({ items: [] as CartItem[], }), persist: true, getters: { totalPrice(state) { return state.items.reduce((sum, item) => { return sum + (item.selected ? item.price * item.quantity : 0) }, 0) } }, actions: { addItem(item: GoodsItem) { const exist = this.items.find(i => i.id === item.id) if (exist) { exist.quantity++ } else { this.items.push({ ...item, quantity: 1, selected: true }) } } } })3. 支付流程开发
支付流程是电商项目的关键环节,需要特别注意安全性和用户体验:
- 订单创建:收集用户选择的商品和收货信息
- 支付对接:调用支付接口获取支付凭证
- 结果回调:处理支付成功/失败的不同状态
支付组件核心逻辑:
<script setup> const route = useRoute() const router = useRouter() const handlePayment = async () => { try { const { paymentUrl } = await api.createOrder({ goods: cartStore.selectedItems, address: selectedAddress.value }) window.location.href = paymentUrl } catch (error) { ElMessage.error('创建订单失败') } } </script>4. 性能优化实践
4.1 图片懒加载
对于电商项目,图片资源往往占据很大流量。我们可以使用VueUse的useIntersectionObserver实现懒加载:
// directives/lazyLoad.ts import { useIntersectionObserver } from '@vueuse/core' export default { mounted(el: HTMLImageElement, binding) { useIntersectionObserver(el, ([{ isIntersecting }]) => { if (isIntersecting) { el.src = binding.value } }) } }4.2 组件按需加载
路由层面使用动态导入实现组件懒加载:
const routes = [ { path: '/product/:id', component: () => import('@/views/ProductDetail.vue') } ]4.3 API请求优化
对于频繁触发的请求(如搜索建议),可以使用防抖技术减少请求次数:
import { debounce } from 'lodash-es' const search = debounce(async (keyword: string) => { const res = await api.searchGoods({ keyword }) searchResults.value = res.data }, 300)5. 项目部署与上线
完成开发后,我们需要将项目构建并部署到生产环境:
- 构建生产版本:
npm run build- 配置Nginx:
server { listen 80; server_name xiaotuxian.com; location / { root /var/www/xiaotuxian/dist; try_files $uri $uri/ /index.html; } location /api { proxy_pass http://backend; } }- 启用Gzip压缩: 在vite.config.ts中配置:
import viteCompression from 'vite-plugin-compression' export default defineConfig({ plugins: [ viteCompression({ algorithm: 'gzip' }) ] })6. 常见问题解决方案
在实际开发中,我遇到过几个典型问题:
Pinia数据不持久化: 确保安装了pinia-plugin-persistedstate并在store中设置了persist: true
路由切换白屏: 检查动态导入的组件路径是否正确,建议使用@/绝对路径
Element Plus样式丢失: 需要在vite.config.ts中正确配置自动导入:
Components({ resolvers: [ ElementPlusResolver({ importStyle: 'sass' }) ] })- 移动端适配问题: 推荐使用postcss-pxtorem插件自动转换px为rem:
// postcss.config.js module.exports = { plugins: { 'postcss-pxtorem': { rootValue: 37.5, propList: ['*'] } } }通过这个完整的电商项目实战,我们系统性地应用了Vue 3的各项核心技术。从项目初始化到最终部署,每个环节都有其技术要点和最佳实践。在实际开发中,建议多使用Composition API组织代码逻辑,保持组件的高内聚低耦合。对于复杂状态管理,合理使用Pinia的getters和actions可以大大提高代码可维护性。
