Vue前端项目实战--移动商城--首页开发

项目总博客见《Vue前端项目实战–移动商城–总结篇》https://blog.csdn.net/Jelly_11/article/details/113851138

这篇博客是记录项目中的首页开发过程。
附上效果图:

一、顶部导航栏navbar的封装

在components/common/navbar文件夹中新建NavBar.vue文件,设置三个插槽,用于用户设置导航栏左中右三块内容。首页中只需要用到中间这个插槽,在Home.vue中引用NavBar.vue。

详细代码:

  1. NavBar.vue
<template>
  <div class='nav-bar' :style='{backgroundColor: navColor}'>
    <div class='left'><slot name='left'></slot></div>
    <div class='center'><slot name='center'></slot></div>
    <div class='right'><slot name='right'></slot></div>
  </div>
</template>

<script>
export default {
   
  name: 'NavBar',
  props: {
   
    navColor: {
   
      type: String,
      default: 'var(--color-tint)'
    } 
  },
}
</script>

<style scoped>
  .nav-bar {
   
    display: flex;
    /*垂直居中*/
    height: 44px;
    line-height: 44px;
    /*水平居中*/
    text-align: center;    
  }
  .left, .right {
   
    width: 60px;
  }
  .center {
   
    flex: 1;
  }
</style>
  1. Home.vue
<template>
  <div id='home'>
    <!-- 顶部导航栏 -->
    <nav-bar navColor='var(--color-tint)' class='home-nav'>
      <div slot='center'>购物街</div>
    </nav-bar>
  </div>
</template>

<script>
import NavBar from "components/common/navbar/NavBar"

export default {
   
  name: 'Home',
  components: {
   
    NavBar
  }
}
</script>

<style scoped>
  .home-nav {
   
    color: #fff;
    position: fixed;
    /*否则center宽度不撑满整个屏幕*/
    left: 0;
    right: 0;
    top: 0;
  }
</style>

二、网络数据请求

使用axios进行网络数据请求,首先安装npm install axios --save
在network文件夹下建立request.js,封装网络请求函数,建立home.js用于存放首页中相关的网络请求函数,然后在Home.vue中引用home.js中函数,在home.js中引用request函数。
详细代码:

  1. request.js
import axios from 'axios'

export function request(config) {
   
  //1.创建axios实例
  const instance = axios.create({
   
    /* 接口地址请加coderwhy老师微信*/
    baseURL: 'http://152.136.185.210:7878/api/m5/',
    timeout: 5000
  })

  //2.axios拦截器
  //请求拦截
  instance.interceptors.request.use(config => {
   
    return config
  }, err => {
   
    console.log(err)
  })

  //相应拦截
  instance.interceptors.response.use(res => {
   
    return res.data
  }, err => {
   
    console.log(err)
  })

  //3.发送真正的网络请求
  return instance(config)
}
  1. home.js
/* 存放首页的相关网络请求函数*/
import {
   request} from './request'

