使用Vue观察者实现一个简单异步无限滚动效果

编辑推荐:3月31日前,点击注册激活 Coding.net 立赠30天付费会员 ,体验极速代码托管服务!
无限滚动(Infinite Scroll)是一种很常见的用户体验模式,它建议用户在Web页面或应用程序加载显示很少的内容。当用户开始向下滚动页面时,会加载更多内容。这些内容是通过向负责提供内容的服务器发出请求来异步加载的。在这篇文章中,我将讨论JavaScript的异步操作以及Vue如何实现无限滚动效果。在这个过程中,我们将看到一个使用无限增发动的简单页面。

理解异步操作

在程序中编写一段同步代码,比如下面的例子,有两行代码:L1L2。如果L1未结速,L2是不会执行的: console.log('quavo'); console.log('takeoff'); 使用Vue观察实现一个简单异步无限滚动效果 通常情况下,我们会看到上面的代码执行的顺序,那是因为$http.get请求需要一些时间才能从our_url获取data,JavaScript并不会花时间去等,而是在等待$http.get时执行下一行代码。完成它所做的事情,这样就可以在控制台上进行日志记录。异步写代码的方法还包括: setTimeout()函数,它可以先执行后面的一些事情,然后再执行setTimeout()中的代码。比如: console.log('我先执行') setTimeout(() => { console.log('是的,我等待3s后才执行') },3000) console.log('对了,我会第二个执行') 使用Vue观察实现一个简单异步无限滚动效果 高阶函数(也称为回调函数)是作为参数传递给其他函数的函数。让我们假设有一个名为function X的回调函数,它被当做一个参数传递给另一个函数function Y。最终,函数X被执行或调用内部Y函数。比如下面的代码: function Y(X) { $.get("our_url", X); } 来看一个实例: var add = function (a, b) { return a + b; } function math (func, array) { return func(array[0] , array[1]); } console.log(math(add, [1, 2])) // => 3 上面的例子中传进去的add是一个参数,而在return的时候刚是一个函数。 高阶函数存在于不同的模式中,很有可能你在不知道的情况下就使用它们。比如window.onclicksetTimeout()setInterval()。除此之外,还有一些常见的高阶函数例子。比如jQuery ajax回调函数: $.ajax({ url: '//localhost:8000/api/v1/entry/1', type: 'GET', dataType: 'json', success: function (data) { // success 接收回调函数 console.log(data) } }) setTimeout()setInterval()这样的计时器函数也是高阶函数: setTimeout(function (){ console.log('是的,我会在3s后执行') },3000) var i = 0; setInterval(function (){ i++; console.log(`我现在的值是:${i}`) }, 100) 使用Vue观察实现一个简单异步无限滚动效果 在数组中的sort()map()reduce()filter()等函数都是高阶函数的示例: var arr = [2, 8, 20, 5, 17, 38, 21]; // 升序 arr.sort(function (x, y) { return x - y }) // 降序 arr.sort(function (x, y) { return y - x }) // 数据所有元素进行求平方得到新数组 arr.map(function (item) { return Math.pow(item, 2) }) // 数组求和 arr.reduce(function (x, y) { return x + y }) // 过滤掉数组中的偶数,只留奇数,返回一个新数组 arr.filter(function (x) { return x % 2 !== 0 }) 使用Vue观察实现一个简单异步无限滚动效果 有关于高阶函数更多介绍,可以阅读下面的内容:

什么是观察者

