其他分享
首页 > 其他分享> > 【Vue项目】尚品汇(五)Detail组件开发 实现轮播图和放大镜效果

【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三大件,/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
    }
})

/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