目前我们主要的业务逻辑都是围绕信息列表展开的,也就是我们创建的List.vue。首先,我们需要获取目标数据,我选用了cnodejs.org社区的API作为例子进行编写。如果你也想用一个封装好的ajax库的话,应该这么做:
引入第三方JS库
将目标JS库文件放在static文件夹中,例如我选择的是reqwest.js,然后在index.html先引入。
<script src="https://www.jb51.net/article/static/reqwest.min.js"></script>
然后在build配置文件夹中,修改webpack.base.conf.js,export externals属性:
externals: { 'reqwest': 'reqwest' }
这样我们在我们的项目中,就可以随时加载第三方库了。
import reqwest from 'reqwest'
写个API接口
在这个例子中,我们只需要调用文章列表这一个接口,但是实际项目中,可能你需要调用很多接口,而这些接口又会在多个组件中被用到。那么调用接口的逻辑四散在各个组件中肯定是不好的,想象一下对方的url发生了变化,你就得在无数个组件中一个个检查是否要修改。
所以我在src文件夹中新建了一个api文件夹,用于存放各类API接口。当前例子中,要获取的是新闻列表,所以新建一个news.js文件:
import reqwest from 'reqwest' const domain = 'https://cnodejs.org/api/v1/topics' export default { getList (data, callback) { reqwest({ url: domain, data: data }) .then(val => callback(null, val)) .catch(e => callback(e)) } }
这样我们就拥有了一个获取新闻列表的API:getList。
编写组件
我们用一个<ol>作为新闻列表,内部的每一个<li>就是一条新闻,其中包括标题、时间和作者3个信息。
在data中,我们用一个名为list的数组来储存新闻列表的数据,一开始当然是空的。我们再在data中设置一个名为limit的值,用来控制每页加载多少条数据,作为参数传给getList这个API。
因此我们的template部分是这样的(加入了一些style美化样式):
<template> <ol> <li v-for="news of list"> <p>{{ news.title }}</p> <p>{{ news.create_at }}</p> <p>By: {{ news.author.loginname }}</p> </li> </ol> </template> <style scoped> ol { margin-left: 2rem; list-style: outside decimal; } li { line-height: 1.5; padding: 1rem; border-bottom: 1px solid #b6b6b6; } .title { font-weight: bold; font-size: 1.3rem; } .date { font-size: .8rem; color: #d6d6d6; } </style>
之后我们显然需要使用getList来获取数据,不过先想想我们会在哪几个地方使用呢?首先,我们需要在组件开始渲染时自动获取一次列表,填充基础内容。其次,我们在每次点击APP.vue中的Next按钮时也需要获取新的列表。
所以我们在methods中定义一个get方法,成功获取到数据后,就把获取的数组拼接到当前list数组后,从而实现了加载更多。
沿着这个思路,再想想get方法需要的参数,一个是包含了page和limit两个属性的对象,另一个是回调函数。回调函数我们已经说过,只需要拼接数组即可,因此只剩下最后一个page参数还没设置。
在初始化的时候,page的值应该为1,默认是第一页内容。之后page的值只由Next按钮改变,所以我们让page通过props获取App.vue中传来的page值。
最后则是补充get方法触发的条件。一是在组件的生命周期函数created中调用this.get()获取初始内容,另一是在page值变化时对应获取,所以我们watch了page属性,当其变化时,调用this.get()。
最后List.vue的script长这样:
<script> import news from '../api/news' export default { data () { return { list: [], limit: 10 } }, props: { page: { type: Number, default: 1 } }, created () { this.get() }, watch: { page (val) { this.get() } }, methods: { get () { news.getList({ page: this.page, limit: this.limit }, (err, list) => { if (err) { console.log(err) } else { list.data.forEach((data) => { const d = new Date(data.create_at) data.create_at = `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}` }) this.list = this.list.concat(list.data) } }) } } } </script>
同时我们将App.vue中的<list>修改为:
<list :page="page"></list>
再为page在App.vue中添加一个初始值以及对应的方法next:
data () { return { page: 1 } }, methods: { next () { this.page++ } }
这样我们就已经完成了加载更多的功能。
改写为分页
因为之前我们的思路非常清晰,代码结构也很明了,所以改写起来会非常简单,只需要将List.vue中拼接数组改为赋值数组就可以了:
// 常规loadmore // this.list = this.list.concat(list.data) // 分页 this.list = list.data
就这么简单的一行就完成了功能的改变,这就是Vue.js中核心的数据驱动视图的威力。当然,接下来我们还要做点更cooooool的。
添加功能