【Vue项目】尚品汇(五)Detail组件开发 实现轮播图和放大镜效果

2023-06-13,,

1 基本准备工作

1.1 组件路由及数据准备

编写请求接口

api/index.js

export const reqGetDetailInfo = (skuId ={}) => {
return requests(({
url:`/item/${skuId}`,
method: 'get'
}))
}

编写组件路由

    {
path: '/detail/:skuId',
component: Detail,
name: 'detail',
meta: {
showFooter: true
}
}

这里为了实现路由跳转滚动条置顶效果以及简化代码文件结构,将路由信息写入routes其他信息仍在index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import routes from "@/router/routes"; Vue.use(VueRouter) export default new VueRouter({
routes,
scrollBehavior(to, from, savePosition) {
return {y : 0}
}
})
// 保存原型push方法
let orignPush = VueRouter.prototype.push;
let orignReplace = VueRouter.prototype.replace; // 修改VueRouter的push
// 第一个参数告诉原来的push方法往哪里跳(传递了那些参数)
// resolve reject参数传递了成功失败参数
VueRouter.prototype.push = function(location, resolve, reject){
if(resolve && reject) {
orignPush.call(this, location, resolve, reject)
}
else {
// this为VueRouter,call将上下文修改为了Vuerouter
orignPush.call(this, location, ()=>{}, ()=>{})
}
} VueRouter.prototype.replace = function(location, resolve, reject){
if(resolve && reject) {
orignReplace.call(this, location, resolve, reject)
}
else {
orignReplace.call(this, location, ()=>{}, ()=>{})
}
}

vuex

编写vuex三大件,/store/detail/index.js

import {reqGetDetailInfo} from "@/api";

const actions = {
async getDetailInfo(context, skuId) {
let result = await reqGetDetailInfo(skuId);
if(result.code === 200) {
context.commit('GETDETAILINFO', result.data);
}
}
}
const state = {
detailInfo: {}
}
const mutations = {
GETDETAILINFO(state, detailInfo) {
state.detailInfo = detailInfo
}
}
const getters = { } export default {
actions,
state,
mutations,
getters
}

在总仓库中引入,/store/index.js

import vue from 'vue'
import vuex from 'vuex'
import home from './home'
import search from './search'
import detail from "./detail"; vue.use(vuex) export default new vuex.Store({
modules: {
home, search, detail
}
})

在Search组件实现路由跳转

/pages/Search/index.vue

    goDetail(skuId) {
this.$router.push({name: 'detail', params: {skuId: skuId}})
},

1.2 使用getters简化数据

/store/detail/index.js

const getters = {
categoryView(state) {
return state.detailInfo.categoryView || {}
},
skuInfo(state) {
return state.detailInfo.skuInfo || {}
}
}

在组件中使用mapGetter生成计算属性

  computed: {
...mapGetters(['categoryView', 'skuInfo'])
},

1.3 产品售卖属性的排他操作

效果为点击一个售卖属性会变为高亮,其他高亮取消的效果。

            <div class="chooseArea">
<div class="choosed"></div>
<dl v-for="(spuSaleAttr, index1) in spuSaleAttrList" :key="spuSaleAttr.id">
<dt class="title">{{ spuSaleAttr.saleAttrName }}</dt>
<dd changepirce="0" :class="{active : spuSaleAttrValue.isChecked == '1'}"
@click="isCheckedHandle(spuSaleAttrValue.saleAttrValueName, spuSaleAttr.spuSaleAttrValueList)"
v-for="(spuSaleAttrValue, index2) in spuSaleAttr.spuSaleAttrValueList" :key="spuSaleAttrValue.id">
{{ spuSaleAttrValue.saleAttrValueName }}
</dd>
<!-- <dd changepirce="0" class="active">金色</dd>-->
<!-- <dd changepirce="40">银色</dd>-->
<!-- <dd changepirce="90">黑色</dd>-->
</dl>
</div>

这里我直接拿的名字和数组进行map修改,和老师直接传入要修改的元素不同,感觉他的更好一点。

    isCheckedHandle(saleAttrValueName, attr) {
attr.map(item => {
if(item.saleAttrValueName === saleAttrValueName) {
item.isChecked = '1'
} else {
item.isChecked = '0'
}
return item
})
}

2 轮播图

目的是轮播显示ImageList组件的skuImageList的图片,因此通过ImageList监视数据创建轮播图实现实时更新。

<div class="swiper-container">
<div class="swiper-wrapper">
<div class="swiper-slide" v-for="(banner, index) in skuImageList" :key="banner.id">
<img :src="banner.imgUrl"/>
</div>
</div>
<!-- 如果需要导航按钮 -->
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
</div>
watch: {
// 监听得到数据时,保证轮播图for循环结构完整
skuImageList(newValue, oldValue) {
this.$nextTick(() => {
new Swiper('.swiper-container', {
slidesPerView: 7,
slidesPerGroup: 1,
// 如果需要前进后退按钮
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
}, })
})
}
}

使用nextTick的原因是服务器返回数据的时候可能浏览器的for循环还没有渲染完,因此需要nextTick等下次页面结构完整才能完成轮播图的渲染。

slidesPerView表示一页的图片量

slidesPerGroup表示一次滑动需要滑动几个图片

2.1 实现点击ImageList组件图片更改Zoom组件图片

分析:两个组件属于兄弟关系,因此使用全局事件总线进行通信

首先在ImageList组件创建图片点击函数以及时间总线触发

  methods: {
changeCurIndex(index) {
this.curIndex = index
this.$bus.$emit('changeImg', index)
}
}

在Zoom组件创建事件总线响应

<script>
export default {
name: "Zoom",
props: ['skuImageList'],
data() {
return {
curIndex: 0
}
},
computed: {
imgObj() {
return this.skuImageList[this.curIndex] || {}
},
},
mounted() {
this.$bus.$on('changeImg', (index) => {
this.curIndex = index
})
}
}
</script>

3 放大镜

<template>
<div class="spec-preview">
<img :src="imgObj.imgUrl" />
<div class="event" @mousemove="handle()"></div>
<div class="big">
<img :src="imgObj.imgUrl" ref="big" />
</div>
<div class="mask" ref="mask"></div>
</div>
</template>
<script>
export default {
name: "Zoom",
props: ['skuImageList'],
data() {
return {
curIndex: 0
}
},
computed: {
imgObj() {
return this.skuImageList[this.curIndex] || {}
},
},
mounted() {
this.$bus.$on('changeImg', (index) => {
this.curIndex = index
})
},
methods: {
handle() {
// console.log(event)
let mask = this.$refs.mask
let big = this.$refs.big let left = event.offsetX - mask.offsetWidth / 2
let top = event.offsetY - mask.offsetHeight / 2 if(left < 0) left = 0
if(top < 0) top = 0
if(left > mask.offsetWidth) left = mask.offsetWidth
if(top > mask.offsetHeight) top = mask.offsetHeight mask.style.left = left + 'px'
mask.style.top = top + 'px' big.style.left = -2 * left + 'px'
big.style.top = -2 * top + 'px' }
}
}
</script>

【Vue项目】尚品汇(五)Detail组件开发 实现轮播图和放大镜效果的相关教程结束。

《【Vue项目】尚品汇(五)Detail组件开发 实现轮播图和放大镜效果.doc》

下载本文的Word格式文档,以方便收藏与打印。