阅读本文大约需要 5 分钟
文章由 skinner 投稿,授权转发!
数据模型是数据特征的抽象,用来抽象定义一个业务对象。假如现在有一个用户模型,如果要抽象的描述这个用户对象,可以按照如下来定义:
const UserModel = {
name:{
type:String,
property:'name',
value:'zhangshang'
},
age:{
type:Number,
property:'age',
value:26
}
}
其中,type
声明数据的类型,property
指明映射路径,value
是默认值。这里先有个大概的概念就行,后面我会通过实例来详细展开。
前面介绍了数据模型的定义,那和前端开发又有什么关系呢?前端又不需要和数据库打交道,前端开发主要就是拿到数据显示就完了,那为什么需要数据模型呢?它是怎么助力前端开发的呢?我们先来看一下以下几个场景。
我们在前端开发中,通过ajax
请求拿到服务端数据,然后将数据显示在视图上,经常会写如下代码:
如示例,假如我们要显示用户头像,通过取到headUrl
的值绑定在src
属性上即可。因为是异步加载获取的数据,在最终获取到headUrl
的值之前,我们需要先判断cardData.buyerExperienceInfo
的存在性,然后才能取值,否则在视图初次渲染之前会报如下错误:
在这种场景下,我们在开发中就不得不写一些防御性的代码,久而久之,项目中类似代码会越来越多,碰到层级深的,防御性代码就会写的越来越恶心。另外还有的就是,如果服务端在这中间某个字段删掉了,那就又得特殊处理了,否则会有一些未知的非空错误报错,这种编码方式会导致前端严重依赖服务端定义的数据结构,非常不利于后期维护。
平时开发中,我们拿到了服务端返回的数据,有些不是标准格式的,是无法直接在视图上直接使用的,是需要而外格式化处理的,比如我司服务端返回的的价格字段单位统一是分,跟时间相关的字段统一是毫秒值,这个时候我们在组件的生命周期内,就不得不而外增加一些对数据处理的逻辑,还有就是这部分处理在很多组件都是公用的,我们就不得不频繁编写类似的代码,数据处理逻辑没有得到复用。
在用户做了一些交互后,需要将一些数据存储到服务端,这个时候我们拿到的数据往往也是非标准的,就比如你要提交个表单,其中有个价格字段,你拿到价格单位可能是百位的,而服务端需要的单位必须是分位的,这个时候在提交数据之前,你又得对这部分数据进行处理,还有就是有些接口的参数是json
字符串形式的,可能是多级嵌套的,你还要需要特意构造这样的参数数据格式,导致开发中编写了太多与业务无关的逻辑,随着项目逐渐扩大或者维护人员更迭,项目会越来越不好维护。
在碰到这么多痛点之后,我就在想如何解决,回顾以上场景,总结下来存在以下几个问题:
所以,这里我引入了数据模型的概念,那通过数据模型如何解决这类问题呢?下面我将通过两个实际案例来进一步呈现上述场景,以及引入了数据模型之后是如何解决的。
这个案例使用Vue开发,功能很简单,就是通过ajax请求从服务端拿到数据,然后通过vue视图进行展现,效果如下:
代码只展示主要功能代码,非完整实现
在created
生命周期内,向服务端请求数据。
获取到数据之后,因为拿到的数据和最终UI上显示的格式不一致,需要转化一下数据格式。
给当前Vue
实例赋值,然后在template
里通过模板语法进行渲染
可以看到常规写法,模板语法里面的写法特别不优雅,各种保护性代码(条件判断)
首先,我们可以专门建一个名叫model的文件夹,专门用来存放模型,然后定义卡片模型cardModel
,其中数据定义格式如下:
type
必填,用来描述该字段的类型,支持String、Number、Date等类型property
必填,数据路径,对应服务端数据结构的取值路径value
选填,数据默认值,可不填通过new Model()
进行初始化,后续只需要通过model.parse(data)
或者model.traverse(data)
这个两个方法就可以完成正向映射和反向映射的过程。
具体的使用方式可以查看API
通过axios请求接口,在拿到数据之后,调用parse
方法解析数据,在解析的过程中会去做赋值操作以及数据格式化。
拿到数据,赋值给vue
组件实例后,在template
模板里面直接使用我们事先定义好的数据字段,不需要再去写类似a&a.b&a.b.c
这样的代码,且不管服务端数据字段如何变化,视图渲染都不受影响,从而实现和服务端数据结构进行解耦。
与此同时,针对类似价格、时间等需要格式化的数据,我们可以直接使用,不需要再去写对应的格式化处理逻辑,从而专注于视图组件渲染处理。
通过引入数据模型,我们可以看到在模板里面引入变量的时候不需要进行各种判断,写法非常优雅,而且健壮性很强,即使服务端某个字段没有返回,我们这里也不会因此存在报错的可能性。且在脚本里面没有了数据格式化处理代码,从而不会因为数据处理逻辑代码可能存在的错误,打断UI的渲染。从而带来的更大好处是,随着项目的不断迭代,数据和视图有着清晰的划分,前端和后端进行了解耦,项目的可维护性得到保证。
在库里面,还提供了traverse
方法,和parse
方法类似,区别是traverse
是反向数据生成以及格式还原。
最后,我来讲讲这个数据模型库(ducker-model
)的实现原理,源码总共不到200行,还是简单的,可以通过这里下载查看,主要实现逻辑如下:
Model
的类。new Model(options)
,传入模型结构,初始化数据模型属性,对外主要使用的是parse
和traverse
方法,parse
方法的实现过程就是遍历模型数据结构,拿到每个属性的数据路径,然后根据这个路径去取传入的的数据里面的数据,最后给事先定义好的属性赋值,在赋值的过程中,可以根据type
格式化一些类似时间、价格类型的数据。traverse
方法刚好和parse
相反,同样是遍历数据模型结构,拿到每个属性的数据路径,然后根据这个数据路径去设置一个新对象的值,这期间,反向格式化数据类型,最后返回这个新对象。目前这个库还很基础,只支持了一些常规的功能,能做的事情还很多,比如:
watch
这个解析之后的数据,做到数据变动,视图变动呢?文章末尾会提供模型库下载地址,有需要的可以在此基础上进行扩展,欢迎一起完善这个库,另外,案例demo的地址也提供了,欢迎下载学习理解。
案例:ducker-model-demo
模型库:ducker-model
[1]
API: https://github.com/simplefeel/ducker-model
[2]
下载: https://github.com/simplefeel/ducker-model
[3]
ducker-model-demo: https://github.com/simplefeel/ducker-model-demo
[4]
ducker-model: https://github.com/simplefeel/ducker-model
推荐阅读