export function getHomeMultidata() {
   
  return request({
   
    url: '/home/multidata'
  })
 export function getHomeGoods(type, page) {
   
  return request({
   
    url: '/home/data',
    params: {
   
      type,
      page
    }
  })
}
  1. Home.vue
/* 网络请求*/
import {
   getHomeMultidata} from "network/home"

export default {
   
  name: 'Home',
  components: {
   
    NavBar
  },
  data() {
   
    return {
   
      /*轮播图数据*/
      banners: [],
      /*推荐数据*/
      recommends: []
    }
  },
  /* 数据网络请求在实例创建完成后进行 */
  created() {
   
    //1.请求多个数据
    this.getHomeMultidata()
  },
  methods: {
   
    /* 网络请求相关函数 */
    getHomeMultidata() {
   
      /*这时引用的home.js中的函数 */
      getHomeMultidata().then(res => {
   
        /*轮播图数据*/
        this.banners = res.data.banner.list;
        /*推荐数据*/
        this.recommends = res.data.recommend.list;
      })

    }
  }
}
</script>

三、轮播图

挂载完成后开启定时,延迟500秒后执行:

  1. 操作Dom:在前后各添加一张slide;
  2. 开启轮播定时。

操作Dom:

  1. 获取要操作的元素(document.querySelectorgetElementsByClassName);
  2. 保存图片数/圆点个数;
  3. 如果图片数大于一个,则在前后分别添加一个slide [1,2,3,4]–[4’,1,2,3,4,1’](cloneNode(true)insertBeforeappendChild),offsetWidth返回元素的宽度,style返回样式;
  4. 让swiper元素, 显示第一个(目前是显示前面添加的最后一个元素),调用自定义setTransform函数,设置滚动到的位置。
handleDom() {
   
      // 1.获取要操作的元素
      //swiperEl:class为swiper的元素 有n个swiperItem class是swiper
      //slidesELs:class为slide的元素 轮播中图在的那个div swiperItem
      let swiperEl = document.querySelector('.swiper');
     // let slidesEls = document.getElementsByClassName('slide');
      let slidesEls = swiperEl.getElementsByClassName('slide');
      
      //2.保存图片数/圆点个数
      this.slideCount = slidesEls.length;

      //3.如果图片数大于一个 则在前后分别添加一个slide [1,2,3,4]--[4',1,2,3,4,1']
      if (this.slideCount > 1) {
   
        //cloneNode方法将复制并返回调用它的节点的副本。
        //如果传递参数是 true,将递归复制当前节点的所有子孙节点,否则只复制当前节点。
        let cloneFirst = slidesEls[0].cloneNode(true);
        let cloneLast = slidesEls[this.slideCount - 1].cloneNode(true);
        //insertBefore()在指定的已有子节点之前插入新的子节点
        //appendChild() 方法向节点添加最后一个子节点
        swiperEl.insertBefore(cloneLast, slidesEls[0]);
        swiperEl.appendChild(cloneFirst);
        //offsetWidth返回元素的宽度(包括元素宽度、内边距和边框,不包括外边距)
        this.totalWidth = swiperEl.offsetWidth;
        this.swiperStyle = swiperEl.style;
      }

       // 4.让swiper元素, 显示第一个(目前是显示前面添加的最后一个元素)
        this.setTransform(-this.totalWidth)
    },

setTransform函数(设置滚动到的位置):

setTransform(position) {
   
      //transform 属性向元素应用2D或3D转换,对元素进行旋转、缩放、移动或倾斜。
      // -webkit 是表示针对 safari 浏览器支持,-ms表示针对 IE 浏览器支持。
      this.swiperStyle.transform = `translateX(${
     position}px)`;
      this.swiperStyle['-webkit-transform'] = `translateX(${
     position}px)`;
      this.swiperStyle['-ms-transform'] = `translateX(${
     position}px)`;

    },

开启轮播定时:

  1. window.setInterval每3000ms调用一次:
    (1) 当前index数+1
    (2)自定义函数scrollContent(-this.currentIndex * this.totalWidth)滚动到正确的位置。
 startTimer() {
   
      // window.setInterval按照指定的周期(以毫秒计)来调用函数或计算表达式
      this.playTimer = window.setInterval(() => {
   
        this.currentIndex++;
        this.scrollContent(-this.currentIndex * this.totalWidth);
      },this.interval)
    },

    stopTimer() {
   
        window.clearInterval(this.playTimer);
    },

scrollContent滚动到正确的位置:

scrollContent(currentPosition) {
   
        // 1.设置正在滚动
        this.scrolling = true;

        // 2.开始滚动动画
        //transition用于在一定的时间内平滑的过度
        this.swiperStyle.transition = 'transform ' + this.animDuration + 'ms';
        this.setTransform(currentPosition)

        // 3.判断滚动到的位置,校验正确的位置
        this.checkPosition();
        // 4.滚动完成
        this.scrolling = false
    },

checkPosition()校验正确的位置:

checkPosition() {
   
      //延时等动画
      window.setTimeout(() => {
   
        // 1.校验正确的位置
        //[1,2,3,4]--[4',1,2,3,4,1']当到达由1'变为1和4'变为4时需要瞬间变换
        this.swiperStyle.transition = '0ms';
        if (this.currentIndex > this.slideCount) {
   
          this.currentIndex = 1;
          this.setTransform(-this.currentIndex * this.totalWidth)
        } else if (this.currentIndex == 0) {
   
          this.currentIndex = this.slideCount;
          this.setTransform(-this.currentIndex * this.totalWidth);
        }
        
      }, this.animDuration)
    },

鼠标拖动事件的处理:

 touchStart(e) {
   
      // 1.如果正在滚动, 不可以拖动
      if (this.scrolling) return;

      // 2.停止定时器
      this.stopTimer();
      // 3.保存开始滚动的位置
      this.startX = e.touches[0].pageX;

    },

    touchMove(e) {
   
      // 1.计算出用户拖动的距离
      this.currentX = e.touches[0].pageX;
      this.distance = this.currentX - this.startX;
      let currentPosition = -this.currentIndex * this.totalWidth;
      let moveDistance = this.distance + currentPosition;

      // 2.设置当前的位置
      this.setTransform(moveDistance);

    },

    touchEnd(e) {
   
      // 1.获取移动的距离
      let currentMove = Math.abs(this
  • 2
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值