一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第22天,点击查看活动详情。
前言
大家好,在上一篇文章话题广场分享中,我们对整个页面布局进行了分析,并通过请求取官方api接口拿到了正式的话题数据实现了页面的动态渲染。而我们今天要分享的“活动”页面整体布局跟话题广场非常类似,也是主要由标题和内容两大块组成。下面我们来具体分析实现一下。
布局分析
如图所示,活动页整体布局比较简单,主要由顶部标题栏和主页面中的活动列表两部分组成,其中活动列表是一组tab标签页,点击不同的tab页可以查看不同城市的活动。而具体的活动内容布局也很简单,主要包括活动的封面图片,活动标题,活动时间,活动所在城市以及一个报名参加的按钮。
布局实现
根据上面对整体布局的分析我们来把页面的布局实现一下:
- 标题栏 标题栏我们还是用vant库中的van-nav-bar来实现,对应的设置title属性为“活动”,left-arrow属性为true(显示返回按钮),绑定click-left事件用于点击返回按钮时返回上一页
<van-nav-bar title="活动" left-arrow @click-left="toBack" />
const router = useRouter()
const toBack = () => {
router.back();
}
- tab标签 tab标签页的标题是几个热门的城市,具体的城市列表可以通过后台api接口“cities”获取得到。因此我们这里需要添加一个van-tabs父组件,然后再给van-tabs添加3个子项van-tab,为什么是3个呢,因为有两个tab(全部和其他)需要做成固定的,而具体的城市则需通过v-for指令循环渲染
<van-tabs @click-tab="switchCity">
<van-tab
:title="c.city_name"
:name="c.city_alias"
v-for="c in cityList"
:key="c.city_alias"
>
<event-list :city="c.city_alias" />
</van-tab>
</van-tabs>
const store = useStore();
api.citys().then((res) => {
state.cityList = res.data.banner_citys;
state.cityList.unshift({ city_alias: "", city_name: "全部" });
state.cityList.push({ city_alias: "buxian", city_name: "其他" });
});
const switchCity = (tab) => {
store.state.refreshList();
};
活动列表封装
上面布局分析的时候我们提到,活动列表内容是放在tab标签中的,也就是说通过切换不同的标签(城市)可以展示不同的活动列表,那么我们来看每个标签页中的活动列表数据格式都是一样,唯一不同的就是根据切换不同的城市显示对应城市的活动数据,那也就是说每个城市的列表除了数据源不同外其它都是一样的,那么为了避免每个标签页中的代码冗余,我们就将列表进行封装,然后通过传递不同的数据源或不同的参数以实现代码的复用。
如上图所示,通过分析官方event_list接口我们发现,每个tab页调用的都是该接口,然后通过传递一个city参数来获取不同城市的活动信息。因为我们封装的这个组件是专门的活动列表组件,只是在活动页面中的tab页面中使用,因此我们可以直接把请求接口的部分也一并封装在组件内,然后通过定义一个city prop来获取不同的城市参数进而获取不同城市的活动数据。
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
<van-list
v-model:loading="loading"
:finished="finished"
finished-text="没有更多了"
@load="onLoad"
>
<van-cell v-for="item in eventList" :key="item.event_id">
<div class="event-item">
<van-image class="image" :src="item.screenshot" />
<div class="event-content">
<div class="event-title">{{ item.title }}</div>
<div class="event-time">{{ item.event_start_time }}</div>
<div class="event-city">{{ item.city }}</div>
<div class="event-join">报名参加</div>
</div>
</div>
</van-cell>
</van-list>
</van-pull-refresh>
props: {
city: {
type: String,
required: true,
},
},
setup(props, ctx) {
const state = reactive({
refreshing: false,
loading: false,
finished: false,
eventList: [],
cursor: 0,
});
const store = useStore();
const { city } = props;
const onRefresh = () => {
state.finished = false; //清空列表数据,重新加载
state.loading = true;
state.refreshing = true;
onLoad();
};
store.commit("setRefresh", onRefresh);
const onLoad = () => {
api.eventList(state.cursor, city).then((res) => {
if (state.refreshing) {
state.eventList = [];
state.refreshing = false;
}
console.log(res);
state.cursor = res.cursor;
state.eventList.push(...res.data);
state.loading = false;
});
};
return {
...toRefs(state),
onRefresh,
onLoad,
};
},
总结
本次分享我们对活动页面进行了布局分析及搭建,还将活动列表进行了封装以实现代码的复用,最终实现了活动页没的整体功能。本次涉及到的知识点有:组件的封装,父子组件信息传递,列表的下拉刷新和上拉加载。今天的分享就到这里了。小伙伴们给个赞哦,感谢!