Web Vue Thinksns Spa(3) 级页面列表数据拉取
分析FeedList
以Feedlist.vue为例,看看vuex的state,getter,mutation,action到底怎么配合用的:
数据拉取
数据拉取下拉刷新,上拉刷新的地方:
<JoLoadMore
ref="loadmore"
@onRefresh="onRefresh"
@onLoadMore="onLoadMore"
>
onRefresh就是上拉刷新,Feed有3个tab:new,hot,follow
async onRefresh () {
const type = this.feedType.replace(/^\S/, s => s.toUpperCase())
const action = `feed/get${type}Feeds`
//获取最新的不需要after
const data = await this.$store.dispatch(action, { refresh: true })
this.$refs.loadmore.afterRefresh(data.length < limit)
},
async onLoadMore () {
const type = this.feedType.replace(/^\S/, s => s.toUpperCase())
const action = `feed/get${type}Feeds`
//根据after的id分页拉取
const data = await this.$store.dispatch(action, { after: this.after })
this.$refs.loadmore.afterLoadMore(data.length < limit)
},
},
action异步拉数据。哪里定义?肯定是vuex module的feed.js:
const actions = {
async getNewFeeds ({ commit }, payload) {
//上面传来的refresh为true
const { after, refresh = false } = payload
//真正的api在这里
const { data } = await api.getFeeds({ type: 'new', after })
const { feeds = [], pinned = [] } = data
//pinned和普通的处理稍微不同,
commit(TYPES.SAVE_PINNED_LIST, { list: pinned })
//普通列表 保存
commit(TYPES.SAVE_FEED_LIST, { type: 'new', data: feeds, refresh })
return feeds
},
}
async/await
异步转同步;
拉取数据到state里,并且第一时间缓存,缓存则是通过mutation,同步的.
const state = {
list: {
hot: lstore.getData('FEED_LIST_HOT') || [], // 热门动态列表
new: lstore.getData('FEED_LIST_NEW') || [], // 最新动态
follow: lstore.getData('FEED_LIST_FOLLOW') || [], // 关注列表
pinned: lstore.getData('FEED_LIST_PINNED') || [], // 置顶列表
},
}
refresh
参数决定要不要更新,
const mutations = {
[TYPES.SAVE_FEED_LIST] (state, payload) {
const { type, data, refresh = false } = payload
//refresh=true,就缓存最新的, 否则,旧的在list前面,data在后面?
const list = refresh ? data : [...state.list[type], ...data]
state.list[type] = list
//更新缓存
lstore.setData(`FEED_LIST_${type.toUpperCase()}`, list)
},
- 逻辑分析
假设1次拉10个,已有10(1-10)个feed文章, 已缓存到FEED_LIST_NEWS里.
拉取时发现有最新的,11-15,那么直接保存15-6,剩余的靠底部的Loadmore重新拉取(5-1)
感觉是有点浪费的,一旦有新的,缓存要整体的更新.
- 如果改进
刷新时,记录下当前最新的,localstorage是否可以写map? obj: true 表示缓存:
[obj,true][obj,false]
数据使用
自然是通过getter:
const getters = {
pinned (state) {
return state.list.pinned
},
hot (state) {
return state.list.hot
},
new (state) {
return state.list.new
},
follow (state) {
return state.list.follow
},
}
getter用mapGetters
,合并到了组件的computed属性里:
可以看到Feedlist.vue里是不存任何数据的,全部在vuex里.
再通过query确定feedType,得到1个新的计算属性feeds, 在template里就查询feeds就好.
computed: {
//来自feed module
...mapGetters('feed', ['hot', 'new', 'follow', 'pinned']),
feeds () {
return this[this.feedType]
},
feedType: {
get () {
return this.$route.query.type || 'hot'
},
set (val) {
const { query } = this.$route
this.$router.replace({ query: { ...query, type: val } })
},
},
<li
v-for="(card, index) in feeds"
:key="`feed-${feedType}-${card.id}-${index}`"
:data-feed-id="card.id"
>
<FeedCard v-if="card.user_id" :feed="card" />
<FeedAdCard v-if="card.space_id" :ad="card" />
</li>
总结
1 数据获取与使用;
2 不同的分类又如何统一处理; news/hot/follow
3 置顶和普通的处理.
NewsList
这个数据又是直接放在组件里了.
news不是每个用户能投,涉及到投稿认证
,这个逻辑暂时不分析,准备另开一篇来做.