商城网页
1.首页 - 静态结构准备 & 动态渲染
2.搜索 - 历史记录管理
需求:
a. 搜索历史基本渲染
b. 点击搜索 (添加历史)
点击 搜索按钮 或 底下历史记录,都能进行搜索
① 若之前 没有 相同搜索关键字,则直接追加到最前面
② 若之前 已有 相同搜索关键字,将该原有关键字移除,再追加
c. 清空历史:添加清空图标,可以清空历史记录
d. 持久化:搜索历史需要持久化,刷新历史不丢失
3.搜索列表 - 静态布局 & 动态渲染
import request from '@/utils/request'
// 获取搜索商品列表的数据
export const getProList = (obj) => {
const { categoryId, goodsName, page } = obj
return request.get('/goods/list', {
params: {
categoryId,
goodsName,
page
}
})
}
// 获取商品详情数据
export const getProDetail = (goodsId) => {
return request.get('/goods/detail', {
params: {
goodsId
}
})
}
// 获取商品评价
export const getProComments = (goodsId, limit) => {
return request.get('/comment/listRows', {
params: {
goodsId,
limit
}
})
}
4.商品详情- 静态布局 & 渲染
5.加入购物车 - 唤起弹层
<!-- 加入购物车/立即购买 公用的弹层 -->
<van-action-sheet v-model="showPannel" :title="mode === 'cart' ? '加入购物车' : '立刻购买'">
<div class="product">
<div class="product-title">
<div class="left">
<img :src="detail.goods_image" alt="">
</div>
<div class="right">
<div class="price">
<span>¥</span>
<span class="nowprice">{{ detail.goods_price_min }}</span>
</div>
<div class="count">
<span>库存</span>
<span>{{ detail.stock_total }}</span>
</div>
</div>
</div>
<div class="num-box">
<span>数量</span>
<!-- v-model 本质上 :value 和 @input 的简写 -->
<CountBox v-model="addCount"></CountBox>
</div>
<!-- 有库存才显示提交按钮 -->
<div class="showbtn" v-if="detail.stock_total > 0">
<div class="btn" v-if="mode === 'cart'" @click="addCart">加入购物车</div>
<div class="btn now" v-else @click="goBuyNow">立刻购买</div>
</div>
<div class="btn-none" v-else>该商品已抢完</div>
</div>
</van-action-sheet>
</div>
</template>
6.加入购物车 - 封装数字框组件
getters: {
// 求所有的商品累加总数
cartTotal (state) {
return state.cartList.reduce((sum, item) => sum + item.goods_num, 0)
},
// 选中的商品项
selCartList (state) {
return state.cartList.filter(item => item.isChecked)
},
// 选中的总数
selCount (state, getters) {
return getters.selCartList.reduce((sum, item) => sum + item.goods_num, 0)
},
// 选中的总价
selPrice (state, getters) {
return getters.selCartList.reduce((sum, item) => {
return sum + item.goods_num * item.goods.goods_price_min
}, 0).toFixed(2)
},
// 是否全选
isAllChecked (state) {
return state.cartList.every(item => item.isChecked)
}
}
7.加入购物车 - 判断 token 添加登录提示
8. 购物车模块
需求分析:
1. 基本静态结构 (快速实现)
2. 构建 vuex cart 模块,获取数据存储
3. 基于 数据 动态渲染 购物车列表
4. 封装 getters 实现动态统计
5. 全选反选功能
6. 数字框修改数量功能
7. 编辑切换状态,删除功能
8. 空购物车处理
模板
9.订单结算台 - 购物车结算
核心步骤:
1. 跳转传递查询参数 mode="cart" 和 cartIds
2. 页面中 $route.query 接收参数
3. 调用接口,获取数据
4. 基于数据渲染
methods: {
toggleCheck (goodsId) {
this.$store.commit('cart/toggleCheck', goodsId)
},
toggleAllCheck () {
this.$store.commit('cart/toggleAllCheck', !this.isAllChecked)
},
changeCount (goodsNum, goodsId, goodsSkuId) {
// console.log(goodsNum, goodsId, goodsSkuId)
// 调用 vuex 的 action,进行数量的修改
this.$store.dispatch('cart/changeCountAction', {
goodsNum,
goodsId,
goodsSkuId
})
},
async handleDel () {
if (this.selCount === 0) return
await this.$store.dispatch('cart/delSelect')
this.isEdit = false
},
goPay () {
// 判断有没有选中商品
if (this.selCount > 0) {
// 有选中的 商品 才进行结算跳转
this.$router.push({
path: '/pay',
query: {
mode: 'cart',
cartIds: this.selCartList.map(item => item.id).join(',') // 'cartId,cartId,cartId'
}
})
}
}
},
10.提交订单并支付
核心步骤:
1. 封装通用请求方法
2. 买家留言绑定
3. 注册事件,调用方法提交订单并支付
export default {
name: 'PayIndex',
mixins: [loginConfirm],
data () {
return {
addressList: [],
order: {},
personal: {},
remark: '' // 备注留言
}
},
computed: {
selectedAddress () {
// 这里地址管理非主线业务,直接获取第一个项作为选中的地址
return this.addressList[0] || {}
},
longAddress () {
const region = this.selectedAddress.region
return region.province + region.city + region.region + this.selectedAddress.detail
},
mode () {
return this.$route.query.mode
},
cartIds () {
return this.$route.query.cartIds
},
goodsId () {
return this.$route.query.goodsId
},
goodsSkuId () {
return this.$route.query.goodsSkuId
},
goodsNum () {
return this.$route.query.goodsNum
}
},
created () {
this.getAddressList()
this.getOrderList()
},
methods: {
async submitOrder () {
if (this.mode === 'cart') {
await submitOrder(this.mode, {
cartIds: this.cartIds,
remark: this.remark
})
}
if (this.mode === 'buyNow') {
await submitOrder(this.mode, {
goodsId: this.goodsId,
goodsSkuId: this.goodsSkuId,
goodsNum: this.goodsNum,
remark: this.remark
})
}
this.$toast.success('支付成功')
this.$router.replace('/myorder')
},
async getAddressList () {
const { data: { list } } = await getAddressList()
this.addressList = list
},
async getOrderList () {
// 购物车结算
if (this.mode === 'cart') {
const { data: { order, personal } } = await checkOrder(this.mode, {
cartIds: this.cartIds
})
this.order = order
this.personal = personal
}
// 立刻购买结算
if (this.mode === 'buyNow') {
const { data: { order, personal } } = await checkOrder(this.mode, {
goodsId: this.goodsId,
goodsSkuId: this.goodsSkuId,
goodsNum: this.goodsNum
})
this.order = order
this.personal = personal
}
}
}
}