【Vue项目】尚品汇(五)Detail组件开发 实现轮播图和放大镜效果
作者:互联网
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>
标签:index,Vue,return,轮播,top,mask,Detail,VueRouter,import 来源: https://www.cnblogs.com/tod4/p/16653195.html