一,在detail组件中,向子组件zoom和 imglist传递数据,属性传递,
1.父组件detail
computed: {
...mapGetters(["categoryView", "skuInfo", "spuSaleAttrList",'imgList'])
},
向子组件传递数据
<div class="previewWrap"> <!--放大镜效果--> <Zoom :imgList="skuInfo.skuImageList" /> <!-- 小图列表 --> <ImageList :imgList="skuInfo.skuImageList" /> </div>
子组件接收
props:['imgList'],
<div class="swiper-container"> <div class="swiper-wrapper"> <div class="swiper-slide" v-for="(img, index) in imgList" :key="img.id"> <img :src="img.imgUrl"> </div> </div> <div class="swiper-button-next"></div> <div class="swiper-button-prev"></div> </div>
3.zoom子组件填充数据,默认呈现第一张图,data中初始化一个index
data(){
return {
defaultIndex : 0
}
大图填充数据
<div class="spec-preview"> <img :src="imgList[defaultIndex].imgUrl" /> <div class="event"></div> <div class="big"> <img :src="imgList[defaultIndex].imgUrl" /> </div> <div class="mask"></div> </div>
注;此时控制台会报错, a.b.c假报错问题,
解决方式,此时需要判断imglist
computed:{
//计算它的可能值,不然出现a.b.c
defaultImg(){
if(this.imgList){
return this.imgList[this.defaultIndex]
}else{
return {}
}
}
}
再次填充数据
<div class="spec-preview"> <img :src="defaultImg.imgUrl" /> <div class="event" @mousemove="move"></div> <div class="big"> <img :src="defaultImg.imgUrl" ref="bigImg"/> </div> <div class="mask" ref="mask"></div> </div>
二,小图列表点击,切换类
1.在imageslist组件中定义初始索引,当点击轮播图的图片时,index赋值给currentIndex,类名也跟着动态展示,此时将轮播图的index传递给大图组件,轮播图展示哪张图,大图也跟着
展示哪张图
data() {
return {
currentIndex: 0
};
},
类名
.active {
border: 2px solid #f60;
padding: 1px;
}
2.点击小图,切换类
<div class="swiper-slide" v-for="(img, index) in imgList" :key="img.id"> <img :src="img.imgUrl" @click="changeIndex(index)" :class="{active:currentIndex === index}" /> </div>
回调函数,跟新索引,
methods: {
changeIndex(index) {
this.currentIndex = index;
三,点击小图,切换一样的中图
1.在imagelist中点击小图,回调中传递index,用全局事件总线传递index,传递给兄弟组件zoom
<div class="swiper-slide" v-for="(img, index) in imgList" :key="img.id"> <img :src="img.imgUrl" @click="changeIndex(index)" :class="{active:currentIndex === index}" /> </div>
点击事件回调函数,搞事件总线,$emitc触发,传递index给zoom大图组件
methods: {
changeIndex(index) {
this.currentIndex = index;
this.$bus.$emit("changeDefaultIndex", index);
}
},
在zoom组件中,监听
mounted(){
this.$bus.$on('changeDefaultIndex',this.changeDefaultIndex)
},
回调函数,跟新当前索引
methods:{
changeDefaultIndex(index){
this.defaultIndex = index
},
四,小图片的轮播图处理
1.html模板
<div class="swiper-container" ref="imglist"> <div class="swiper-wrapper"> <div class="swiper-slide" v-for="(img, index) in imgList" :key="img.id"> <img :src="img.imgUrl" @click="changeIndex(index)" :class="{active:currentIndex === index}" /> </div> </div> <div class="swiper-button-next"></div> <div class="swiper-button-prev"></div> </div>
2.引入swiper
import Swiper from "swiper";
import "swiper/css/swiper.min.css";
3. 在实例化swiper
watch: {
imgList: {
handler() {
//Vue.nextTick或者vm.$nextTick是一样的功能
//在最近的一次dom更新之后执行nextTick里面传的回调函数
this.$nextTick(() => {
new Swiper(this.$refs.imglist, {
// direction: "vertical", // 垂直切换选项
// autoplay:true,//等同于以下设置
// loop: true, // 循环模式选项
// // 如果需要分页器
// pagination: {
// el: ".swiper-pagination"
// },
// 如果需要前进后退按钮
navigation: {
nextEl: ".swiper-button-next",
prevEl: ".swiper-button-prev"
},
slidesPerGroup:5, //点击一下滑动一组有多少张
slidesPerView:5 //一屏显示多少张
// 如果需要滚动条
// scrollbar: {
// el: ".swiper-scrollbar"
// }
});
});
},
immediate: true //立即执行,在最近dom更新之前就会执行
}
}
五,放大镜逻辑
1.在图片中添加移动事件,获取鼠标的坐标,并且确定遮罩mask需要移动的距离,以及对应的大图移动的距离
在zoom组件中, html中
<template> <div class="spec-preview"> <img :src="defaultImg.imgUrl" /> <div class="event" @mousemove="move"></div> <div class="big"> <img :src="defaultImg.imgUrl" ref="bigImg"/> </div> <div class="mask" ref="mask"></div> </div> </template>
js代码
// 图片移动事件 move(event){ let target = event.target //拿的是事件源元素 let mouseX = event.offsetX //鼠标相对事件源本身的x位置 let mouseY = event.offsetY //鼠标相对事件源本身的y位置 let mask = this.$refs.mask let bigImg = this.$refs.bigImg //求mask 要走的位置 let maskX = mouseX - mask.offsetWidth / 2 let maskY = mouseY - mask.offsetHeight / 2 if(maskX < 0){ maskX = 0 }else if(maskX > target.clientWidth - mask.offsetWidth){ maskX = target.clientWidth - mask.offsetWidth } if(maskY < 0){ maskY = 0 }else if(maskY> target.clientHeight- mask.offsetHeight){ maskY = target.clientHeight - mask.offsetHeight } //设置mask的位置 mask.style.left = maskX + 'px' mask.style.top = maskY + 'px' //设置大图的移动位置,mask移动相反的两倍 bigImg.style.left = -2 *maskX + 'px' bigImg.style.top = -2 *maskY + 'px' }
六, 对产品的属性的方框进行选中处理
1. isChecked属性为选中的标识,‘1’为选中, ‘0’为不选中
在detail组件中
html代码
<dl v-for="(item, index) in spuSaleAttrList" :key="index"> <dt class="title">{{item.saleAttrName}}</dt> <dd changepirce="0" :class="{active:attrValue.isChecked === '1'}" v-for="(attrValue, index) in item.spuSaleAttrValueList" :key="attrValue.id" @click="changeIsCheck(item.spuSaleAttrValueList,index)" >{{attrValue.saleAttrValueName}}</dd> </dl>
2.对选中的方框排他处理
js代码
changeIsCheck(attrValueList,index){
//排它
attrValueList.forEach(item => {
item.isChecked = '0'
})
attrValueList[index].isChecked = '1'
},
七, 修改购买的数量的v-model的应用,收集数量,点击加号,减号,增减数量
<div class="controls"> <input autocomplete="off" class="itxt" v-model="skuNum"/> <a href="javascript:" class="plus" @click="skuNum++">+</a> <a href="javascript:" class="mins" @click="skuNum <= 1 ? 1 : skuNum-- ">-</a> </div>
八, 点击添加购物车时发送请求,是否添加成功
1.封装请求添加购物车的请求
//请求添加购物车 /api/cart/addToCart/{ skuId }/{ skuNum } post
export const reqAddOrUpdateShopCart = (skuId,skuNum) => Ajax.post(`/cart/addToCart/${ skuId }/${ skuNum }`)
2.配置shopcart.js的vuex
import {reqAddOrUpdateShopCart} from '@/api'
const state = {
}
const mutations = {
}
const actions = {
async addorUpdateShopCart({commit},{skuId,skuNum}){
const result = await reqAddOrUpdateShopCart(skuId,skuNum)
if(result.code === 200){
return '添加购物车成功'
}else{
// return '添加购物车失败' 返回的还是成功的promise
//返回的是失败的promise
return Promise.reject(new Error('添加购物车失败'))
}
}
}
const getters = {
}
export default {
state,
mutations,
actions,
getters
}
3.在总vuex中注册
<div class="add"> <a href="javascript:" @click="toSuccess">加入购物车</a> </div>
5, js代码,添加商品请求成功后,需要把商品存储在本地浏览器sessionStorage, 商品的数量用路由传参,然后路由组件
跳转到产品添加成功页面
async toSuccess(){
//先发请求,判定是否成功
//调用我们actions内部的异步函数(async),这个调用的返回值一定是一个promise
try {
const result = await this.$store.dispatch('addorUpdateShopCart',{skuId:this.skuInfo.id,skuNum:this.skuNum})
alert(result)
//在添加成功跳转到添加成功页面之前,把相应的商品存储在sessionStorage当中,用来在添加成功页面去使用
//本地存储传参
sessionStorage.setItem('SKUINFO_KEY',JSON.stringify(this.skuInfo))
this.$router.push(`/addcartsuccess?skuNum=${this.skuNum}`) //如果添加购物车成功,那么就跳转到添加购物车成功的页面
//路径传参给路由组件
// this.$router.push({name:'addcartsuccess', query:{skuNum:this.skuNum,skuInfo:this.skuInfo }})
} catch (error) {
alert(error.message)
}
//成功
//失败
}
6,跳转到商品添加成功页面AddCartSuccess,填充传递过来的数据
<div class="right-info"> <p class="title">{{skuInfo.skuName}}</p> <p class="attr">颜色:WFZ5099IH/5L钛金釜内胆 数量:{{$route.query.skuNum}}</p> </div>
data(){
return {
skuInfo: JSON.parse(sessionStorage.getItem('SKUINFO_KEY')) || {}
}
},
<router-link :to="`/detail/${skuInfo.id}`" class="sui-btn btn-xlarge">查看商品详情</router-link>