《美食街》项目(主页篇){为什么父级的滑动事件,在子级是怎么启用的.节流 性能优化:每隔一段时间,再去执行指定的功能,参数,第一个参数,间隔多少;第二个参数,节流谁

内容大概:

首页是由header和home两个组件构成,组件里面使用了element组件库,实现了轮播图、下拉显示一系列效果。

组件中安装element组件库:

npm i element-ui -S

步骤

在home组件的mounted里通过api向后端请求轮播图数据,再通过element进行渲染,—全观—代码如下:

<template>
  <div class="home">
    <!-- 轮播 start -->
    <el-carousel :interval="5000" type="card" height="300px">
      <el-carousel-item v-for="item,index in list">
        <!--/detail?menuId=5d83bfba2f7cb93a4009cf98-->
        <router-link :to="{name:'menulist'}">
          <img 
            :src="item.product_pic_url"
            width="100%"
            alt=""
          >
        </router-link>
      </el-carousel-item>
    </el-carousel>
    <!-- 轮播 end -->
    <!-- 内容精选 瀑布流形式 start -->
    <div>
      <h2>内容精选</h2>
      <!-- :info='info' -->
      <waterfall ref="waterfall" @view="loadingMenuCard">
        <menu-card :margin-left="13" :info="menuList"></menu-card>
      </waterfall>     
    </div>
    <!-- 内容精选 瀑布流形式 end -->
  </div>
</template>

<script>
import MenuCard from '@/components/menu-card.vue'
import Waterfall from '@/components/waterfall.vue'
import { getBanner, getMenus } from '@/service/api.js'
// 引入 注册 使用
export default {
  name: 'home',
  components: {
    MenuCard: MenuCard,
    Waterfall
  },
  data(){
    return {
      list:[],
      menuList:[],
      page:1,
      pages:0,      
    }
  },
  created(){
    getBanner().then(res=>{
      console.log(res)
      this.list=res.data.list
    })
    getMenus({page:this.page}).then(({data})=>{
      
      this.menuList=data.list;
      this.pages=Math.ceil(data.total/data.page_size);
      
    })
  },
  methods:{
    loadingMenuCard(){
      console.log('在外部监听到的滚动')
      this.page++
      if(this.page>this.pages){//当数据加载完毕,不在进行新数据渲染
        this.$refs.waterfall.isLoading = false;
          console.log('没有了崽子')
          // console.log('111')
        return;
      }
      this.$refs.waterfall.isLoading=true;
      getMenus({ page: this.page }).then(({ data }) => {
        this.menuList.push(...data.list)
        this.$refs.waterfall.isLoading = false;
      })
    },    
  }
}
</script>
<style lang="stylus">
.home 
  h2
    text-align center
    padding 20px 0;
  .el-carousel__item h3 
    color #475669
    font-size 14px
    opacity 0.75
    line-height 200px
    margin 0
  .el-carousel__item:nth-child(2n) 
    background-color #99a9bf
  .el-carousel__item:nth-child(2n+1) 
    background-color #d3dce6
</style>
data中声明的为:
list:[],//轮播图数据
menuList:[],//传给menu-card的值
page:1,//初始值,显示页数,后期为给pages作比较。
pages:0,初始值,后在计算属性中,将总数据的总页数赋给了它,后期为给page作比较。
有人问ref="waterfall"是干什么?真正作用最后列出;
ref是给这个元素盖个标签,方便取获。

1.获取轮播图数据并渲染:

created(){
    getBanner().then(res=>{
      this.list=res.data.list
    })
  },

api文件中:

export async function getBanner(){
  return await http.get('/banner');
}

将值赋予给本组件中的属性中,并将数据渲染到页面中。

2.显示菜品

首先在home组件里的created周期里通过api向后端请求数据内容精选的第一页,并赋值给data里面的数组menuList,通过**:info**方法传递给子组件menu-card。
获取数据:

getMenus({page:this.page}).then(res=>{
  this.menuList=res.data.list//存了第一页的五条      
  this.pages=Math.ceil(res.data.total/res.data.page_size)
})

传递数据:

<div>
       <h2>内容精选</h2>
       <waterfall ref="waterfall" @view='loadingMenuHanle()'>
         <menu-card :margin-left="13" :info="menuList"></menu-card>
       </waterfall>
</div>

api:

export async function getMenus(params){
  return await http.get('/menu/query', {params});
}

3.让我们将注意移入menu-card组件中

从menu-card组件里面获取父组件home传递的info,通过v-for遍历,进行渲染

<template>
  <el-row class="menu-card" type="flex" justify="start">
    <el-col
      style="flex:none;" 
      :style="{'margin-left':marginLeft+'px'}"
      v-for=" item in info" :key="item.id"
    >
      <el-card :body-style="{ padding: '0px' }">
        <router-link :to="{ name: 'detail', query: { menuId: item.menuId }}">
          <img :src="item.product_pic_url" class="image" style="width: 232px;height: 232px;">
          <div style="padding: 14px;" class="menu-card-detail">
            <strong>菜品名称:{{item.title}}</strong>
            <span>{{ item.comments_len}} 评论</span>
            <router-link :to="{name:'space',query:{userId:item.userId}}" tag="em"> 
              <!-- //em作用a标签不能嵌套 -->
            作者--{{item.name}}
            </router-link>
          </div>
        </router-link> 
      </el-card>
    </el-col>
   
  </el-row>
</template>
<script>

export default {
  name: 'menu-card',
  props:{
    marginLeft: {
      type: Number,
      default: 22
    },
    info:{
      type: Array,

      default:() => []
    }
  }
}
</script>

<style lang="stylus">
.menu-card 
  flex-wrap wrap
  .el-col-24
    width auto
    margin-bottom 20px
    margin-left: 22px
    
  .menu-card-detail
    > *
      display block
    strong 
      height 24px
      line-height 24px
      font-size 14px
      font-weight bold
      color #333
    span 
      height 26px
      line-height 26px
      font-size 12px
      color #999
    em 
      height 23px
      line-height 23px
      font-size 12px
      color #ff3232
</style>

完成后—

4再来到waterfall组件中:

home组件中通过滚动事件进行判断,当从可视窗上边到waterfall元素下边小于可视窗高的时候,调用父组件home的事件loadingMenuHanle。如代码:

<template>
  <div class="waterfall" ref="waterfall">
    <slot></slot>
    <div class="waterfall-loading" ref='loading' v-show="isLoading">
      <i class="el-icon-loading"></i>
    </div>
    
  </div>
</template>
<script>
//节流
import {throttle} from 'throttle-debounce'
export default {
  name: 'Waterfall',
  data(){
    return {
      isLoading:false,
      
    }
  },
  mounted(){
    //节流 性能优化:每隔一段时间,再去执行指定的功能
    // 参数,第一个参数,间隔多少
    //           第二个参数,节流谁
    this.scrollHandler = throttle(500,this.scroll.bind(this))
    window.addEventListener('scroll', this.scrollHandler);
  },
  //防止组件被解绑候,监听事件依然存在,需要解绑
  destroyed(){
    window.removeEventListener('scroll',this.scrollHandler)
  },
  methods:{
    scroll(){
      if (this.isLoading) return;
      //clientHeight 可视高度
      if (this.$refs.waterfall.getBoundingClientRect().bottom < document.documentElement.clientHeight){ 
        //console.log('已到达可视区域')
        this.isLoading = true;
        this.$emit('view');//通知外部,滚动已完成,可以显示数据了
      }
    }
  }
}
</script>
<style lang="stylus">
.waterfall-loading
  width 100%
  height 20px
  text-align center
</style>

window.addEventListener:添加事件监听;
window.removeEventListener:移除事件监听;(在销毁周期destroyed时移除事件)
this.$ emit(‘view’)
有人问,为什么父级的滑动事件,在子级是怎么启用的, this.$emit(‘view’) 给你答案,它通过父子通信,通知Home.vue中waterfall组件中的@view事件处理完成。

5.Home的waterfall区域中,监听到滑动事件触发,执行Home中loadingMenuCard事件:

loadingMenuCard(){
      this.page++
      if(this.page>this.pages){//当数据加载完毕,不在进行新数据渲染
        this.$refs.waterfall.isLoading = false;
          alert('没有了崽子')
        return;
      }
      this.$refs.waterfall.isLoading=true;
      getMenus({ page: this.page }).then(({ data }) => {
        this.menuList.push(...data.list)
        this.$refs.waterfall.isLoading = false;
      })

判断当前页数(page)大于总页数(pages)结束运行。如果小于总页数,向后添加到数组menuList里面。

为什么要再获取一次getMenus? 因为在page属性得到++时,需要获取更多页数,让其活跃起来。
让新请求的数据,将原本的menuList覆盖;

若有疑问,请及时点出哦

小作者在持续更新中…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

漠媂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值