ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-09-03 18:02:11  阅读:210  来源: 互联网

标签:index Vue return 轮播 top mask Detail VueRouter import


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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有