Vue.js实现无限加载和分页功能开发
本文是Vue.js的教程,旨在通过使用一个常见的业务场景——分页/无限加载,帮助读者更好地理解Vue.js中的一些设计思想。相比Todo List类的很多入门教程,展示如何使用Vue.js完成一个需求思考过程更全面;与一些构建大规模应用的高级教程相比,它们更侧重于一些零碎细节的实现,方便读者快速掌握和应用。
需求分析
当一个页面中的信息量太大时(例如,一个新闻列表中有200个新闻项目需要显示),就会出现问题,例如:
数据量太大,影响加载速度
用户体验差,很难找到我之前看过的文章
“可扩展性差,如果200变成2000或更多,
因此,常见的解决方案是在底部加载数据或显示页面。无限加载的实现过程类似于:
1 .获取数据的ajax类方法
2.数据存储在本地数组中
3.数组中的每一条数据都被相应地插入到一个HTML模板片段中
4.将HTML片段附加到节点上
前端分页的实现过程类似于:
1 .获取数据的ajax类方法
2.用数据替换本地数组
3.数组中的每一条数据都被相应地插入到一个HTML模板片段中
4.清空节点后,将HTML片段附加到节点上
在修改或维护代码时,我们经常会发现呈现HTML和插入部件很烦人。因为我们需要将HTML拼接成字符串,在对应的位置插入数据,这往往是一个很长的字符串,然后很难添加一个类。es6的模板字符串使这种情况变得更好,但它仍然有缺陷(例如,实际编写时无法突出显示HTML代码)。同时,我们需要编写大量的for或forEach来循环数组,然后命令append。如果这个代码片段有一些复杂的交互,它可能需要通过事件代理绑定一堆方法。
如果你在完成这类业务的时候遇到了以上的问题,那么你会发现vue太coooooool了,我们Vue吧!
创建一个新的Vue.js项目
强烈建议使用vue-cli创建新项目。
一开始,你可能会认为用node.js和npm安装了很多库,生成了一些你不太了解的目录和配置文件,编写代码时会弹出很多eslint提示。但这绝对是值得的,因为这样的模板可以帮助你更好地理解Vue.js组织文件的思想,当你习惯了之后,你会发现这些规章制度大大加快了你的开发效率。
在本教程中,我们创建了一个名为loadmore的新项目。创建新项目的具体流程请参考官网教程的安装部分。
布局页面结构
为了配合教程的逐渐深入,我从加载更多的函数开始。为了跟上后续的分页,我的页面准备由两部分组成,一部分是信息列表,另一部分是底部的load more按钮,我放在App.vue的根组件中
模板div id=' app ' List/List a class=' button ' @单击=' NEXT ' GO NEXT/a/div/templatescriptimport List from '。/components/List ' export default { components 3360 { List },data(){ return }.} },methods : { next()}.} }}/scriptstyle作用域。按钮{ display:块;宽度: 100%;背景: # 212121;color: # ffffont-weight:粗体;文本对齐:中心;padding: 1emcursor:指针;文本装饰:无;} .按钮跨度{ margin-left : 2em;font-size : 5 rem;color: # d6d6d6}/style在这个过程中,我们根据Vue的设计思路有以下思路:
1.在信息列表中,我们将完成上面提到的几个步骤,但这些步骤只与信息列表本身有关。与“下一步”按钮唯一的联系是“下一步”按钮需要触发信息列表才能获取,可以通过道具进行传输。因此,我们将列表及其自己的业务逻辑和风格放在组件List.vue中
2.我们已经为按钮定义了一些基本样式,但是我们使用的css选择器是一个. button类名,它可能与。其他组件中的按钮样式,所以我们添加了一个限定范围的属性,这样App.vue中的样式样式只在这个组件中起作用。
注意:作用域不影响css的优先级。使用scoped并不意味着它不会被外部样式表覆盖。
3.我们想介绍一些基本的样式,比如reset.css如果在项目中使用了sass这样的语言,可以将对应的外部sass文件放在assets文件夹中,通过导入的方式导入。普通的css可以直接写在一个没有作用域属性的组件中,但是如果你确定这个样式表不会经常改变,它也可以作为第三方静态资源引入index.html。例如,在这个例子中,我添加了:
link rel=“样式表”href=。/static/reset.css '
效果:
完整列表
目前我们主要的业务逻辑是围绕信息列表展开的,也就是我们自己创建的List.vue。首先,我们需要得到目标数据。我选择了cnodejs.org社区的API作为例子来写。如果您还想使用封装的ajax库,您应该这样做:
介绍第三方JS库,把目标JS库文件放在静态文件夹,比如我选择了reqwest.js,然后在index.html先介绍一下。
脚本src='http:/static/req west . min . js '/脚本
然后,在构建配置文件夹中,修改webpack.base.conf.js并导出externals属性:
external s : { ' req west ' : ' req west ' }以便我们可以在项目中随时加载第三方库。
从“需求”导入需求
编写一个API接口在这个例子中,我们只需要调用文章列表接口,但是在实际的项目中,你可能需要调用很多接口,而这些接口会在多个组件中使用。那么调用接口的逻辑分散在各个组件中肯定不好。想象一下对方的网址变了,你要在无数个组件中逐一检查是否修改。
因此,我在src文件夹中创建了一个新的api文件夹,用于存储各种API接口。在当前示例中,将获得新闻列表,因此创建一个新的news.js文件:
从' reqwest ' const domain=' https://cnodejs . org/API/v1/topics ' export default { getList(数据,回调){ reqwest({ url: domain,Data:data})导入req west。然后(val=回调(null,val))。catch (e=callback (e))}}所以我们有一个获取新闻列表的API:get list。
书写组件
我们用一个ol作为新闻列表,里面的每一个li都是一条新闻,包括三条信息:标题、时间和作者。
在数据中,我们使用一个名为list的数组来存储新闻列表的数据,当然一开始是空的。我们在数据中设置一个名为limit的值来控制每页加载多少条数据,并将其作为参数传递给API getList。
因此,我们的模板部分是这样的(添加一些样式美化样式):
模板ol li v-for='列表的新闻' p class=' title“{ news . title } }/p p class=' date“{ news . create _ at } }/p p class=' author ' by : { { news . author . loginname } }/p/Li/ol/template style作用域ol { margin-left 3360 2 rem;十进制以外的list-style :} Li { line-height : 1.5;padding: 1remborder-bottom: 1px实心# b6b 6;} .title { font-weight : bold;font-size : 1.3 rem;} .日期{ font-size : 8 rem;color: # d6d6d6}/style,我们显然需要使用getList来获取数据,但是先想想我们会在哪里使用它。首先,我们需要在组件开始渲染时自动获取一次列表,并填写基本内容。其次,我们需要在每次点击APP.vue中的Next按钮时获得一个新列表
因此,我们在methods中定义了get方法,在成功获取数据后,将获取的数组拼接到当前列表数组中,从而实现更多的加载。
沿着这个思路,再想想get方法需要的参数,一个是包含page和limit两个属性的对象,另一个是回调函数。正如我们所说的,回调函数只需要拼接数组,所以只有最后一页参数没有设置。
初始化时,page的值应为1,默认为第一页内容。之后,页面的值只通过下一步按钮改变,所以我们让页面通过道具从App.vue获取页面值。
最后,它补充了get方法触发的条件。一种是在组件的生命周期函数中调用this.get()来获取初始内容,另一种是在页面值发生变化时获取,所以我们观察页面属性,当它发生变化时调用this.get()。
最后,List.vue的脚本是这样的:
脚本导入来自的新闻./API/news ' export default { data(){ return { list :[],limit: 10 } },prop : { page : { type : Number,default: 1 } },created () { this.get() },watch : { page(val){ this . get()},methods : { get(){ news . getlist({ page : this . page,limit: this。list=this . list . concat(list . data)} } } } } }脚本同时,我们将App.vue中的列表修改为:
列表:page='page'/list
然后在第页的App.vue中添加初始值和相应的方法:
Data () {return {page: 1}},methods: {next () {this。page}},所以我们已经完成了更多函数的加载。
覆盖为分页
因为我们之前的思路很清晰,代码结构也很清晰,重写会很简单,只需要把List.vue中的拼接数组改成赋值数组:
//general load more//this . list=this . list . concat(list . data)//paging this . list=list . data用这么简单的一行就完成了函数的改变,这就是Vue.js中核心数据驱动视图的强大之处当然,接下来我们还会做一些更cooooool的事情。
添加功能
因为分页代替了原来的数组,只有一个Next按钮是不够的,我们需要一个Previous按钮来返回到上一页。同样,将上一个方法绑定到上一个按钮。除了用this.page -改变page的值外,还需要判断this.page===1的边界条件。
同时,为了方便了解我们当前的页码,在按钮上添加{{ page }}来显示页码。
a class=' button ' @ click=' next ' GO next spanCurrENT: { { page } }/span/a
在编写和完善过渡动画功能的过程中,充分体现了Vue.js的清晰性和便捷性。接下来,继续看其他有用的功能,首先是过渡动画。
为了展示过渡的力量,我首先找到了一个模仿对象:lavalamp.js(Demo地址)。
在Demo中,我们可以看到页面已经用非常优雅的动画过渡完成了内容切换的过程,这是用JQuery CSS动画完成的,我准备用Vue.js重写
第一,研究了原作者的实现思路,发现用一个div作为加载器,位置设置为固定。翻页时,根据单击的按钮,加载器会将其高度从顶部或底部扩展到100%。数据加载后,高度再次折叠,最后隐藏。
那么最初的思路如下:
1.添加一个加载器,最小高度与按钮相同,背景为黑色,使过渡更加自然。
2.2.loader的高度需要达到一个屏幕的高度,所以把html和body的高度设置为100%。
3.需要有一个值作为是否显示加载程序的基础。我将其设置为finish,其默认值为true。通过添加v-show='!“完成”以控制其显示。
将this.finish=false添加到下一个和上一个方法中,以触发加载程序显示。
5.在App.vue和List.vue中建立一个双向道具属性绑定完成。执行List.vue中的get方法后,通过道具将App.vue中的finish设置为true,隐藏加载器。
向加载器添加过渡。因为动画可以分为顶部展开和底部展开,所以使用动态过渡来指定正确的过渡名称。
7.向上加一个新值,用来判断动画从哪个方向开始,默认值为false。在前一个方法中,执行this.up=true,而在下一个方法中,执行this.up=false。
按照思路,编写好的加载器应该是这样的(样式和其他样式在最终统一显示中设置):
div id='loader' v-show='!完成“:传输=‘向上’?”Up-start ' : ' down-start ' ' span loading/span/div,可以看到我设置了up-start和down-start过渡模式,对应的css动画代码如下:向下-开始-过渡{ bottom : 0;高度: 100%;} .down-start-enter { animation : expand . 5s 1三次贝塞尔曲线(0,1,0,1)两者;} .向下-开始-离开{ animation: collapse .5s 1三次贝塞尔曲线(0,1,0,1)两者;top : 0;bottom: auto} .启动-过渡{ top : 0;高度: 100%;} .up-start-enter { animation : expand . 5s 1三次bezier(0,1,0,1)两者;} .up-start-leave { animation : collapse . 5s 1三次bezier(0,1,0,1)两者;top:汽车;bottom : 0;} @关键帧展开{ 0% { height : 3em;transform: translate3d(0,0,0);} 100% { height : 100%;transform: translate3d(0,0,0);} } @个关键帧折叠{ 0% { height : 100%;transform: translate3d(0,0,0);} 100% { height : 3em;transform: translate3d(0,0,0);}}设置了展开和折叠两个动画,然后在过渡的每个生命周期钩子中进行相应的绑定,从而达到类似lavalamp.js的效果
为了保证动画能够完整执行,在执行List.vue的get方法后,使用setTimeout定时器将完成延迟0.5秒,变为真。
优化体验动画效果后发现,lavalamp.js在实际使用中有一个巧妙的设计,就是点击“上一页”后,页面转到底部,而点击“下一页”后,页面转到顶部。
实现后者并不复杂,只需在下一个方法中添加下面一行代码来调整位置:
document.body.scrollTop=0
对于previous来说,下一步有点复杂,因为获得数据后页面高度会发生变化。如果在前一个中执行scrollTop的更改,填充新内容后高度会变长,页面不会在底部。所以我观察finish的值,只有当click按钮是previous并且finish从false变为true时,我才会进入底部。代码如下:
watch: { finish (val,oldVal) { if(!奥尔德瓦尔这个。up){ document . body . scroll top=document . body . scroll height } } }前端路由完成上述内容后,发现无论翻到哪一页,一旦刷新就会回到第一页。Vue路由器就是为了解决这样的问题而诞生的。
首先介绍VueRouter,参考上面的“介绍第三方JS库”。然后在main.js中配置路由规则
我们的想法包括:
1.我们需要在url上反映当前的页码。
2.2.url中的页面数量应该与所有组件中的页面值一致。
3.单击下一个和上一个按钮跳转到相应的网址。
在这个例子中,我们没有路由器视图。
因此,main.js的配置如下:
从“vue”导入Vue从“App”导入。/App ' import VueRouter from ' vue . use(VueRouter)const router=new VueRouter()router . map({ '/page/: page num ' : { name : ' page ',component : } } })router . redirect({ '/' : '/page/1 ' })router . beforeach((transition)={ if(transition . to . path!=='/page/0') {transition。next ()} else {transition。abort ()}})路由器。start (app,' app ')首先定义一个名为page的命名路径。之后,所有目标路径为“/”的请求(即初始页面)都被重定向到“/page/1”以确保一致性。最后,在每次路线执行前做出判断。如果到达像“/page/0”这样的非法路径,将不会执行transition.next()。
按照之前的思路,在App.vue中,获取路由对象的参数值,并分配给page。同时向两个按钮添加相应的v形链接。
本文已整理成《Vue.js前端组件学习教程》,欢迎大家学习阅读。
以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。
版权声明:Vue.js实现无限加载和分页功能开发是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。