开发在线商店:基于Vue2+ElementUI的电商平台前端实践

发布于:2025-07-10 ⋅ 阅读:(21) ⋅ 点赞:(0)

Hi,我是布兰妮甜 !在当今数字化时代,电子商务已成为商业领域的重要组成部分。开发一个功能完善、用户友好的在线商店应用对于企业拓展市场至关重要。本文将详细介绍如何使用Vue2框架配合ElementUI组件库开发一个完整的在线商店应用。



一、项目初始化与配置

1.1 创建Vue2项目

首先,我们需要使用Vue CLI创建一个新的Vue2项目:

vue create online-store
cd online-store

1.2 安装ElementUI

在项目目录中安装ElementUI:

npm install element-ui -S

然后在main.js中引入ElementUI:

import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

Vue.use(ElementUI)

1.3 项目结构规划

src/
├── api/            # API请求封装
├── assets/         # 静态资源
├── components/     # 公共组件
├── router/         # 路由配置
├── store/          # Vuex状态管理
├── utils/          # 工具函数
├── views/          # 页面组件
├── App.vue         # 根组件
└── main.js         # 入口文件

二、核心功能模块开发

2.1 用户认证模块

登录/注册组件

<template>
  <div class="login-container">
    <el-form :model="loginForm" :rules="loginRules" ref="loginForm">
      <el-form-item prop="username">
        <el-input v-model="loginForm.username" placeholder="用户名"></el-input>
      </el-form-item>
      <el-form-item prop="password">
        <el-input type="password" v-model="loginForm.password" placeholder="密码"></el-input>
      </el-form-item>
      <el-button type="primary" @click="handleLogin">登录</el-button>
      <el-button @click="showRegisterDialog = true">注册</el-button>
    </el-form>

    <el-dialog title="注册" :visible.sync="showRegisterDialog">
      <!-- 注册表单内容 -->
    </el-dialog>
  </div>
</template>

<script>
export default {
  data() {
    return {
      loginForm: {
        username: '',
        password: ''
      },
      loginRules: {
        username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
        password: [{ required: true, message: '请输入密码', trigger: 'blur' }]
      },
      showRegisterDialog: false
    }
  },
  methods: {
    handleLogin() {
      this.$refs.loginForm.validate(valid => {
        if (valid) {
          // 调用登录API
          this.$store.dispatch('user/login', this.loginForm)
            .then(() => {
              this.$router.push('/')
              this.$message.success('登录成功')
            })
        }
      })
    }
  }
}
</script>

2.2 商品展示模块

商品列表组件

<template>
  <div class="product-list">
    <el-row :gutter="20">
      <el-col :span="6" v-for="product in products" :key="product.id">
        <el-card :body-style="{ padding: '0px' }" shadow="hover">
          <img :src="product.image" class="product-image">
          <div style="padding: 14px;">
            <h3>{{ product.name }}</h3>
            <div class="price">¥{{ product.price }}</div>
            <div class="bottom">
              <el-button type="text" @click="showDetail(product)">查看详情</el-button>
              <el-button type="primary" size="small" @click="addToCart(product)">加入购物车</el-button>
            </div>
          </div>
        </el-card>
      </el-col>
    </el-row>
    
    <el-pagination
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      :current-page="pagination.current"
      :page-sizes="[12, 24, 36, 48]"
      :page-size="pagination.size"
      layout="total, sizes, prev, pager, next, jumper"
      :total="pagination.total">
    </el-pagination>
  </div>
</template>

<script>
export default {
  data() {
    return {
      products: [],
      pagination: {
        current: 1,
        size: 12,
        total: 0
      }
    }
  },
  created() {
    this.fetchProducts()
  },
  methods: {
    fetchProducts() {
      // 调用API获取商品列表
      const { current, size } = this.pagination
      getProducts({ page: current, pageSize: size }).then(res => {
        this.products = res.data.items
        this.pagination.total = res.data.total
      })
    },
    handleSizeChange(val) {
      this.pagination.size = val
      this.fetchProducts()
    },
    handleCurrentChange(val) {
      this.pagination.current = val
      this.fetchProducts()
    },
    addToCart(product) {
      this.$store.dispatch('cart/addToCart', product)
      this.$message.success('已加入购物车')
    },
    showDetail(product) {
      this.$router.push(`/product/${product.id}`)
    }
  }
}
</script>

2.3 购物车模块

购物车组件

<template>
  <div class="cart-container">
    <el-table :data="cartItems" style="width: 100%">
      <el-table-column prop="name" label="商品名称"></el-table-column>
      <el-table-column prop="price" label="单价" width="120"></el-table-column>
      <el-table-column label="数量" width="180">
        <template slot-scope="scope">
          <el-input-number 
            v-model="scope.row.quantity" 
            :min="1" 
            @change="updateQuantity(scope.row)">
          </el-input-number>
        </template>
      </el-table-column>
      <el-table-column label="小计" width="120">
        <template slot-scope="scope">
          ¥{{ (scope.row.price * scope.row.quantity).toFixed(2) }}
        </template>
      </el-table-column>
      <el-table-column label="操作" width="120">
        <template slot-scope="scope">
          <el-button type="danger" icon="el-icon-delete" circle 
            @click="removeItem(scope.row.id)">
          </el-button>
        </template>
      </el-table-column>
    </el-table>

    <div class="total-section">
      <span class="total-amount">总计: ¥{{ totalAmount.toFixed(2) }}</span>
      <el-button type="primary" @click="checkout">结算</el-button>
    </div>
  </div>
