本学期学校开设了开源这门课程,为了扩宽自己的知识面与技术栈我选择了滴滴的Dokit-Web方向,对源代码进行了阅读与分析
一、Dokit项目概述
Dokit是DoraemonKit的简称,意味着能够像哆啦A梦一样提供给他的主人各种各样的工具。Dokit是一个功能平台,能够让每一个 App 快速接入一些常用的或者你没有实现的一些辅助开发工具、测试效率工具、视觉辅助工具,而且能够完美在 Doraemon 面板中接入你已经实现的与业务紧密耦合的一些非通有的辅助工具,并搭配dokit平台,让功能得到延伸,接入方便,便于扩展。Dokit是一款泛前端的应用平台,包含了安卓、ios、小程序、Web、Flutter等多个平台的应用,并且可以实现跨平台的交流,为用户实现实现方便快捷的功能接口。
Dokit的主要功能可以总结如下:
1、DoraemonKit 能够快速让你的业务测试代码能够在这里统一管理,统一收口;
2、DoraemonKit 内置很多常用的工具,避免重复实现,一次接入,你将会拥有强大的工具集合;
3、搭配dokit平台,借助接口Mock、健康体检、文件同步助手让你方便和他人协同,极大的提升研发过程中的效率。
二、Web模块简介
Web模块是整个Dokit生态的重要组成部分,主要面向HTML页面实现一些功能接口,并且可以与移动端产生互联。主要的编程语言为前端的HTML、CSS、Javascript(JS),其中JS的主要应用是Vue3框架,可以负责实现网页中各种事件、组件、交互数据、通信跳转的实现与渲染;HTML与CSS主要负责网页的排版布局与美观设计。目前Web端主要覆盖了日志、接口抓取、视图元素查看、资源查看、应用存储、接口mock等。 各部分的基础功能与接近功能如下表所示:
表2-1 Web各部分功能简介
模块 | 日志 | 接口抓取 | 查看试图元素 | 资源查看 | 应用存储 | 接口mock | 基础功能 | - 支持所有的 `console` 方法 - 支持日志的筛选和清除 - 支持执行简易的 `javascript`命令 | - 支持抓取常用的接口类型 `xhr` 和`fetch` - 展示请求的详细内容 - 展示响应的详细内容 | - 展示整个页面的 `Dom`树 - 支持展开、关闭、选择(高亮元素) - 支持查看特定元素的内容 - 查看元素的样式 - 查看元素的盒模型 | - 展示`javascript`资源 - 展示`css`资源 - 展示`image`等媒体资源 | - 支持查看并修改`LocalStorage` - 支持查看并修改 `SessionStorage` - 支持查看 `Cookie` | - 支持无侵入式一键 Mock - 支持自动同步真实请求数据到平台侧,并与快速创建 | 进阶功能 | - 打通平台侧的日志查看,支持查看多个设备 |
---|
三、代码阅读工具
IDE:VS Code 1.54. VS Code是一个运行于 Mac OS X、Windows和 Linux 之上的,针对于编写现代Web和云应用的跨平台源代码编辑器,可在桌面上运行,并且可用于Windows,macOS和Linux。它具有对JavaScript,TypeScript和Node.js的内置支持,并具有丰富的其他语言(例如C++,C#,Java,Python,php,Go)和运行时(例如.NET和Unity)扩展的生态系统。VS Code也集成了所有一款现代编辑器所应该具备的特性,包括语法高亮,可定制的热键绑定,括号匹配以及代码片段收集, 也拥有对 Git 的开箱即用的支持。 操作系统:Windows 阅读方式:离线阅读,利用git将项目clone到本地,并且可以随时跟进项目的更新。
四、Web项目解析
4.1 整体结构
Web项目的主要结构如图4-1所示,readme文件是对整个项目的简要说明,主要介绍了每个模块及其功能,与前文类似;package.json和lerna.json文件主要说明了一些依赖库的版本说明;node_modules目录下是项目用到的底层支持库;packages是项目主要组成,关键的功能模块都打包在了packages目录下;playground相当于主程序或启动程序;script是一个js文件,用于项目运行时请求服务器。
4.2 主程序
主程序为index.html文件,是需要打开的主网页,主程序十分简洁明了,部分说明了编码形式与标题等主要内容,调用部分只有dokit.js文件,也就是各模块的所有功能都整合在了dokit.js文件中。
4.3 packages目录 前文说到,packages包含了Web项目的所有主要成分,其中又细分为三个模块:core、utils、web。其中core部分主要定义了网页需要的容器,比如框架、画布等内容,并且实现了容器之间的通信,以及路由管理;utils封装一些工具类,如对操作系统的区分,主要属于比较底层应用;web部分是网页层面的应用接口,也是顶层应用,比如前面提到的日志功能都来自web封装。使用这样三级模块,可以实现容器与应用的解耦,使得应用开发者可以专心设计应用对应的功能,而不需要过多的应用与容器的对接。本文将重点针对应用部分进行解析,因为剩余的课程项目也是围绕应用功能展开的。
4.4 Web模块
Web模块中主要实现了应用接口,在Dokit框架中网页中的应用功能可以与容器设定解耦,因此首先关注应用的实现。目前有三个比较简易的功能:hello world、应用信息展示、日志同步。这三个功能彼此独立,分开实现后绑定在统一容器内。
Hello World: 此功能最为简易,只需要在页面特定位置显示对应信息,并设置对应的风格,如字体大小颜色、对齐方式等。在语言分工上,html语言定义了网页中不同的div块,在此应用中主要是需要展示的文字,css代码定义了每个块的渲染风格,此例中为补齐长度和文字对齐位置
应用信息: 在展示应用信息,需要将对应信息绑定一个组件中,此例中为在common文件下的Card组件,Card组件只有一个Title属性。.dokit-card定义了Card组件的某些渲染特征比较明显的,将背景色设为了蓝色。组件的主要功能即为显示Title字符串。
与Hello World相比,应用展示功能需要获取数据,比如页面数据以及用户当前的设备数据,而这些数据可通过全局的window类中调用方法获取,也可以从document类获取窗口中的DOM元素element。 HTML 文档的主干是标签(tag),根据文档对象模型(DOM),每个 HTML 标签都是一个对象。嵌套的标签是闭合标签的“子标签(children)”。标签内的文本也是一个对象。所有这些对象都可以通过 JavaScript 来访问,我们可以使用它们来修改页面。
每个树的节点都是一个对象。标签被称为 元素节点(或者仅仅是元素),并形成了树状结构:<html>
在根节点,<head>
和 <body>
是其子项。元素内的文本形成文本节点,被标记为 #text。一个文本节点只包含一个字符串。它没有子项,并且总是树的叶子。例如,<title>
标签里面有文本 "About elk"。
应用信息主要分为“用户信息”和“设备信息”,这两个标题分别显示在前面所述的Card组件中;具体的数据呈现在html中的表格:
export default {
components: {
Card //Card作为当前Vue应用的一个组件
},
data() {// AppInfo 需要获取的数据
return {
ua: window.navigator.userAgent, //浏览器以及用户数据
url: window.location.href, //浏览器url地址
ratio: window.devicePixelRatio, // 页面放缩比例
screen: window.screen, //屏幕尺寸信息
viewport: {
width: document.documentElement.clientWidth, //屏幕用户使用范围宽度
height: document.documentElement.clientHeight //屏幕用户使用范围高度
}
}
},
}
<template>
<div class="app-info-container"> <!--绑定一级容器风格-->
<div class="info-wrapper"> <!--绑定二级容器风格-->
<Card > <!--将要显示的信息分别绑定在两个Card容器中,分别是页面信息和设备信息-->
<table border="1"> <!--用表格展示具体数据-->
<tr>
<td>UA</td> <!--表头:用户信息-->
<td>{{ua}}</td> <!--具体数据,用vue对象中data的对应变量ua绑定-->
</tr>
<tr>
<td>URL</td> <!--表头:url地址-->
<td>{{url}}</td> <!--具体数据,用vue对象中data的对应变量url绑定-->
</tr>
</table>
</Card>
</div>
console日志功能:
日志功能的内容,是可以在网页中显示控制台命令console.log中输出的数据,并且可以折叠/展开对应的标号与内容细节。与前面两部分相比,此部分内容略复杂,需要两个组件Detail和Logitem的支持。
其中Detail组件可以通过点击控制数据是否折叠,其中可折叠的类型有对象和数组,即可迭代对象:
const TYPE_CAN_FOLD = ['Object', 'Array']
Detail实例中只有一个unfold数据,用于控制是否折叠的转换,转换的触发发生在组件被点击时,即组件实例的@click事件绑定了一个方法unfoldDetail(),
data () {
return {
unfold: false
}
},
methods: {
unfoldDetail() {
this.unfold = !this.unfold
}
}
<div @click="unfoldDetail" v-html="displayDetailValue"></div>
Detail可以根据日志的数据类型显示不同的细节内容, Detail的关键在于自我的嵌套,这样可以实现可迭代数据的嵌套,如果日志中的数据本身属于不可迭代的类型,则直接显示数据内容,如字符串、整形数据等;如果是可迭代数据,利用canfold数据进行判断,则将数据再次封装为一个Detail组件,可以以树形结构展示迭代对象内部的细节。
export default {
components: {
Detail
},
<template v-if="canFold">
<div v-show="unfold" v-for="(key, index) in detailValue" :key="index">
<Detail :detailValue="key" :detailIndex="index"></Detail>
</div>
</template>
Logitem对应了每一条console.log的日志信息,将Detail作为一个子组件,并且可以展示日志细节。在默认情况下将以文本形式展示当前日志中每个元数据的内容,如果有可迭代类型将标明数据类型(object/Array),每条日志中的每个元数据又被封装成了detail,类似的定义了点击事件“toggleDetail”,决定是否展开/折叠事件。由于包含了子组件Detail,显示细节的任务又完全由Detail内部实现。
export default {
components: {
Detail
},
methods: {
toggleDetail () {
this.showDetail = !this.showDetail
}
}
<div v-if="showDetail">
<div class="list-item" v-if="typeof value === 'object'" v-for="(key, index) in value">
<Detail :detailValue="key" :detailIndex="index"></Detail>
</div>
</div>
console日志功能: 回到具体的日志功能,将Logitem作为子组件,需要把每条日志数据封装在一个Logitem中,并用一个loglist的数据存储每条日志
components: {
LogItem
},
data() {
return {
logList: []
}
},
调用生命周期中的created()方法,即在创建之后就可以随时绑定控制台中的console.log()中的内容。具体实现时,需要绑定全局窗口的window.console方法获取日志中的数据,并不对更新到自己的loglist属性中。
created () {
let self = this
let originConsole = window.console;
['log'].forEach(type => {
let origin = originConsole[type].bind(originConsole)
originConsole[type] = function (...args) {
self.logList.push(args)
origin(...args)
}
})
}
4.5 应用的封装
现有的三个应用彼此独立,在完成单独的功能设计后,需要将其视为三个独立的组件包裹成一个应用容器ToolsContainer。包裹时利用tabs数据储存所有的组件功能和提示名,用v-for遍历所有的应用组件,利用<keep-alive>
标签确定被激活的应用,在点击对应应用时,进行激活应用的动态切换。
components: {
ToolConsole,
ToolHelloWorld,
ToolAppInfo
},
data() {
return {
tabs: [{
component: 'console',
displayName: 'Console'
},{
component: 'app-info',
displayName: 'AppInfo'
},{
component: 'hello-world',
displayName: 'HelloWorld'
}],
currentTab: 'console'
}
},
4.6 web模块设计小结
由前面的解析可以看出,web应用层面的设计具有很强的层次结构,即上一层的功能仅需要对下一层进行封装,而不需要涉及更底层的模块调用,这在设计上逻辑层次非常清晰,使得模块之间实现解耦,这样可以更好的对单一模块进行优化,避免牵一发而动全身。以日志功能为例,单条日志内的每一条数据,如字符串、整数、数组、对象封装在Detail组件中,而一整条的日志封装在Logitem组件中,整体的日志功能可以以logitem为最小单位进行调用,而不需要再考虑更下一层的Detail; 更进一步的,基础功能的封装可以把单个功能单位(helloworld、应用信息、日志)进行组合,而不需要考虑每个功能内部需要的组件,这种层次结构,可简单的表示为下图:
五、实验验证
下面将项目运行从而更加直观的体验Web功能的设计
1.将项目从github上进行clone,按照DEVELOPMENT.md中的说明,在终端执行命令行npm run bootstrap 和 npm run dev:playground,可以申请网络服务打开页面,端口为http://localhost:3000/playground 目前界面比较简单,下方的图标即为功能入口
2.点击图标即可看到现有的功能,可以看到整个页面的容器框架可以分为标题栏、基础功能栏、平台功能栏和版本信息栏,由红色箭头指明,这些内容定义在了core文件夹下。在功能栏内部的容器时每个功能对应的bar,即为蓝框划定的图标,bar类同样属于core模块中定义的容器。
3.分别点击“基础功能”栏内的图标即可看到对应的应用页面,下图分别显示了Hello World、应用信息、日志功能的界面。Hello World页面比较简单只有标题文字;应用信息部分,红色箭头指向的蓝色标题框即为前文提到过的Card容器,蓝色箭头指向的表格为Card组件内部的表格标签
4.日志功能需要与网页控制台中的console.log进行交互,因此我们打开控制台利用函数输入一些数据查看效果,可以看到控制台中的信息可以重现在界面中,下方右图中的两行数据即为前文提到的logitem组件,点击可以触发事件,进行细节的展示,细节展示的功能即为Detail组件的功能,如蓝色箭头所指。
5.前文提到,Detail组件可以自我嵌套,从而实现可迭代数据的详细嵌套关系,我们在console中输入此类数据查看效果,此时从日志维度观察,界面中已经有了两条日志,也就是对应了两个Logitem组件,loglist数组中包含了两个元素。
在第二条日志中,输入了一个字符串“abc”、一个数组Array、和一个对象Object,每条数据成为了一个Detail组件,点击可以触发对应事件,查看详细的数据信息:而数组和对象本身又是可迭代数据,在Detail中被嵌套成了一个新的Detail,而Array中的第三个元素又是一个Array[3,4,5],它再次被嵌套成了一个Detail组件,因此可以不断点击组件查看数据内容,最终可以得到如下的效果:由此可以看到,通过嵌套Detail组件,可以以树形结构展示迭代数据的详细内容.
六、总结
Dokit的web项目主要由core、utils、web三部分组成,其中core部分主要实现了容器的定义和路由管理;utils部分封装了部分底层的应用接口;web部分定义了网页中的应用功能,这三部分实现了解耦,使得是实现页面功能时不需要过度考虑容器问题。我们重点针对网页应用部分,分析了现有的三个功能的设计框架思想,其中日志部分利用了嵌套组件,实现了可迭代数据类型的展开。整体上web项目的设计实现了层层递进,模块解离,这使得项目具有更好的可拓展性,也便于bug的定位与改进,这种代码设计风格值得学习与借鉴。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!