原项目为第四届字节跳动青训营前端进阶版项目,我小组历时3周完成这个零组件库的Win11 In Vue
的开发,作为主力开发人员,我贡献了约 3 / 5
的commit。
偶然回省代码,觉得某些地方写的并不好,比如内容写的比较死;代码重复量高、复用性差;没有过多考虑性能等客观因素;组件注册方式死板丑陋....。
因而想要对此进行重构,吸取先前教训。
- 代码会尽量以
OOP
+FP
编程范式叙写逻辑。 - 系统由单系统过渡到
monorepo
,模板依赖于我的cli
搭建 - 注重分包,删除无意义冗余文件分层
- 注重通用性,减少重复代码的书写,可以实践
HOC
orHOF
提高复用性 - 编写过程中,思考数据流向,拒绝无意义重复数据输入,及时察觉错误数据传递,以数据流向作为组件乃至文件分包分层的导向依据
Vite
Typescript
Vue3
Pinia
VueRouter
应用注册方式变为手动导出自动注册,通过scheduler/apps
导出你所需要的 packages/app
中的应用,第三方开发者只需要在其中编写应用即可。
理论上:第三方开发者完全可以采用npm
第三方发包的方式进行应用的插装,你只需要在scheduler/apps
中简单的import
一下就可以使用,系统会提供一些数据,通过provide
依赖注入形式,注入到第三方编写的组件中,更多组件编写规则,请参考app
开发规范组件编写规范
导出的组件会由统一调度器Scheduler
进行管理,因此在Root(View/Home)组件的创建初期,对Scheduler
进行初始化和挂载。通过调度器中的信息,而后对这些组件进行处理即可,最后处理的结果就是一个组件数组。因此,系统会直接遍历进行挂载即可
{Object.keys(Applications).map((key, idx) => {
var WinApp = Applications[key];
return <WinApp key={idx} />;
})}
-
组件应该伪挂载,在不需要出现的时候不应该被渲染,否则毫无疑问这会拖垮首屏渲染,因此需要对未出现的组件统统remove,不渲染进
dom tree
-
将所有的组件和
taskBar
做联动,当点击的时候控制对应的组件显现。通过nomalize HOC
实现,也就是说所有的应用其实都是要通过HOC
做处理的,这样这个组件就会被HOC
所管理,每个组件都会开启一个新的HOC
,因此他们之间互不干扰
- 组件最小化不应该进行隐藏,而是隐藏层级,因为频繁的触发
display:none
会引起性能问题 - 组件关闭需要考虑是否进行
display:none
,因为关闭后可能短时间内不会再次打开 - 组件关闭最小化与否通过调用
scheduler
的方法实现 -
TODO
:ToolBar
作为公共组件,为了更好的维护性应实践OOP
的开发方式,因此接下来的工作会着重于refactor ToolBar component and optimization it
单纯依靠对象的引用特性难以达成需求,如果依靠响应式那么如何将
scheduler
数据流向全局?
- 如果采用
props
那就意味着需要对所有的组件进行改动,这显然违背开闭原则 - 如果采用依赖注入的方式依然可以实现跨组件共享数据,同时可以确保所有组件都能够正常接收,因为他们同属于一个依赖链,但是性能负担较大,如果大规模组件存在,难以保证性能。
- 这里的性能负担指的是,同一数据要被顶层
App
的自己组件也消费,这样注入的依赖深度就可能会不止3层(依赖注入3层以上的传递可能会造成严重的性能问题) - 因此不确定性就是不稳定的因素。但是如果要作为系统与应用间的数据共享,是一个很好的选择,因为这既打通了系统间的沟通壁垒,又能将数据流向控制在顶层依赖链中,但是这需要开发者自行遵守
- 这里的性能负担指的是,同一数据要被顶层
- 采用
store
方式可以实现跨组件间共享数据- 注意这里说的跨组件应用传递指的是系统中,包括系统的内置
baseComponent
是根据状态管理工具进行数据共享的。 TODO
:App
级的应用,初步还是想依赖于依赖注入。
- 注意这里说的跨组件应用传递指的是系统中,包括系统的内置
-
底部栏根据你的配置决定是否固定 通过
Scheduler
-IsFixTaskBar
实现 -
底部栏要联动桌面 通过HOC
实现 -
taskBar
还需要考虑当前打开的app
是否是taskBar
固定的,如果是固定的就原地打开即可,如果不是就末位打开,按照时间戳排序(UI层消化) -
ToolsBar
联动pinia.components
实现层级切换,这就需要组件具备自治能力,因此在此采用OOP
建立自定义组件类是最佳实践
taskbar
同步消费currentShowTaskbar
,数据按照时间戳进行排序
desktop
要消费scheduler.components
数据,可以直接消费pinia
的components
即可
做到多向联动性是系统互联的基础
因为如果TaskBar
继续采用HOC
方案,那么目标应用在开启的时候需要打开两次,这不是一个好的结果
我的思路是仍然保留scheduler
方案,HOC
方案也可以继续得以保留,因为以HOC
方案做组件的管理要更加单一化细粒度,各HOC
各司其职
那么就需要taskBar
做出让步,因此taskBar
的渲染方案并不是继续采用HOC
方案,而是自己渲染出一套icon
来
通过各组件自行管理的方式导出CustomComponent
类实例,其内置组件信息,taskBar
可基于此对其进行渲染
想起来很简单,因为如果是正在显示的话,一定是存在于currentShowComponent
中的,如此一来,我需要在taskBar
中做出操作
要分为不同的考虑方式
taskBar
的显示数据源分为两个部分:fixTaskBarComponent
和currentShowComponent
因此需要考虑:
- 如果是
fixTaskBarComponent
的任务显示无论order
与否都是原地显示的 - 如果不是
fixTaskBarComponent
中的任务显示就需要根据order
进行排序,order
越小距离左侧越近(这个地方写死还是做动态化需要考虑)
因此渲染还需要依赖于currentShowComponent
,对于隐藏(非关闭)的组件来讲,它仍然还存在于currentShowComponent
中,因此这个时候需要根据isHide
判断(需要分区域考虑了)是否隐藏,对当前显示的和隐藏的内容所应用的类是不同的比如显示的是长蓝色条,隐藏的是白色的条
因此在components/taskbar.vue
的computed
阶段就需要进行划分了,将不是fixTaskBarComponent
的任务划分出来,这部分是需要用order
排序的(这个保留与否有待思考,因为感觉不太美观)
只要不是fixTaskBarComponent
的内容就直接根据isHide
处理就好了
-
先抛出问题:自定义应用如果需要
store
或者其他数据
进行第三方app间联动,这如何实现?这需要一步步思考为何需要这样,这样的应用场景有哪些举例证明一下;如何做到跨应用数据共享,如何做到跨应用数据变动....
如何组件间共享数据,我相信方案绝对不止一种,包括上面思考的三种实现方式:
props
、store
、provide
之外肯定还有能够实现的方案。不过不论哪种方案来讲,都需要遵守以下的原则:- 是否遵守合理安全的数据流向
- 代码可访问安全性:(不能将全部的隐私数据开放给用户)
- 代码复杂程度,数据流向复杂程度
- 。。。。
- 对于
props
来讲,我觉得并不是一个好的选择,尽管你可以自定义选择是否接收props
,但在组件的挂载初期,要将中心放在这上面,并且不能实现第三方的数据插入到另一个app
的props
上 - 对于
store
来讲,要思考是否具有必要性,因为这会另引入新包,并且尽管可以由app
自定义store
数据,那么这个store
的引入就必需通过core
repo
某个文件导出三方app
的store
或者,第三方的app
直接引入另一个app
的store
这你觉得好吗?
所以最佳的方案我认为还是
依赖注入
的形式,应用可以方便的引入其他app
暴露的数据,只需要简单的inject
一下,便可以拿到你想要的数据。同时在组件的挂载时期,需要遍历待挂载的组件,检测到有暴露的数据就将其provide
即可,由于组件最终是需要挂载到core/Home/index.vue
中的,因此就能实现所有的组件数据共享。不过要想达成这一点就需要修改CustomComponent
同时需要更新HOC
的逻辑。不过在编写的时候应当注意以下的事项
provide
的名字需要标明组件名称,用户自定义数据名,以下划线分割,如:Folder_FolderData
,用户在使用的时候需要标明,以防混淆,因此数据的名称需要在注册期做正则判定- ....
待续....