</template>

<script>
export default {
  computed: {
    cartItems() {
      return this.$store.state.cart.items
    },
    totalAmount() {
      return this.cartItems.reduce((total, item) => {
        return total + (item.price * item.quantity)
      }, 0)
    }
  },
  methods: {
    updateQuantity(item) {
      this.$store.dispatch('cart/updateQuantity', {
        id: item.id,
        quantity: item.quantity
      })
    },
    removeItem(id) {
      this.$store.dispatch('cart/removeItem', id)
    },
    checkout() {
      if (this.cartItems.length === 0) {
        this.$message.warning('购物车为空')
        return
      }
      this.$router.push('/checkout')
    }
  }
}
</script>

三、状态管理(Vuex)

3.1 购物车状态管理

// store/modules/cart.js
const state = {
  items: []
}

const mutations = {
  ADD_ITEM(state, product) {
    const existingItem = state.items.find(item => item.id === product.id)
    if (existingItem) {
      existingItem.quantity++
    } else {
      state.items.push({
        ...product,
        quantity: 1
      })
    }
  },
  UPDATE_QUANTITY(state, { id, quantity }) {
    const item = state.items.find(item => item.id === id)
    if (item) {
      item.quantity = quantity
    }
  },
  REMOVE_ITEM(state, id) {
    state.items = state.items.filter(item => item.id !== id)
  },
  CLEAR_CART(state) {
    state.items = []
  }
}

const actions = {
  addToCart({ commit }, product) {
    commit('ADD_ITEM', product)
  },
  updateQuantity({ commit }, payload) {
    commit('UPDATE_QUANTITY', payload)
  },
  removeItem({ commit }, id) {
    commit('REMOVE_ITEM', id)
  },
  clearCart({ commit }) {
    commit('CLEAR_CART')
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

四、路由配置

// router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import Home from '../views/Home.vue'
import ProductList from '../views/ProductList.vue'
import ProductDetail from '../views/ProductDetail.vue'
import Cart from '../views/Cart.vue'
import Checkout from '../views/Checkout.vue'
import Login from '../views/Login.vue'

Vue.use(Router)

const router = new Router({
  mode: 'history',
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/products',
      name: 'products',
      component: ProductList
    },
    {
      path: '/product/:id',
      name: 'product-detail',
      component: ProductDetail,
      props: true
    },
    {
      path: '/cart',
      name: 'cart',
      component: Cart,
      meta: { requiresAuth: true }
    },
    {
      path: '/checkout',
      name: 'checkout',
      component: Checkout,
      meta: { requiresAuth: true }
    },
    {
      path: '/login',
      name: 'login',
      component: Login
    }
  ]
})

// 路由守卫
router.beforeEach((to, from, next) => {
  const isAuthenticated = store.getters['user/isAuthenticated']
  
  if (to.matched.some(record => record.meta.requiresAuth) {
    if (!isAuthenticated) {
      next({ name: 'login', query: { redirect: to.fullPath } })
    } else {
      next()
    }
  } else {
    next()
  }
})

export default router

五、API封装与Axios配置

// utils/request.js
import axios from 'axios'
import { Message } from 'element-ui'

const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API,
  timeout: 5000
})

// 请求拦截器
service.interceptors.request.use(
  config => {
    const token = localStorage.getItem('token')
    if (token) {
      config.headers['Authorization'] = `Bearer ${token}`
    }
    return config
  },
  error => {
    return Promise.reject(error)
  }
)

// 响应拦截器
service.interceptors.response.use(
  response => {
    const res = response.data
    
    if (res.code !== 200) {
      Message({
        message: res.message || 'Error',
        type: 'error',
        duration: 5 * 1000
      })
      
      return Promise.reject(new Error(res.message || 'Error'))
    } else {
      return res
    }
  },
  error => {
    Message({
      message: error.message,
      type: 'error',
      duration: 5 * 1000
    })
    return Promise.reject(error)
  }
)

export default service

六、优化与部署

6.1 性能优化

  1. 组件懒加载
    const ProductList = () => import('../views/ProductList.vue')
    
  2. 路由懒加载
    {
    path: '/products',
    component: () => import('../views/ProductList.vue')
    }
    
  3. CDN引入
    // vue.config.js
    module.exports = {
      configureWebpack: {
        externals: {
          'vue': 'Vue',
      	  'element-ui': 'ELEMENT'
        }
      }
    }
    

6.2 部署配置

// vue.config.js
module.exports = {
  publicPath: process.env.NODE_ENV === 'production' ? '/online-store/' : '/',
  outputDir: 'dist',
  assetsDir: 'static',
  productionSourceMap: false,
  devServer: {
    proxy: {
      '/api': {
        target: 'http://your-api-server.com',
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
      }
    }
  }
}

七、总结

本文详细介绍了如何使用Vue2和ElementUI开发一个功能完整的在线商店应用。我们从项目初始化开始,逐步实现了用户认证、商品展示、购物车管理等核心功能模块,并介绍了状态管理、路由配置、API封装等关键技术点。

通过ElementUI丰富的组件库,我们能够快速构建出美观、响应式的用户界面,而Vue2的响应式特性和组件化开发模式则大大提高了开发效率和代码可维护性。

希望本文能为开发者提供一个全面的参考,帮助您快速构建自己的在线商店应用。


网站公告

今日签到

点亮在社区的每一天
去签到