因为分页替换了原来的数组,所以仅仅一个Next按钮不够用了,我们还需要一个Previous按钮返回上一页。同样的,也给Previous按钮绑定一个previous方法,除了用this.page--改变page的值以外,还需要对this.page === 1的边界条件进行一个判断。
同时为了方便知道我们当前的页数,在按钮中,加入{{ page }}显示页数。
<a @click="next" >GO NEXT<span>CURRENT:{{page}}</span></a>
transition动画
编写和完善功能的过程中,已经充分体现了Vue.js清晰和便利的一面,接下来继续看看其它好用的功能,首先就是transition动画。
为了展示transition的威力,首先我找到了一个模仿的对象:lavalamp.js( Demo地址 )。
在Demo中可以看到页面以一种非常优雅的动画过渡完成了切换内容的过程,其本身是用JQuery+CSS动画完成的,我准备用Vue.js进行改写。
首先学习了一下原作者的实现思路以后,发现是将一个div作为loader,position设定为fixed。当翻页时,根据点击的按钮不同,loader从顶部或者底部扩展高度,达到100%。数据加载完毕后,再折叠高度,最终隐藏。
那么初步的思路如下:
1.添加一个loader,最小高度与按钮一致,背景同为黑色,让过渡显得更自然。
2.loader高度需要达到一个屏幕的高度,所以设置html和body的height为100%。
3.需要有一个值,作为loader是否显示的依据,我定为finish,其默认值值为true,通过给loader添加v-show="!finish"来控制其显示。
4.在next和previous方法中添加this.finish = false触发loader的显示。
5.在App.vue和List.vue建立一个双向的props属性绑定至finish,当List.vue中的get方法执行完毕后,通过props将App.vue中的finish设定为true,隐藏loader。
6.给loader添加一个transition。由于动画分为顶部展开和底部展开两种,所以使用动态的transition为其指定正确的transition名称。
7.新增一个值up,用于判断动画从哪个方向开始,其默认值为false。在previous方法中,执行this.up = true,反之在next方法中,则执行this.up = false。
根据思路,写出的loader应该是这样的(style等样式设定在最后统一展示):
<div v-show="!finish" :transition="up? 'up-start':'down-start'"> <span>Loading</span> </div>
可以看到我设定了up-start和down-start两种transition方式,对应的css动画代码如下:
.down-start-transition { bottom: 0; height: 100%; } .down-start-enter { animation: expand .5s 1 cubic-bezier(0, 1, 0, 1) both; } .down-start-leave { animation: collapse .5s 1 cubic-bezier(0, 1, 0, 1) both; top: 0; bottom: auto; } .up-start-transition { top: 0; height: 100%; } .up-start-enter { animation: expand .5s 1 cubic-bezier(0, 1, 0, 1) both; } .up-start-leave { animation: collapse .5s 1 cubic-bezier(0, 1, 0, 1) both; top: auto; bottom: 0; } @keyframes expand { 0% { height: 3em; transform: translate3d(0, 0, 0); } 100% { height: 100%; transform: translate3d(0, 0, 0); } } @keyframes collapse { 0% { height: 100%; transform: translate3d(0, 0, 0); } 100% { height: 3em; transform: translate3d(0, 0, 0); } }
设置了expand和collapse两个animation,再在transition的各个生命周期钩子中做对应的绑定,就达到了和lavalamp.js相接近的效果。
为了保证动画能执行完整,在List.vue的get方法执行完之后,还使用了一个setTimeout定时器让finish延时0.5秒变为true。
优化体验
动画效果完成之后,实际使用时发现lavalamp.js还有个巧妙地设计,就是点击Previous后,页面前往底部,反之点击Next后则前往顶部。
实现后者并不复杂,在next方法中加入以下一行代码调整位置即可:
document.body.scrollTop = 0
previous前往底部则略微复杂一点,因为获取到数据之后,页面高度会发生改变,如果在previous中执行scrollTop的改变,有可能会出现新的内容填充后高度变长,页面不到底的情况。所以我watch了finish的值,仅当点击按钮为previous且finish变化为false至true时前往底部,代码如下:
watch: { finish (val, oldVal) { if (!oldVal && val && this.up) { document.body.scrollTop = document.body.scrollHeight } } }
前端路由
完成以上内容之后,发现不论翻到第几页,一旦刷新,就会回到第一页。vue-router就是为解决这类问题而生的。
首先我们引入VueRouter,方式可以参考上文中的“引入第三方JS库”。然后在main.js对路由规则进行一些配置。
我们的思路包括:
1.我们需要在url上反映出当前所处的页数。
2.url中的页数应该与所有组件中的page值保持一致。
3.点击Next和Previous按钮要跳转到对应的url去。
4.在这个例子中我们没有router-view。
因此main.js的配置如下: