如何管理 vue 项目中的数据?
vuex
如何管理 vue 项目的数据?这个问题似乎早已经有答案了,无非就是使用 vuex ,全局 store,整个应用维护一个超大的 Object,界面的显示情况随着超大 Object 的变化而变化。
看起来很简单,不就维护一个 Object 嘛,实际上,要想组织好数据这块代码,必须事先对项目的数据结构理解得非常透彻,然后像设计数据库表一样把各个 module 的样子设计出来。实际上,个人觉得设计 vuex 的 module 比设计数据库表复杂得多:
1、像数据库一样设计各个业务实体的外貌,这部分设计难度应该和数据库表设计差不多;
2、维护一堆 ajax 请求状态;
3、如何优雅地复用 module。比如有一个 PersonListModule,在一个页面上有两处要用到 PersonListModule 中的列表数据:一个是要在表格控件里面展示,一个是要在下拉控件里面展示,每个控件中展示的列表数据筛选条件不一样;
4、如何同步 vuex 中的数据和服务器端数据。vuex 的超大 Object 可以看做服务器端数据在客户端内存中的一个缓存,怎么设计这个缓存的同步策略?
对于3、4两个问题,结合起来更恐怖:同步服务器端数据到 PersonListModule 的同时,还要考虑如何从 PersonListModule 中筛选出分页数据到页面展示,还要筛选出多个列表,还要考虑在什么时机重新更新“缓存”,想想就头大。
假设我们能力很强大,设计出了能完美应对上述问题的 store 方案,还有一个大问题拦着我们呢:如何保证这套设计的可扩展性?因为业务系统变化多端,不知道什么时候产品经理又有新想法了,我们得设计能很好地应对变化多端的需求吗?
为什么这么难?问题究竟出现在哪里?
vuex 的思维模式主要是从数据着手,由数据推导出界面的样子,这就需要先设计好 store 结构了。要设计好 store 结构,目测必须具备如下特质的工程师才能做好:
1、对项目业务了解非常深入;
2、具备超强的抽象思维能力;
3、经验丰富,能尽量想到设计出的 store 结构能应付哪些情况、不能应付哪些情况。
第2条的门槛实在是太高了,能做到的前端工程师估计没多少。
怎么办?
我们不应该从数据推导出界面,而应该从界面推导出数据,逐层抽象。
比如现在要仿一个新浪微博首页,页面上主要包含的数据有:分组信息、微博列表、个人信息、一些推荐信息等,那么就设计一个只针对该页面的 module ,大致结构为:
const homePageModule = {state: {groupList: [{id: 1,name: '名人明星',unread: 1},{id: 2,name: '同事',unread: 0}],groupListExtraInfo: {// 初始显示多少个小组initShowCount: 5,loading: true},weiboList: [{id: 1,content: '<p>震惊部</p>',author: 'yibuyisheng',createTime: '20170719234422'}],weiboListPageInfo: {loadingStatus: 'QUIET', // 三种取值:QUIET -> 没有加载;UP -> 向上加载;DOWN -> 向下加载// weiboList 的开始时间,可用这个时间戳做下一次的向上加载startTime: '20170719234422',// weiboList 的结束时间,可用这个时间戳做下一次的向下加载endTime: '20170719234422'},self: {id: 1,nickname: 'yibuyisheng',email: 'yibuyisheng@163.com',avatar: 'http://weibo.com/2674779523/profile?rightmod=1&wvr=6&mod=personinfo',followedCount: 405,followerCount: 235,weiboCount: 1321},recommendMovies: [...],recommendTopics: [...]...},mutations: {updateWeiboList(state, list) {...}},actions: {appendWeiboList() {...},prependWeiboList() {...}}
};
针对这个页面,这个结构,各个处理逻辑就具体化、特殊化了,代码写起来非常轻松。
代码复用?
假设现在有个小组页面,点进去后可以看到该小组所有成员发的微博,因为是一个新的页面,所以需要新起一个 module ,这也意味着要重复写一遍 weiboList 相关的代码,岂不蛋疼!
此时可以考虑写一个 createWeiboListModule()
函数,用于创建这种通用 module ,然后再写一个 mergeModules()
函数,把 createWeiboListModule()
函数创建出来的 module 对象和各页面特殊的 module 合并起来,样子看起来大致是这样:
mergeModules(createWeiboListModule(), {state: {...},mutations: {...},actions: {...}
});
遇到需要复用的才抽取通用逻辑,很自然,很简单。
怎么结合 vue 组件?
上面的结构有一个很大的问题,就是不能很好地和 vue 组件结合。比如,要让微博首页和分组页面中的微博列表能复用 weiboList 相关代码,那么 weiboList 涉及到的 state、action、mutation、getter 的命名都要尽量保持一致,不然就要传一个 nameMap(命名映射)给两个页面通用的 WeiboListComponent 组件,看起来就像这样:
<weibo-list-component :name-map="{weiboList: 'homePageWeiboList'}"></weibo-list-component>
简直蛋疼!
好吧,那就严格约束这两个页面的 state、action、mutation、getter 命名都保持一致吧!
简直超级蛋疼!
此时可以考虑用 namespace 来解决这个问题,比如上面的 homePageModule
可以把 weiboList
拆分出来:
const store = new vuex.Store({...,modules: {'page:home': {state: {groupList: [{id: 1,name: '名人明星',unread: 1},{id: 2,name: '同事',unread: 0}],groupListExtraInfo: {// 初始显示多少个小组initShowCount: 5,loading: true},self: {id: 1,nickname: 'yibuyisheng',email: 'yibuyisheng@163.com',avatar: 'http://weibo.com/2674779523/profile?rightmod=1&wvr=6&mod=personinfo',followedCount: 405,followerCount: 235,weiboCount: 1321},recommendMovies: [...],recommendTopics: [...]...},},'page:home:weiboList': createWeiboListModule(...)}...
});
这样一来,只要给 vue 组件传一个 namespace 参数就行了:
<weibo-list-component namespace="page:home:weiboList"></weibo-list-component>
嗯,看起来挺好的!
如何处理“store 缓存”?
可以在上一个问题解决的基础上,加上缓存功能,目测有大把现成的缓存策略可以参考(服务器端都玩儿烂了),由于绝大部分系统并不需要这层缓存功能,所以此处不赘述。
就这样了吗?
上述方案,思维方向的确是导致最后执行起来轻松了很多,从具体到抽象的过程,很自然,符合思考习惯。但是最终的代码还是会很容易搞得很乱的:
1、
mergeModules()
要照顾各种合并策略;2、
createXXXModule()
方法会抽出很多层。比如可以从createWeiboListModule()
抽出来createContinuousListModule()
,用于构造通用的具备“向前向后”加载能力的列表 Module,最终可能会形成一条常常的“继承链”,需要自己去定义维护这套继承逻辑,心累。
其实上面两条一看,就知道有现成的解决方案了: class。
参考此处实现:https://github.com/yibuyishen...(代码还在完善中)。
具体业务代码写起来就像是这样了:
class ContinuousList extends BaseModule {state = {list: [],pageInfo: {loadingStatus: 'QUIET',startTime: '20170720003939',endTime: '20170720003939'}}@actionasync appendList(...) { ...const result = await request('some url', params);this.updateList(result.list);...}@actionprependList(...) { ... }
}class WeiboList extends ContinuousList {@actionasync voteUp(...) {...await request('some url', params);const weiboDetail = await updateWeibo('some url', params.weiboId);const newList = this.state.list.map((wb) => {return wb.id === weiboDetail.id ? weiboDetail : wb;});this.updateList(newList);...}
}@composition(WeiboList)
class HomePage extends BaseModule {$namespace = 'page:home:';...@actionrequestRecommendInfo(...) {...}...
}HomePage.register();
在对应的 HomePage.vue 里面,大致是这样:
<template><div class="home-page-view">...<weibo-list-component namespace="page:home:weiboList"></weibo-list-component>...</div>
</template>
<script>
export default {created() {...const constants = this.getConstants('page:home');this.$store.dispatch(constants.REQUEST_RECOMMEND_INFO, params);...}
};
</script>
而 WeiboListComponent
组件大致是这样:
<template><div class="weibo-list-component">...</div>
</template>
<script>
export default {props: {namespace: {type: String,required: true}},computed: {weiboList() {const constants = this.getConstants(this.namespace);return this.$store.getters[constants.LIST];}},created() {...const constants = this.getConstants(this.namespace);this.$store.dispatch(constants.APPEND_LIST, params);...}
};
</script>
总结
其实就是换一种思路:从界面推导数据,从具体到抽象。
如何管理 vue 项目中的数据?相关推荐
- Vue项目中获取数据后使用swiper轮播,无法轮播且 autoplay 和 loop 失效问题!
Vue项目中获取数据后使用swiper轮播,无法轮播且 autoplay 和 loop 失效问题! 问题表现:轮播组件显示第一张图,可拖动但无法切换到下一张图.但是F12控制台切换屏幕后能正常轮播但无 ...
- vue项目中打印数据或表格(使用第三方依赖print-js)
一. 第三方依赖print-js (print-js插件可以打印Html.图片和Json数据类型,下面示例打印的是Json数据类型,其他类型可查看官方文档 ) 资源包文档网址:https://prin ...
- Vue项目中使用props传递数据并允许子组件修改的方案
在项目中遇到了一个相关需求: 一个页面中为了能够使代码更加简洁和易于查看,将其分成了多个功能模块.此时多个功能模块都需要使用共同的一组数据进行展现或对其进行修改.此时考虑到Vue项目中的数据通信方式: ...
- 在vue项目中引用vuex状态管理工具
在vue项目中引用vuex状态管理工具 一.vuex是什么? 二.使用步骤 1.引入库 2.在main.js文件引入配置 3.配置store/index.js文件 4.获取state数据 5.获取ge ...
- 【EasyExcel】在SpringBoot+VUE项目中引入EasyExcel实现对数据的导出(封装工具类)
在SpringBoot+VUE项目中引入EasyExcel实现导入导出 一.引入EasyExcel 通过maven引入,坐标如下: <dependency><groupId>c ...
- Vue项目中v-for无法渲染数据
在Vue项目中,我们想要实现下面的布局效果 后端返回的数据格式如下,可以看出产品列表五张图的数据位于同一个数组中 而我的html结构如下: 我希望直接渲染左边一张大图,然后右边的四张小图通过v-for ...
- methods vue过滤器 和_数据动态过滤技巧在 Vue 项目中的实践
这个问题是在下在做一个 Vue 项目中遇到的实际场景,这里记录一下我遇到问题之后的思考和最后怎么解决的(老年程序员记性不好 -.-),过程中会涉及到一些Vue源码的概念比如 $mount. rende ...
- vue之猫眼json数据的获取直接用于自己的vue项目中,swiper轮播插件的坑
vue之猫眼json数据的获取直接用于自己的vue项目中 遇到问题总结: 加载不出猫眼数据,无法调用,数据被限制 猫眼电影图片的拼接及删除问题 swiper的迷幻坑** 首先来说一下第一问题 加载不出 ...
- vue项目中api接口管理总结
默认vue项目中已经使用vue-cli生成,安装axios,基于element-ui开发,axiosconfig目录和api目录是同级,主要记录配置的相关. 1. 在axiosconfig目录下的ax ...
最新文章
- 微信小程序实践_1前言
- 日本“女机器人”畅销全球,有三个地方最吸引人,网友:想拥有
- Fedora Workstation 30是激动人心的、功能丰富的更新
- jquery之仿京东菜单
- [转载]Javascript异步编程的4种方法
- 百度飞桨 如何撑起了AI产业生态?
- Centos6.5优化Tomcat7
- Sync Framework 词汇表
- 视频编辑软件(Nero Video2021中文版) v23.0.1.12pjb
- 1.16 隐藏不需要打印的内容 [原创Excel教程]
- UTF和uncode
- 计算机海报大赛策划书,海报策划书模板.docx
- 什么是流程引擎,F2BPM
- 本科计算机专业考研集成电路,集成电路工程专业考研院校排名
- 制造业MES生产管理系统程序代码 MES源码
- 请问在C#中如何实现声音报警?
- CVS和CSV概念区分
- 数字金字塔(保证两位数的数字也能排好)
- 毕业论文怎样写?(三天写出一篇初稿)
- idea 导入项目java类图标C不见了,显示出J标识解决办法
热门文章
- 四款 5G 版 iPhone 12 齐发,支持北斗系统,你准备好了吗?
- Docker Desktop添加对Kubernetes的支持
- Repository 设计模式介绍
- iOS开发之UIWebView
- 【Laravel学习篇 · 一】Windows下起步就遇麻烦
- WINDOWS XP 开始→运行→命令 集锦
- bpexpdate – 更改映像目录库中备份的截止日期以及介质目录库中介质的截止日期nbu...
- 作为数据科学家,我都有哪些弱点
- CSS基础知识(颜色、伪类、盒子模型)
- 《中国人工智能学会通讯》——3.15 社交媒体中的谣言识别研究及其发展趋势...