需求技术点分析
- 新闻列表页面需要实现下拉刷新和滑动更新内容的功能,需要通过vant组件库里的组件实现功能
- 列表内容后续需要复用,所以需要单独封装一个组件
- 更新时候需要更新和原来不同的内容,需要通过时间戳判断
静态页面搭建
- 使用vant组件库van-nav-bar组件搭建头部样式,并使用插槽的方式插入搜索按钮
- 使用vant组件库tabs组件van-tabs标签实现标签页滚动,并在右侧使用插槽技术插入汉堡按钮
- 使用vant组件库的van-cell单元格组件,搭建新闻列表整体框架
封装网络请求
- 在新闻列表页面中,一共要获取两种数据,一个是频道滚动标签页数据,还有一个是新闻列表数据,所以需要封装两个axios请求函数
- 频道滚动标签页网络请求
import request from "@/utils/request";
/**
* 获取首页频道列表信息
*/
export const getUserChannels = () => {
return request({
method: 'GET',
url: 'v1_0/user/channels'
})
}
- 新闻列表网络请求
- 这个请求需要用户传入两个必须的参数,一个是请求的频道ID(channel_id),还有一个是时间戳(timestamp),请求新的推荐数据传当前的时间戳,请求历史推荐传指定的时间戳
import request from "@/utils/request";
/**
* 获取频道的文章列表
*/
export const getArticles = params => {
return request({
method: 'GET',
url: 'v1_0/articles',
params
})
}
将频道数据渲染到页面上
- 将请求到的频道需要滚动的内容循环渲染到van-tab组件标签上,就可以完成滚动的频道标签页
渲染文章列表内容
- 需求技术点:这里需要考虑到,在渲染文章列表时,是要考虑到下拉刷新和滑动更新内容这两个功能的,所以需要在这两个功能的基础上来完成数据的渲染。这里我选择将整个的文章列表封装成组件,填充到van-tab 标签中,通过父传子的传值方式将对象传过去,用来获取频道的id
<van-tab :title="item.name" v-for="item,index in channels" :key="index">
<!-- 文章列表组件 -->
<ArticleList :channel="item"></ArticleList>
</van-tab>
- 完成下拉刷新和滑动更新的需求
- 滑动更新功能
-
功能技术点:这里使用了vant组件库中的van-list列表组件,其中的关键点就是在于利用该组件的loading,finished属性和load事件
-
官方文档:List 组件通过
loading和finished两个变量控制加载状态,当组件滚动到底部时,会触发load事件并将loading设置成true。此时可以发起异步操作并更新数据,数据更新完毕后,将loading设置成false即可。若数据已全部加载完毕,则直接将finished设置成true即可。 -
注意点:需要定义一个空的数组,监听van-list的load事件,当load事件触发,发起网络请求时,把请求到的数组数据添加到新的数组当中,这里不可以直接等于,需要用push方法追加,不然就会数据覆盖永远没办法显示下一组数据
-
遇到的问题,没有对接口需要定义的时间戳做定义和判断,导致无法刷新新的内容
-
解决办法:在data中定义一个变量timestamp设置为null,通过请求到的数组长度作为判断条件,如果可以获取数据长度,则加载完成就获取新的事件戳,如果已经没有数据了就将finished 属性改为true结束加载
async onLoad() {
// 1. 请求获取数据
try {
const { data } = await getArticles({
channel_id: this.channel.id,
//获取事件戳参数
timestamp: this.timestamp || Date.now(),
with_top: 1
})
const { results } = data.data
// 2. 把请求结果数据放到 list 数组中
//每次请求数据都往里面追加内容,才能完成滚动加载,使用展开运算符将元素追加
this.list.push(...results)
// 3. 本次数据加载结束之后要把加载状态设置为结束
// loading 关闭以后才能触发下一次的加载更多
this.loading = false
// 4. 判断数据是否全部加载完成
if (results.length) {
// 更新获取下一页数据的时间戳
this.timestamp = data.data.pre_timestamp
} else {
this.finished = true
}
} catch (err) {
this.error = true
this.loading = false
}
},
- 下拉刷新需求
-
功能技术点:这里使用了vant组件库中的van-pull-refresh下拉刷新组件,其中的关键点就是在于监听该组件refresh事件,然后利用该组件的v-model属性设置为boolen变量来控制刷新状态,
-
官方文档:下拉刷新时会触发
refresh事件,在事件的回调函数中可以进行同步或异步操作,操作完成后将v-model设置为false,表示加载完成 -
注意点:这里在请求过数据后,同样也是追加到定义的list数组中,不过这里要使用数组的unshift方法在最前面追加,不然显示不出页面更新的效果
// 当触发下拉刷新的时候调用该函数
async onRefresh() {
try {
// 1. 请求获取数据
const { data } = await getArticles({
channel_id: this.channel.id, // 频道 id
timestamp: Date.now(), // 下拉刷新每次都应该获取最新数据
with_top: 1 // 是否包含置顶,进入页面第一次请求时要包含置顶文章,1-包含置顶,0-不包含
})
// 2. 将数据追加到列表的顶部
const { results } = data.data
this.list.unshift(...results)
// 3. 关闭下拉刷新的 loading 状态
this.isRefreshLoading = false
// 提示成功
this.refreshSuccessText = `刷新成功,更新了${results.length}条数据`
} catch (err) {
console.log(err)
this.isRefreshLoading = false // 关闭下拉刷新的 loading 状态
this.$toast('刷新失败')
}
}
封装文章单元格组件
- 因为考虑到组件复用,所以把文章列表里的单个文章单元格封装成了组件
- 注意点:因为接收到的数据里需要显示的图片有一张和三张的,所以需要使用v-if来判断显示哪个image标签
- 需求技术点:同样适用了vant组件库中的单元格组件和图片组件,并且从文章列表父组件中使用props方法接受了对象数据来渲染页面
<van-cell class="article-item">
<div slot="title" class="title">{{article.title}}</div>
<div slot="label">
<div v-if="article.cover.type === 3" class="cover-wrap">
<div
class="cover-item"
v-for="(img, index) in article.cover.images"
:key="index"
>
<van-image
fit="scale-down"
width="100"
height="100"
:src="img"
/>
</div>
</div>
<div class="label-info-wrap">
<span>{{ article.aut_name }}</span>
<span>{{ article.comm_count }}评论</span>
<span>{{ article.pubdate }}</span>
</div>
</div>
<van-image
v-if="article.cover.type === 1"
fit="cover"
slot="default"
width="100"
height="100"
:src="article.cover.images[0]"
/>
</van-cell>