Vue观察者允许我们在更改数据时执行异步操作。它们就像是在Vue实例中对数据做更改,而视图做出相应的反应。在我们的Vue实例中,观察者用watch关键词表示,并因此被使用: let app = new Vue({ el: '#app', data () { return { // 和view绑定的数据 } }, watch: { // 将在app中使用的异步操作 } })

扩展观察者的异步操作

让我们看看Vue如何使用观察者来监视异步操作。使用Vue构建一个具有无限滚动特性的应用程序,一旦用户到达页面的底部,就会执行GET请求,并检索更多的数据。这篇文章的示例是来自于@Sarah Drasner的原始案例(我是她的超级粉丝)。接下来看它是如何工作的。 首先使用<script>标签导入必要的库。在这里,我们将导航Vue和Axios,这是一个基于HTTP客户端的浏览器。 <head> <script src="https://unpkg.com/vue"></script> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> </head> 如果你在Codepen上写的话,可以直接在JavaScript设置中导入相关的脚本,如下图所示: 使用Vue观察实现一个简单异步无限滚动效果 创建一个新的Vue实例: let app = new Vue({ // el属性是一个挂载器,指向index.html中的#app的DOM元素 el: '#app', }) 创建data()函数,并附加需要绑定到DOM的数据属性。最初我们是不会在页面的底部,因此bottom的值设置为false。另外设置beers属性,先设置为一个空数组。 let app = new Vue({ el: '#app', data () { return { bottom: false, beers: [] } } }) 接下来使用methods属性创建所需要的方法。methods允许我们创建函数,并将事件绑定到这些函数以及处理相关的事件。在bottomVisible()函数中,我们使用三个只读属性手动创建无限滚动相关的特性:
  • scrollY:返回滚动条距离viewport顶部边缘的Y坐标。如果没有离开viewport,返回的值为0
  • clientHeight:无素可视区高度,包括padding,但不包括水平滚动条高度、bordermargin
  • scrollHeight:元素内容的高度,包括由于溢出在屏幕上不可见的内容
有关于这方面的相关属性的介绍,可以阅读前段时间整理的一篇笔记《视口宽高、位置与滚动高度》。
let app = new Vue({ el: '#app', data () { return { bottom: false, beers: [] } }, methods: { bottomVisible () { const scrollY = window.scrollY const visible = document.documentElement.clientHeight const pageHeight = document.documentElement.scrollHeight const bottomOfPage = visible + scrollY >= pageHeight return bottomOfPage || pageHeight < visible } } }) methods中继续添加另一个函数addBeer(),我们使用Axios执行GET请求。使用Promisescallback,创建一个apiInfo对象,并从API中调用检索值传给它。我们的Vue实例中的每个函数都可以使用this访问data属性。 let app = new Vue({ el: '#app', data () { return { bottom: false, beers: [] } }, methods: { bottomVisible () { const scrollY = window.scrollY const visible = document.documentElement.clientHeight const pageHeight = document.documentElement.scrollHeight const bottomOfPage = visible + scrollY >= pageHeight return bottomOfPage || pageHeight < visible }, addBeer () { axios.get('https://api.punkapi.com/v2/beers/random') .then(response => { let api = response.data[0] let apiInfo = { name: api.name, desc: api.description, img: api.image_url, tips: api.brewers_tips, tagline: api.tagline, food: api.food_pairing } this.beers.push(apiInfo) if (this.bottomVisible()) { this.addBeer() } }) } } })
有关于Vue中的methods相关的知识可以阅读前段时间整理的相关学习笔记《Vue的Methods》、《Vue的Methods和事件处理》和《在Vue中何时使用方法、计算属性或观察者》。
watch属性中添加相应的观察者,用来监视应用程序状态的变化,并相应的更新DOM: let app = new Vue({ el: '#app', data () { return { bottom: false, beers: [] } }, methods: { bottomVisible () { const scrollY = window.scrollY const visible = document.documentElement.clientHeight const pageHeight = document.documentElement.scrollHeight const bottomOfPage = visible + scrollY >= pageHeight return bottomOfPage || pageHeight < visible }, addBeer () { axios.get('https://api.punkapi.com/v2/beers/random') .then(response => { let api = response.data[0] let apiInfo = { name: api.name, desc: api.description, img: api.image_url, tips: api.brewers_tips, tagline: api.tagline, food: api.food_pairing } this.beers.push(apiInfo) if (this.bottomVisible()) { this.addBeer() } }) } }, watch: { bottom (bottom) { if (bottom) { this.addBeer() } } } })
有关于Vue中的观察者相关的知识,可以阅读前段时间整理的学习笔记:《Vue的观察者》。
接下来再使用Vue的生命周期的钩子created添加一个scroll滚动事件,每次调用bottomVisible()函数时触发一个滚动事件。为了实现无限滚动特性,将data函数中的bottom值设置为bottomVisible()函数。created钩子允许我们访问反应性数据和Vue实例中的函数。 let app = new Vue({ el: '#app', data () { return { bottom: false, beers: [] } }, methods: { bottomVisible () { const scrollY = window.scrollY const visible = document.documentElement.clientHeight const pageHeight = document.documentElement.scrollHeight const bottomOfPage = visible + scrollY >= pageHeight return bottomOfPage || pageHeight < visible }, addBeer () { axios.get('https://api.punkapi.com/v2/beers/random') .then(response => { let api = response.data[0] let apiInfo = { name: api.name, desc: api.description, img: api.image_url, tips: api.brewers_tips, tagline: api.tagline, food: api.food_pairing } this.beers.push(apiInfo) if (this.bottomVisible()) { this.addBeer() } }) } }, watch: { bottom (bottom) { if (bottom) { this.addBeer() } } }, created () { window.addEventListener('scroll', () => { this.bottom = this.bottomVisible() }) this.addBeer() } })
有关于Vue实例和生命周期相关的知识可以阅读前段时间整理的学习笔记《Vue实例和生命周期》。
现在把注意力集中到DOM中,将使用Vue指令让DOM和Vue实例之间实现数据的双向绑定:
  • v-if:根据条件的布尔值,有条件的渲染DOM元素
  • v-for:基于数组循环遍历出项目列表,比如beer in beers,其中beer是被迭代的数组元素的别名
有关于Vue的指令相关的介绍,可以阅读:
示例中的DOM这样写: <div id="app"> <section> <h1>Make yourself some Punk Beers</h1> <!-- beers数组值为空时,显示正在加载中的状态 --> <div class="beer-container"> <div v-if="beers.length === 0" class="loading">Loading...</div> <!-- 对beers数组进行迭代 --> <div v-for="beer in beers" class="beer-contain"> <div class="beer-img"> <img :src="beer.img" height="350" /> </div> <div class="beer-info"> <h2>{{ beer.name }}</h2> <div class="beer-description"> <p><span class="bright">Description:</span> {{ beer.desc }}</p> </div> </div> </div> </div> </section> </div> 这个时候你的页面可以看到这样的结果: 使用Vue观察实现一个简单异步无限滚动效果 因为还没有添加任何样式,看上去丑丑的。如果添加了样式之后,就可以看到下面这样的效果:
注意,我在@Sarah Drasner的示例上删除了一些字段,只是为了样式上看上去好看一点。原始示例的效果和源码,点击这里可以看到
这个时候你滚动到页面的底部的时候就可以无限加载内容。这个效果也就是我们所说的无限滚动效果: 使用Vue观察实现一个简单异步无限滚动效果

总结

有人可能会问,为什么我们不直接使用Vue的computed属性呢?原因是computed属性是同步的,必须返回一个值。当执行类似timeout函数之类的异步操作,或者像上面示例中GET请求时,最好使用Vue的watch,因为Vue会侦听函数的返回值。使用事件监听器也很酷,但这些都有手工处理事件和调用方法而不是只监听数据更改的缺点。无论如何,当你看到或想要在Vue中使用它们时,你现在知道如何处理异步操作了吧。
特别声明,本文整个思路是跟着@Chris Nwamba的博文《Simple Asynchronous Infinite Scroll with Vue Watchers》学习整理的。文章有关于Vue的示例代码,都源于此文。
由说作者是Vue相关的初学者,如果文章中有不对之处,还请各路大婶拍正。如果你有更好的建议或者想法,欢迎在下面的评论中与我们一起分享。

大漠

常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《图解CSS3:核心技术与案例实战》。
如需转载,烦请注明出处:https://www.w3cplus.com/vue/simple-asynchronous-infinite-scroll-with-vue-watchers.html
返回顶部