Vue学习Day17 封装tab栏、请求商品数据、封装回到顶部、上拉加载更多

想利用暑假时间好好学习一下vue,会记录每一天的学习内容。
今天是学习vue的第17天!

起起伏伏乃人生常态,继续加油~



1. 轮播图展示

(不写具体代码,直接引入使用)
在这里插入图片描述
Home.vue中代码:

// 引入
import {Swiper} from '../../components/common/swiper/Swiper.vue';
import {SwiperItem} from '../../components/common/swiper/SwiperItem.vue'
// 注册组件
components: {
    NavBar,
    Swiper,
    SwiperItem
  },
<!-- 放在navbar下面-->
<!-- 不用写四个,直接用v-for遍历-->
<!-- 每张图实际上可以点击跳转链接,所以用<a>标签包裹-->
<swiper>
  <swiper-item v-for="item in banners" :key="item.title">
    <a :href="item.link">
      <img :src="item.image" alt="">
    </a>
  </swiper-item>
</swiper>

目前效果:
在这里插入图片描述


还可以再抽一层,如果不想把轮播图的内部逻辑也放在Home.vue
抽到HomeSwiper.vue中:
在这里插入图片描述
这里要注意在HomeSwiper.vue中,我们是没有banners的数据的,就要借助父子通信了

// HomeSwiper.vue
props: {
  banners: Array
},

Home.vue中引入、注册、使用:

import HomeSwiper from './childComponents/HomeSwiper.vue'
components: {
  NavBar,
  HomeSwiper
},
<!-- 这里要把banners数据传过去-->
<home-swiper :banners="banners"></home-swiper>

2. 推荐信息的展示

新建一个组件文件:
在这里插入图片描述
要拿到的数据在Home.vue中,依然需要父子通信

props: {
  recommends: Array
}

Home.vue中引入、注册、使用:

import HomeRecommendView from './childComponents/HomeRecommendView.vue'
components: {
    NavBar,
    HomeSwiper,
    HomeRecommendView
},
<!--这里要把recommends数据传过去-->
<home-recommend-view :recommends="recommends"></home-recommend-view>

HomeRecommendView.vue中代码:
比较简单,没啥要说的

<template>
  <div id="recommend-view">
    <div v-for="item in recommends" :key="item.sort">
      <a :href="item.link">
        <img :src="item.image" alt="">
        <div>{{ item.title }}</div>
      </a>
    </div>
  </div>
</template>

样式比较简单也就不放代码了
在这里插入图片描述


3. 封装一张图片

是的,就是一张图片,但是因为依然是一个模块,所以还是把它封装了
步骤都跟上面的封装一样,这里跳过
在这里插入图片描述


4. tab切换栏的封装

tab切换栏在别的界面也可能会用到,所以封装在components/content中比较合适
在这里插入图片描述
活跃状态的tab栏有颜色和文字底部一条线
主要逻辑是给选项卡动态绑定active
默认是第一个选项卡有颜色,所以设置一个currentIndex = 第一个选项卡的index = 0
点击选项卡的时候能拿到index,这时候就应该让currentIndex = index,使得{active: ture},让该点击的选项卡绑定上active

<template>
  <div class="tab-control">
    <div @click="clickTab(index)" v-for="(item,index) in titles" :key="index">
      <span :class="{active: currentIndex == index}">{{ item }}</span>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    titles: Array,
  },
  data() {
    return {
      currentIndex: 0
    }
  },
  methods: {
    clickTab(index) {
      this.currentIndex = index
    }
  }
};
</script>
.active {
  color: #ff8198;
  position: relative;
}

在这里插入图片描述


5. 首页商品数据的请求和保存

// home.js
export function getHomeGoodsData(type,page) {
  return request({
    url: '/home/data',
    params: {
      type,
      page
    }
  })
}
// Home.vue
data() {
  return {
    goods: {
      'pop': {page: 1, list: []},
      'new': {page: 1, list: []},
      'sell': {page: 1, list: []},
      }
  }
},
methods: {
  getHomeGoodsData(type) {
      const page = this.goods[type].page;
      getHomeGoodsData(type, page).then(res => {
        console.log(res);
        // 这里不要直接赋值,当下拉滚动条,要请求更多的数据,也要加进来
        this.goods[type].list.push(...res.data.data.list);
        this.goods[type].page += 1;
      })
    }
},
created() {
  // 2.请求商品数据
  this.getHomeGoodsData('pop');
  this.getHomeGoodsData('sell');
  this.getHomeGoodsData('new');
}

6. 首页商品数据的展示

在这里插入图片描述
Goods.vue中代码:
先从Home.vue中拿到一整组goods数据,再传给子组件GoodsItem.vue

<template>
  <div class="goods">
    <goods-item v-for="item in goods" :key="item.title" :goods-item="item"></goods-item>
  </div>
</template>
<script>
 import GoodsItem from './GoodsItem.vue'
