「这是我参与2022首次更文挑战的第26天,活动详情查看:2022首次更文挑战」
前言
大家好,经过一波三折终于结束了优秀作者榜页面的功能实现,接下来的分享中我们继续回到首页来完善首页中的功能。在首页中除了“关注”和“推荐”标签外,其它几个标签都是动态渲染的,并且对应标签页中的列表数据也是根据标签动态加载的。然而在这几个动态渲染的标签中还有一个额外的功能没做,就是进入标签页后这个标签下面还会分为很多子标签,并且点击子标签后列表数据会自动过滤刷新。接下来的分享中就来实现一下该功能。
点击子标签属性数据列表
在前面实现数据列表功能时,特意针对这几个动态标签封装来一个子标签组件JTags和列表组件JList,然而就是这两个封装给我们接下来的分享会带来很多麻烦
先来看下我们接下来要实现的功能:如下图
- 首先在点击任意一个动态标签时会跳转到该标签对应的页面,该页面包括一个JTags组件(子标签)和一个JList组件(列表),默认进来后会根据主标签ID动态加载出该标签下所有的子标签(在JTags中展示),然后列表则会加载主标签下的所有数据内容。
- 当我们尝试去点击某个子标签时,则列表会根据主标签和子标签过滤出符合条件的文章。而就是这个功能,由于前面两个组件的分开封装,实现起来变得有些复杂有些绕。 在前面封装JTags和JList时,我们是通过定义url和其它的参数属性(props)来实现数据请求与加载的,而不是直接将数据源传给组件去渲染,这样就会带来一个问题:当url或其它的参数属性发生变化时,组件不会自动触发更新操作,也就是说一旦数据已经渲染完成,不管是url还是其它的props怎么变化都不再重新请求数据,这就是问题所在。
而我们要实现的功能是:点击某个子标签后会根据子标签的id重新去后台请求列表数据并重新渲染,但点击标签操作是发生在JTags组件中的,而数据渲染需要加载在JList的组件中,而我们知道在没有任何外界帮助的情况下,在一个组件中是无法实现对另一个组件中的属性或方法进行操作的。
最初想到的解决方案是:在JTags组件中再定义一个自定义点击事件,在该自定义事件中将对应子标签的id传递出去,然后在Home.vue中定义一个函数来接收该标签id并通过props的形式传递给JList组件。然而结果可想而知:并没有达到我们预期的效果,子标签点击后列表数据并未发生任何变化。
在经过一番绞尽脑汁的思索过后,受兄弟组件间传值的启发,突然灵光一现想到一个可行但不一定是最优的方案:虽然点击和加载不是发生在同一个组件中,但是我们可以把两个组件间要用到的数据保存在全局状态vuex中,这样一来就可以实现两个组件间的数据共享了。大概思路如下:
- 在store下的index.js中定义三个状态属性:
- url:String类型,默认值:“/juejin/recommend_cate_feed”,用于请求后台接口的url(给JList.vue组件使用)
- tagId:String类型,默认为空,保存子标签的id(给JList.vue组件使用)
- refreshList:function类型,用于点击子标签后刷新列表数据(给JTags使用)
- 在JTags中给标签绑定一个click事件,并在该事件中做如下操作:
- 设置vuex中的url属性值为“/juejing/recommend_cate_tag_feed”,用于同时根据父标签id和子标签id共同过滤数据
- 设置vuex中的tagId属性值为当前选中的子标签的id值
- 最后调用vuex中的refreshList方法,属性JList列表数据
- 在JList组件中做如下修改:
- 删除之前定义的props:url(或者保留也不影响)
- 在onLoad方法中定义两个新的变量url和tagId,值则从vuex中的url和tagId中或取,并将两个参数传递给htt.post axios请求
- 最后再在onRefresh方法的下面将该方法(onRefresh)的定义赋值给vuex中的refreshList,以便在JTags中调用
- 在首页Home.vue中,由于点击不同的父标签会根据不同的请求接口加载不同的数据,因此还需在标签的click-tab事件中根据不同的标签设置不同的后台接口给vuex中url 核心代码及实现效果:
- store/index.js
export default createStore({
state:{
url:'/juejin/recommend_cate_feed',
tagId:'',
refreshList:function(){}
},
mutations:{
setRefresh(state,payload){
state.refreshList = payload
},
setUrl(state,url){
state.url = url
},
setTagId(state,tagId){
state.tagId = tagId
}
}
})
- JTags.vue
<ul class="tag-list">
<li class="tag-item"
<!--省略...-->
:data-id="tag.tag_id"
@click="clickTag(tag.tag_id)"
>
{{tag.tag_name}}
</li>
</ul>
const clickTag = function(tagId){
const tags = document.querySelectorAll(".tag-item");
tags.forEach(item=>{
item.classList.remove('active');
if(item.getAttribute("data-id") == tagId){
item.classList.add('active');
}
});
store.commit('setUrl',"/juejin/recommend_cate_tag_feed")
store.commit('setTagId',tagId);
store.state.refreshList();
}
& .tag-item.active{
background:#1e80ff;
color:#fff;
}
- JList.vue
const onLoad = function(){
let api_url = store.state.url,
tagId = store.state.tagId;
http.post(api_url,{
//...
tagId:tagId
})
}
const onRefresh = function(){}
store.commit("setRefresh",onRefresh);
- Home.vue
const clickTab = function(tab){
if(tab.name === "关注"){
store.commit("setUrl", "/juejin/recommend_follow_feed")
}else if(tab.name === "推荐"){
store.commit("setUrl", "/juejin/recommend_all_feed")
}else{
store.commit("setUrl", "/juejin/recommend_cate_feed")
}
}
总结
到此关于首页列表的功能就算是完全实现了,由于一次封装事故,我们还意外的引入了vuex的使用,也算是借助本次实战来练习一下vuex的使用吧。今天的分享就先到这里了,欢迎点赞加关注哦!!