亲宝软件园·资讯

展开

JS异步观察目标分页加载

jsmask 人气:0

介绍

平时我们处理分页加载时,往往是通过滚动条判断是否到了容器底部再执行的加载任务的,这样有一个问题就是,不管滚动条是否划到底部位置,它都会运行计算这个函数。

那么,如果能判断底部的加载区域出现后再去执行加载,不用再做滚动条计算了,这样岂不美哉。本期将以异步观察目标元素的新方式去完成分页加载业务。

代码

<div id="app" @vue:mounted="mounted" :class="{'active':active}">
  <ul>
    <li v-for="item in num"><span>{{item}}</span>
      <p></p>
    </li>'
    <div class="loading">
      <div ref="loading" v-show="!isLoading"></div>
      loading..
    </div>
  </ul>
</div>
#app{
  display: none;
  &.active{
    display: block;
  }
}
ul{
  width: 100%;
  li{
    width: 100%;
    height: 10vh;
    display: flex;
    align-items: center;
    justify-content: start;
    box-sizing: border-box;
    padding: 0 3%;
    position: relative;
    border-bottom: 1px solid #efefef;
    font-size: 14px;
    font-family: fantasy, Courier, monospace;
    span{
      display: inline-block;
      min-width: 30px;
      text-align: center;
    }
    p{
      flex: 1;
      height: 4vh;
      background-color: #e2e2e2;
      margin-left: 3%;
    }
  }
}
.loading{
  font-family: fantasy, Courier, monospace;
  display: flex;
  height: 15vh;
  align-items: center;
  justify-content: center;
  animation: loading 1s linear infinite;
}
@keyframes loading{
  0%,100%{
    opacity: 1;
  }
  50%{
    opacity:0;
  }
}
import { createApp } from 'https://unpkg.com/petite-vue?module'
createApp({
  num: 0,
  page:1,
  active:false,
  observer:null,
  isLoading:false,
  mounted() {
      this.active = true;
      this.loading = this.$refs.loading;
      this.observer= new IntersectionObserver(()=>{
         this.addNum();
      },{
        root:window.document,
        rootMargin:"0px 0px 0px 0px",
        threshold:0
      })
      this.observer.observe(this.loading)
      // this.observer.unobserve(this.loading)
  },
  addNum(){
    if(this.isLoading) return;
    this.isLoading = true;
    console.log(`loading,page:${this.page}`)
    setTimeout(()=>{ 
      this.num += 20;
      this.page ++;
      this.$nextTick(()=>{
          this.isLoading = false;
      })
    },1000)
  }
}).mount()

演示

正文

监听元素

IntersectionObserver() 对不少小伙伴来说可能是一个比较生疏的构造器,你可以传入监听区域,以及监听后的回调函数,然后它会创建并返回一个 IntersectionObserver 对象,而这个对象可以来完成监听某个目标元素是否与该监听区域发生交叉,每次达到检查阈值后都会触发刚才传入的回调函数。

// 获取监听目标
this.loading = this.$refs.loading;
// 用构造器创建监听区域对象
this.observer= new IntersectionObserver(()=>{
    this.addNum();
},{
    root:window.document, // 监听区域,默认为整个可视窗体
    rootMargin:"0px 0px 0px 0px", // 类似margin,为边界的偏移量用于判定范围是否满足计算需要,默认0px 0px 0px 0px
    threshold:0  // 阈值(0-1),表示交叉区域的比例值,默认为0
})
// 
this.observer.observe(this.loading)

根据以上代码就可以在业务中,判断元素是否出现在,只要达到阈值就会触发回调,在这个回调函数中你可以去完成加载列表等操作,从而代替频繁用计算滚动条的位置距离的困扰。

反复交叉

或许你在尝试使用异步观察目标元素的这个写法时,会发现一个严重的问题,就是可能本想加载一次的任务突然出现两次请求。这又是为什么呢?

其实就是因为 threshold 这个阈值,表示着交叉区域的比例值的,当你进入这个观察区域的时候会触发,当页面内容往下填充,会把监听目标元素往下推,又到达了这个阈值从而又触发了一次。

解决方案很简单,就是加一个 isLoading 开关,在请求中的时候,把根据这个开关把监听目标隐藏掉,等加载渲染结束之后,再显示出来,就可以解决这个问题了。具体可以看演示的案例哦~

<div class="loading">
    <div ref="loading" v-show="!isLoading"></div>
    loading..
</div>

结语

以异步观察目标元素的方式来完成诸如此类的业务比如说分页加载,触发动画,阻止操作等等都是不错的选择,而且从兼容性来看也可以放心在大多数现代浏览器中使用到它。

加载全部内容

相关教程
猜你喜欢
用户评论