export default {
  props: {
    goods: Array
  },
  components: {
    GoodsItem
  }
}
</script>

GoodsItem.vue中代码:

<template>
  <div class="goods-item">
    <img :src="goodsItem.show.img" alt="">
    <div>
      <p class="goods-item-title">{{goodsItem.title}}</p>
      <span class="goods-item-price">{{goodsItem.price}}</span>
      <span class="goods-item-star">🌟{{goodsItem.cfav}}</span>
    </div>
  </div>
</template>
<script>
export default {
  props: {
    goodsItem: Object
  }
}
</script>

Home.vue中代码:

<!-- 拿到goods对象中,'pop'对应的对象中的list-->
<!-- 传给Goods组件 -->
<goods :goods="goods['pop'].list"></goods>

(这里我们的tab栏还不能切换对应商品,暂时传了一个固定的'pop')
(样式不放了,不是重点)


7. 点击tab栏切换商品数据

其实就是下面这行代码,不能传一个固定的'pop'
实际上是用户点到了哪个选项卡再将对应页面的数据传给子组件Goods->GoodsItem,再显示对应的商品

<goods :goods="goods['pop'].list"></goods>

我们的TabControl组件中是监听了click事件的,这时候应该在子组件TabControl中发射自定义事件,也就是将用户点击了哪个选项卡相关的信息发到父组件Home

TabControl.vue中代码:

methods: {
  clickTab(index) {
    this.currentIndex = index;
    // 自定义事件名用短横线命名
    // index要传出去,(选项卡的索引
    this.$emit('tab-item-click',index);
  }
}

Home.vue中代码:

<!-- 自定义事件监听器要与自定义事件名完全匹配,不能用驼峰-->
<tab-control class="home-tab" :titles="titles" @tab-item-click="clickTab"></tab-control>

上面的tab-item-click事件对应了clickTab方法,我们就要定义一个clickTab方法来处理这个事件
我们再思考一下index怎么与goods对象中的三个属性'pop''new''sell'对应起来:

data() {
  return {
    goods: {
      'pop': {page: 1, list: []},
      'new': {page: 1, list: []},
      'sell': {page: 1, list: []},
    },
    goodsType: ['pop','new','sell'],
    // 默认值是'pop'
    currentType: 'pop'
  }
}
clickTab(index) {
  this.currentType = this.goodsType[index]
},

这个时候就可以把该行固定写了'pop'改成动态的了:

<goods :goods="goods[currentType].list"></goods>

请添加图片描述
(样式凑合看,马马虎虎随便写了一下😢)


8. 回到顶部组件封装使用

先新建一个BackTop组件,然后在Home组件中应用
(这里跳过,不放代码了,上面重复过很多遍)

然后要实现一个点击BackTop组件回到顶部的功能,
⚠️一下:组件不能直接监听点击事件

<!-- 错误写法,监听不到 -->
<back-top @click="backTop"></back-top>

如果想要监听组件的原生事件,要加修饰符.native

<!-- 正确写法 -->
<back-top @click.native="backTop"></back-top>
backTop() {
  let timer = null;
  timer = setInterval(() => {
    document.documentElement.scrollTop > 0
      ? (document.documentElement.scrollTop =
          document.documentElement.scrollTop - 10)
      : clearInterval(timer);
  }, 5);

我们还需要实现:当界面滚动到一定位置,这个回到顶部按钮再出现,否则不出现

不出现可以在样式中设置display:none,这里我就用了动态绑定类的方式:

<!-- 当isHide为true时,会有hide类-->
<back-top :class="{hide: isHide}" @click.native="backTop"></back-top>
data() {
  return {
  	// 默认不出现
    isHide: true}
},
// 生命周期钩子函数,在这个阶段页面已经渲染好了
mounted() {
  // 监听界面的滚动事件
  window.onscroll = () => {
    document.documentElement.scrollTop > 800
      ? (this.isHide = false)
      : (this.isHide = true);
}

9. 上拉加载更多

当滚动条到达界面底部时会自动加载更多商品数据:

滚动条到达底部会调用getHomeGoodsData()方法,会发送一次新的网络请求,同时将新请求到的结果pushgoodslist数组,同时page+1
(这里判断滚动条是否到达底部我没写兼容)

methods:{
  listenScroll() {
    window.onscroll = () => {
      document.documentElement.scrollTop > 800
        ? (this.isHide = false)
        : (this.isHide = true);
      if (
        document.documentElement.scrollTop +
          document.documentElement.clientHeight >=
        document.documentElement.scrollHeight
      ) {
        this.getHomeGoodsData(this.currentType);
      }
    };
  },  
}
mounted() {
  this.listenScroll();
}
getHomeGoodsData(type) {
  const page = this.goods[type].page;
  getHomeGoodsData(type, page).then(res => {
    console.log(res);
    this.goods[type].list.push(...res.data.data.list);
    this.goods[type].page += 1;
  })
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值