全国免费咨询:

13245491521

VR图标白色 VR图标黑色
X

中高端软件定制开发服务商

与我们取得联系

13245491521     13245491521

2024-07-14_Flutter TolyUI 框架#07 | 案例解析与管理

您的位置:首页 >> 新闻 >> 行业资讯

Flutter TolyUI 框架#07 | 案例解析与管理 《Flutter TolyUI 框架》系列前言:TolyUI 是 张风捷特烈 打造的 Fluter 全平台应用开发 UI 框架。具备 全平台、组件化、源码开放、响应式 四大特点。可以帮助开发者迅速构建具有响应式全平台应用软件: 开源地址:https://github.com/TolyFx/toly_ui image.png该系列将详细介绍 TolyUI 框架使用方式、框架开发过程中的技术知识、设计理念、难题解决等。 一、为什么需要解析管理TolyUI 中每个组件有若干个介绍的案例,随着组件的增加,介绍的节点的维护成了一个非常繁杂的事。如下所示,一个介绍节点包括 标题、介绍、代码、内容 四个部分: image.png1. 目前遇到的问题之前案例展示的信息内容通过 Map 对象进行维护,如下红框中是 BreadcrumbDemo1 的介绍信息。这种维护方式,任何部分的变更都需要及时同步,比如视图代码变化了,展示的代码信息如果没及时更新。使用者就会产生困惑: image.png靠手动来维护这些数据,正在变得越来越复杂。为了 TolyUI 更好的发展,我需要寻找一条可以自动解析和管理介绍文本信息的方式。也是文想要向大家分享的内容。 2. 解析和生成面对当前的维护困境,我给出的方案是: 解析文件 与 自动生成代码。首先需要明确,当前解析的目标以及想要生成的内容。解析的目标自然是对当前案例代码的介绍信息。自动生成的内容有三个部分: [1]. 之前手动维护的 displayNodes 将是生成代码的核心内容。放在 node.g.dart 文件中。[2]. 案例的展示代码属于大文本,并没有必要全部放入映射中占据内存。所以会将其抓取到 assets 资源文件之下,点击时按需加载。[3]. 案例最终想要以组件的形式展示在界面上,节点数据以字符串作为标识,通过 widget_display_map.g.dart 来维护标识与具体组件间的映射关系。image.png3. 注解与信息维护巧妇难为无米之炊 ,现在最重要的问题是:在哪里,如何向案例提供描述信息? 由于 Dart 即将支持宏编程,所以我决定采用 注解 的方式来维护某个案例的介绍数据。如下所示:@DisplayNode 是我自定义的注解类,包含标题和描述两个字段: image.png到这里,解析生成的路线基本就确定了: [1]. 遍历案例文件夹,当文件内容有 @DisplayNode 注解时,通过正则解析文件,收录数据。[2]. 通过解析收录的数据,操作文件生成对应代码。[3]. 解析过程中提取案例代码到资源文件。二、案例文件的解析逻辑NodeMeta 是解析过程中承载数据的核心对象,每个案例文件将解析成一个 NodeMeta 对象。其中变化代码字符串、案例文件路径、案例名称、展示信息四个数据内容: classNodeMeta{ finalStringcode; finalStringname; finalStringfilePath; finalDisplayNodedisplay; constNodeMeta({ requiredthis.filePath, requiredthis.code, requiredthis.name, requiredthis.display, 1. 提取案例文件信息拿上面的 CardDemo1 为例,该文件中已经包含了 NodeMeta 对象的所有信息数据。现在关键在于如何解析文本内容,生成 NodeMeta 对象。 image.png想要匹配文本中的关键信息,很容易想到可以使用 正则表达式 。比如想要抓取注解的字符串内容,可以通过 @DisplayNode(.|\s)*?\) 进行匹配: image.png抓取到 DisplayNode 配置的字符串之后,可以继续通过正则表达式来匹配对应字段的数据。如下所示,匹配其中 title 对应的字符串信息: image.png通过 class (?name\w+)(.|\s)* 匹配第一个以 class 开头的文字及其之后的所有字符串。并且 class 后的类名通过 name 组名获取: image.png2. 单文件解析类 DisplayFileParser一个园林中有很多树,想着为所有树木修葺是一件很复杂的事。但修葺一棵树就比较简单,而且修葺的任务是类似的工作,一棵修的好,那么其他的都只是时间问题。解析也是一样,一开始应该着眼于个体,做好第一个任务。 如下,定义 DisplayFileParser 类负责解析 path 对应的文件内容,通过 parser 方法异步解析,生成 NodeMeta 对象: classDisplayFileParser{ finalStringpath; staticfinalRegExp_codeRegex=RegExp(r'class(?name\w+)(.|\s)*'); staticfinalRegExp_displayRegex=RegExp(r'@DisplayNode(.|\s)*?\)'); constDisplayFileParser(this.path); FutureNodeMeta?parser()async{...} 在解析前,可以先基于一些既定规则,过滤一下不必要的文件读取和解析。比如这里所有的案例文件名都会包含 _demo 字符串。另外,读取内容中不包含 @DisplayNode( 的文件表示不需要解析。最终通过 _parserContent 方法处理具体的解析逻辑: FutureNodeMeta?parser()async{ if(!path.contains('_demo'))returnnull; Filefile=File(path); Stringcontent=awaitfile.readAsString(); boolhasDisplay=content.contains('@DisplayNode('); if(!hasDisplay)returnnull; return_parserContent(path,content); } _parserContent 方法中基于两个正则表达式匹配得到数据,从而创建 NodeMeta 对象。其中 DisplayNode.fromString 构造方法是基于字符串,来匹配创建 DisplayNode 对象: NodeMeta_parserContent(StringfilePath,Stringcontent){ RegExpMatch?codeMatch=_codeRegex.firstMatch(content); String?code=codeMatch?.group(0); String?name=codeMatch?.namedGroup('name'); String?display=_displayRegex.firstMatch(content)?.group(0); returnNodeMeta( filePath:filePath, name:name??'', code:code??'', display:DisplayNode.fromString(display??''), } 如下所示,这样就可以解析某个案例文件,通过正则匹配得到关键的数据内容: image.png3. 遍历解析与收集 NodeMeta 结果所有的案例代码都放在了项目中的 widgets 文件夹下,接下来需要遍历文件夹,来逐一解析内容。得到每个案例文件对应的 NodeMeta 数据集: image.png下面代码中,通过 parserDir 方法遍历一个文件夹中的文件,处理解析逻辑。并将解析的结果放入 displayMap 中。由于一个组件有若干个案例,所以这里通过 MapString, ListNodeMeta 记录一个组件对应的节点列表信息。解析完后,数据如下所示: image.pngvoidmain()async{ StringwidgetPath=path.join(Directory.current.path,'lib','view','widgets'); DirectorywidgetDir=Directory(widgetPath); MapString,ListNodeMetadisplayMap= awaitparserDir(widgetDir,displayMap); } FuturevoidparserDir(Directorydir,MapString,ListNodeMetadisplayMap)async{ ListNodeMetadisplays= ListFileSystemEntityentity=dir.listSync(); for(FileSystemEntityeinentity){ if(eisFile){ NodeMeta?ret=awaitDisplayFileParser(e.path).parser(); if(ret!=null){ displays.add(ret); ret.saveCode(); } }elseif(eisDirectory){ awaitparserDir(e,displayMap); } } if(displays.isNotEmpty){ displayMap[path.basename(dir.path)]=displays; } } 三、使用结果生成代码上面已经完成了对案例代码的解析,得到了所有期望获取的数据。接下来就是基于这些数据,创建并写入代码文件,完成案例代码的自动维护。 1. 代码生成的格式代码生成的核心是 node.g.dart ,其中 queryDisplayNodes 方法可以通过组件名称得到对应的案例列表数据。注意这里使用的是 switch 进行匹配,并不是将所有的数据通过 Map 全部加入到内存中。这种运行时的取用,可以降低内存的使用,特别是对于案例介绍这样的大量数据。 image.png另外,这里将每个组件对应的案例列表数据拆散成 独立文件。通过 part 和 part of 关键字建立文件间的关系。将独立文件在逻辑上视为 node.g.dart 的一部分。单独分离文件的目的在于:让代码逻辑结构更加清晰,另外,单个大文件在多人协作时更容易产生冲突。 image.png2.组件名到组件的映射在案例介绍的信息中,记录着 String 类型的案例组件名,但在展示时需要将组件名映射为具体的组件。由于解析过程中,所有案例的组件名都可以收集到,因此可以自动生成 widgetDisplayMap 的映射关系,将字符串映射为对应的组件: image.png在视图层的使用中,通过组件标识调用 queryDisplayNodes 查找案例信息列表。然后遍历列表,根据案例组件的字符串名称,基于 widgetDisplayMap 得到对应的组件: image.png3. 代码生成逻辑代码本质上也是字符串,基于解析得到的 displayMap 数据,我们可以通过字符串拼接得到代码字符串,然后写入到指定的文件中。这样就完成了用代码写代码的目的:通过 FileGen类来维护代码生成的逻辑,其中依赖解析后的数据对象 displayMap,通过构造函数传入: classFileGen{ finalMapString,ListNodeMetadisplayMap; FileGen(this.displayMap); 代码的生成听起来好像挺高大上的,但本质上也只是一个基于模版的填词游戏。如下是 node.g.dart 的文件模版,需要结合 displayMap 中的数据,将 part 和 content 的两处内容添到指定位置: StringnodeTemplate(Stringcontent,Stringpart){ return""" ///=================================================== ///PowerBy张风捷特烈---Generatedfile.Donotedit. ///github:https://github.com/toly1994328 ///=================================================== $part MapString,dynamicqueryDisplayNodes(Stringname){ returnswitch(name){ $content_={}, } """; } 其中的内容,只需要遍历 displayMap 映射元素,拼接呈成目标字符串即可。如下代码在 nodeParts 和 nodeContents 分别表示 node.g.dart 头部引入的部分和中间的具体内容字符串列表。生成代码字符串之后,写入对应文件中,将完成代码的生成任务: FuturevoidgenNode(StringoutPath)async{ ListStringnodeParts= ListStringnodeContents= Filefile=File(outPath); displayMap.forEach((k,v){ MapString,dynamicitems= nodeParts.add("part'$k.g.dart';\n"); nodeContents.add('"$k"=_${k}Data,\n'); ///... Stringcontent=nodeTemplate(nodeContents.join(),nodeParts.join()); awaitfile.writeAsString(content); } 单个组件对应的节点列表文件也是类似,定义模版之后,遍历映射关系,向其中插入期望的字符串,得到代码: image.pngStringsingleNodeTemplate(Stringcontent,Stringname){ content=content.replaceAll(r'$',r'\$'); return"""///=================================================== ///PowerBy张风捷特烈---Generatedfile.Donotedit. ///github:https://github.com/toly1994328 ///=================================================== partof'node.g.dart'; MapString,dynamicget_${name}Data=$content;"""; } 4. 基于命令行工具使用生成器到这里,已经完成了解析和代码生成的逻辑,以后任何的代码或描述信息的改动,或者新增组件案例介绍。只要运行一下工具就可以自动生成代码,同步所有的更新内容。从而大大简化了书写和维护案例介绍的 劳动成本。 虽然现在已经挺好用了,但是作为 dart 文件来执行会比较麻烦,还需要手动点击运行。期间的编译、运行会耗个十几秒,也不是非常优雅。 之前在 《Flutter 知识集锦 | Dart 开发命令行工具》 一文中介绍过,Dart 文件可以作为打包为命令行工具,进行使用。所以为了更好地使用工具来生成代码,我将这个代码解析生成器集成到 toly 命令行工具中: image.png也就是说,当案例信息有任何变化,我只需要在命令行输入 toly ui ,就可以在 100ms 内完成代码生成来更新所有的案例信息。 image.png工具可以让人从枯燥的繁杂任务中解脱出来,特别是重复性的有明确规则的任务。联合收割机、卡车、电饭锅,优秀的工具能更精准、迅速且正确地完成特定任务,从而可以大大提升生产的效率。希望 tolyui 中对于案例的解析管理,能让你对工具的使用有所启发。那本就到这里,谢谢观看 ~ 四、小结到这里 TolyUI 就完成了一个可以灵活定制的下拉菜单 TolyDropMenu。目前为止,TolyUI 已经完成了响应式布局和反馈模块的核心功能。导航模块也完成了三个非常重要的组件,下一步会继续对导航模块进行开发,敬请期待 ~ image.png感谢你关注 tolyui 的成长,如果喜欢,也希望你能在 github 中点赞支持~ github 开源地址:https://github.com/TolyFx/toly_ui TolyUI 官方案例演示网站:http://toly1994.com/ui

上一篇:2023-07-31_海底捞演唱会抢人、望山楂猛男诱惑...瓜不能停 下一篇:2020-09-14_拿下威尼斯金狮奖的赵婷,会成为下一个李安吗?

TAG标签:

18
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设网站改版域名注册主机空间手机网站建设网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。
项目经理在线

相关阅读 更多>>

猜您喜欢更多>>

我们已经准备好了,你呢?
2022我们与您携手共赢,为您的企业营销保驾护航!

不达标就退款

高性价比建站

免费网站代备案

1对1原创设计服务

7×24小时售后支持

 

全国免费咨询:

13245491521

业务咨询:13245491521 / 13245491521

节假值班:13245491521()

联系地址:

Copyright © 2019-2025      ICP备案:沪ICP备19027192号-6 法律顾问:律师XXX支持

在线
客服

技术在线服务时间:9:00-20:00

在网站开发,您对接的直接是技术员,而非客服传话!

电话
咨询

13245491521
7*24小时客服热线

13245491521
项目经理手机

微信
咨询

加微信获取报价