
XD实习总结
建站器部分
总共有4次merge,分别是不同的功能实现
第一次merge(fix: 修复跨页面粘贴节点和属性)
简单说一下
主要是修复跨页面粘贴节点和样式的bug,这里原本的实现逻辑是通过将节点对象和样式对象存储到localstorage中,这样其他页面也可以读取到需要被粘贴的值。但是这里存在一个问题,右键菜单的粘贴选项的可用状态是通过一个状态进行控制,这个状态只有在本页面中触发过复制之后才会被更新为可用,这就导致了如果在页面A进行了复制操作,但页面B是无法及时更新可用状态的。只能通过在页面B额外进行一次复制,触发粘贴可用状态的更新,这样才可以正常的跨页面复制。
这种操作体验是不符合预期的,所以我对这里进行了修复。
我的实现思路总共有两个:
设置一个对localstorage的监听器,如果localstorage(也就是剪贴板)发生了变化,那么就通知粘贴可用状态进行状态更新,这样每个页面都能相应复制的变化。
在每次触发右键菜单的时候,读取localstorage中的内容,如果存在内容,那么就将粘贴可用状态进行更新。
最后选择了第二种解决方案,因为在和mentor讨论之后,它认为额外增加新的监听器对内存不利,而且复制粘贴的操作并不是非常频繁,在右键的时候再去更新状态会更好一些。
学到了什么呢
感觉感悟最深的东西就是关于localstorage的应用,给我的理解就是,在前端的客户端渲染中,也就是大部分逻辑在客户端处理的时候,localstorage可以去支撑很多功能的实现(例如这种剪贴板、偏好设置的存储、又比如在视频网站中可以存储历史观看记录等不敏感的数据),需要学会善用。
提交记录
第二次merge(feat: 增强事件编辑器搜索功能)
简单说一下
我给建站器输送的代码的思路一直都是在实际使用中,如果遇到了哪些让自己非常难受的功能,而且这些功能不太涉及底层设计,那么我就会去研究一下去修改。
这次的事件编辑器,也就是利用blockly实现的一个js事件块编辑器,基本的功能已经实现的很完备了,但是依旧有一个功能让我觉得比较难受,就是工作区的搜索功能。
针对平时的使用,我主要做了下面的修改和完善:
优化搜索框
这里做的主要优化有:
为搜索操作按钮添加激活态背景色,以提供更好的视觉反馈。
在搜索栏内设置默认占位文本,以提升用户指引。
这里第一个激活背景色,就是因为在点击搜索框中的按钮的时候,它没有一个很好的反馈,导致不确定是不是真正点下去了,再加上当时没有搜索计数器,而且这个搜索插件的切换是直接将目标快放置到中间,这样就更不知道是不是切换了搜索项。
第二个是个小问题,主要是当时引入搜索插件的时候,没有改搜索框默认的placeholder。
添加搜索计数器
这里主要就是一点:显示当前搜索结果索引及总结果数
因为就像在上一项说的一样,没有这种统计信息,让人非常迷茫,甚至不知道搜索到了多少,目前在第几个结果。现在很多带搜索功能的编辑器都会默认存在这个显示标记,做为一个官方的搜索插件,没有这个功能是让人非常不能理解的。
这里的实现没有什么好说的,主要就是通过继承原插件,扩展一个新的类,在新类的基础上扩展开发,维护了一个搜索总数和当前索引的状态,在切换当前搜索结果的时候去更新状态。
功能优化
主要有两个方向的功能优化,一个是键盘操作相关,一个是搜索蒙版。
首先来说键盘操作,添加了键盘导航,也就是上下箭头切换搜索结果,另外就是ctrl+F的快捷键来开关搜索框,之前只能通过右键打开搜索框,及其不方便。这里的上下箭头导航,我记忆里是vscode或者chrome的搜索带有的功能,可是我回过头去用,发现vscode和chrome都没有这个功能。但是实际体验中,尤其是在调试的环境中,直接使用键盘切换,舒适感是更好的。
下面来说搜索蒙版,说到这个要来了解一下blockly事件块,它主要是由很多五颜六色的事件块组成,也就是说传统编辑器中的底色高亮和字体变色的方案是不太合适的,不美观且不够明显。
而这个搜索插件默认的高亮效果,是将当前搜索结果块设置为灰色,而其他搜索结果设置为黑色。这真的很反直觉,因为在正常的逻辑中,颜色较深的应该是目标块,所以我把它们的颜色给反转了。
但即使这样,眼睛还是无法快速的定位到目标快,因为相对于黑色,其他事件块的颜色实在是太鲜艳了,导致在一堆鲜艳的颜色中去找到黑色还是很费劲。
所以我参考了一下一个官方插件:
https://github.com/google/blockly-samples/tree/master/plugins/content-highlight
这个插件的作用是通过一个蒙版去高亮内容区域,简单的理解就是显示能最小的可以框住所有工作区中事件块的矩形区域,可以看下面的图,一看就明白。
那么我可以参考这个插件的实现逻辑,在搜索插件中复刻,其实主要的区别就是我需要绘制的矩形区域应该是我目标搜索结果的区域,那么其实大部分逻辑可以不用动,只需要得到目标块区域并且绘制就可以了。
那么依据这个思路,最后实现出的效果大致如下⬇️
同时还有一些小细节,就是在拖动任意事件块的时候,蒙版会暂时消失,等停止拖动之后再重新出现。
其他优化
这里没有什么大的更改,主要就是优化了再次打开搜索框后,框内内容保存上次搜索内容,主要因为这个插件在定位搜索结果的时候会强制把视口定位到目标块,如果想要调试,应该会关闭搜索框,这时候可能会丢失定位。
学到了什么呢
这里是第一次接触到了blockly事件块,所以主要学习到的还是关于blockly事件块的各种知识,了解了事件块是怎么从这些图形转换到了js代码,又是怎么将这些内容进行序列化之后存储到服务器的。
具体上来说,就是对设计模式的理解更加深入了,主要是体现在集成菜单选项的时候,这种配置+分发任务来更新状态的方式对我来说比较新颖,在之后其他的项目中也是很好的借鉴。
除此之外,这次之后对js的熟练程度比之前要高了许多,直观感受就是越来越像一个工具了。
同时还对前端工具链的理解也更深入一些,因为这个项目是基于vue2和vuex,都是比较老的一些架构了,但其实大部分的开发主要集中在js上,如果着重动画和显示效果,那么就是css和js左右开弓,框架的影响会变的更小,基本上框架所负责的功能就是对虚拟dom节点的管理和渲染,尤其是到一个项目基本成型的时候,主要的开发重点还是在js。所以对于我的感悟就是,框架可能会很多很繁杂,但是全部都是基于html+css+js这个壳去构建的,无论使用什么框架,最后还是要回到这三部分上来,而在这三者当中,js是最重要的那部分,无论是业务还是性能优化都离不开它。
就比如这次的开发中,基本上一直在写js,因为想这种库,基本上都是实现出挂载到dom,主要的逻辑部分都抽象成了js,实际开发中也是这样,不可能将某个功能跟vue或者react的特性强绑定,那么做的话通用性就太弱了。
最后的最后,我还意识到做前端,有很多时候需要站在产品的角度去思考问题,前端的页面是与人沟通的门户,视觉反馈和操作逻辑都是影响产品体验的很重要的组成部分。
提交记录
第三次merge(虚拟视口/迷你地图/优化搜索/优化事件块反序列化速度)
简单说一下
这次的内容比较多一下,简单概括一下的话,就是修复了之前加入搜索新功能的bug,优化了一些显示。然后就是通过实现了虚拟视口来优化大量事件块的工作区的操作流畅性,并且优化了工作区从json加载事件块的速度。
下面分条详细说明:
fix:
修复关闭搜索框事件块颜色覆盖问题
之前蒙版的实现是参考了官方的‘内容高亮’的插件,因为那个插件高亮区域是整个内容区域,所以不会存在蒙版高亮块边缘被事件块遮挡的情况,所以他把高亮矩形的svg元素放到了整个画布的最底层。
但是这种实现方式在我现有的逻辑就会遇到问题,就是高亮块会被上层的事件块遮挡边缘,这样就会出现实际已经高亮了,但是被挡住看不到的情况。
所以我重写了这里的逻辑,让蒙版元素放到最上层,这样就不会被遮挡住了。
minimap增加销毁清除机制,优化可见性控制逻辑
迷你地图是这次新增的工作区插件,也是对它进行了继承重写,加入了dispose销毁机制,这样它的内存销毁会被blockly接管,在切换工作区的时候会自动销毁相应dom和监听器来释放内存。
优化Blockly视窗管理器,移除不必要的调试矩形和滚动位置记录,改进高亮选择逻辑以防止阻塞viewportchange事件
这里算是修一个bug,也是之前优化搜索高亮时候残留的bug,在新增的虚拟视口和之前的搜索插件结合的时候,搜索结果切换的时候不会触发viewportchange事件,导致新视口的事件块无法正常显示。
优化事件块从JSON反序列化速度
在进入一些事件块较多的事件块的工作区的时候,因为事件块太多,而blockly默认的加载逻辑是递归创建元素,而每次创建元素都会触发大量的无效事件,并且还会将添加操作装入回退栈。这些都是大量的内存浪费,尤其是其中有些事件会触发布局的重新计算,如果有1000个事件块,那就要重新计算1000次,浪费了大量的加载时间。
所以我选择关闭了部分事件的发送,并且关闭触发布局重新计算,并且引入文字宽度计算缓存,也能一定程度避免渲染文字的时候的重复计算,大概优化了30%的加载速度。
feat:
增强工作区高亮效果,调整高亮元素的透明度和颜色,优化块的尺寸获取逻辑
这个修改的主要内容就是调整了一下蒙版的样式,让高亮区域更加明显一些,另外就是之前的块的边界的计算逻辑是连带着目标块所连接的所有块的一整个大块的边界,这样不太好精确定位,所以更改了计算边界的逻辑,让计算出来的边界具体到单独块。
添加迷你地图插件,优化工作区布局,更新相关样式
主要是调整了迷你地图的显示位置,因为目前工作区的其他插件已经占据了四个角中的位置,所以调整了它的默认位置,并且加入了一些显示隐藏的过渡动画效果。
添加迷你地图显示选项,更新相关组件和状态管理
向菜单项中添加开关选项。
添加虚拟化视窗管理器,优化大块数量处理逻辑,更新迷你地图插件初始化
这里是实现的一个主要优化项,因为在一些较多事件块的工作区中,如果你对事件块进行编辑、移动等操作,都会触发整个工作区对于事件块布局、位置、图形等的重新计算,而且由于工作区渲染的机制导致,会触发事件块的大量重绘,这导致即使你的缩放比例特别大,视口内的事件块很少,但依旧阻止不了视口外的事件块重绘,让操作体验很不好,非常卡顿。
所以这里想到了之前看到过的虚拟化视窗的概念,我维护了一个可绘制的事件块的集合,这个集合是保证出现在视口内的,当视口发生变化时,重新计算哪些事件块离开了视口,哪些事件块加入了视口,对加入视口的事件块进行显示,离开的则隐藏。由于利用了哈希集合,查找速度可以降到O(1),所以对速度提升较大。另外,为了保证操作的连续性,还给显示区域加入了内边距,通过显示更大的区域的事件块,让显示隐藏的流畅程度更高,避免空屏的情况出现的频率。
最后经过实际测试,这种方法确实可以大幅提升操作的流畅性,尤其是在一些事件块较多的工作区,开启后的体验提升非常明显。
添加视口虚拟化选项,更新状态管理和事件编辑器逻辑,优化视窗管理器初始化条件
向菜单中添加开关选项和优化初始化条件。
学到了什么呢
在这次的修改过程中,为了去优化加载速度,实现虚拟化视口,不光要利用chrome的performance工具进行大量的性能指标的测试,还需要大量查阅blockly的官方api,来找到突破口。之前是不太会运用performance这个工具的,只会简单的LCP,FCP等指标的测试。这次之后,我也能很熟练的去利用这个工具进行性能测试的调优,并且能通过堆栈定位到影响性能的原因。
另外就是对blockly的实现机制和api也更加熟悉,我相信以我现在的熟悉程度,应该能很好的胜任绝大多数的blockly二次开发。
同时,也通过虚拟化视口的实践,让我对这个技术的理解更加深入了一些,也利于后面我将同样的思想套用到其他的场景上。
提交记录
第四次merge(fix(): 修复变量输入失焦问题,修复默认关闭闪一下的问题)
简单说一下
这一次的merge内容就很简短了,主要是为了修复一个比较影响使用的bug。就是在事件块中输入变量名,或者函数名的时候,只要输入一个字符,输入框就会自动失焦,不能连续输入。在仔细排查之前我怎么想不到,我提交的代码能影响到这一功能,因为变量和函数的功能是利用了插件来实现,我所提交的代码没有对这一块代码进行任何修改,但事实上确实是因为引入了迷你地图这个插件之后,影响到了这里的功能。
仔细排查之后,发现原因是因为迷你地图这个插件的绘制逻辑没有做好,导致了它和变量插件的不兼容。
插件的实现依赖一个主要函数‘mirror’来将工作区的状态‘镜像’到地图中,但它似乎考虑的不够周全,他会重放镜像所有的事件,所以输入事件也是其中一个事件,这其实没有什么,但他会在每次重放事件之后,调用finishQueuedRenders来结束blockly 的排队渲染,这就导致了输入框失去焦点,这其实是不合理的,所以我加入了一些逻辑来避免这种情况的出现。
学到了什么呢
这里主要学到的内容就是,在功能上线之前最好做好边界测试,但还是会有一些意向不到的情况出现,所以如果真的是很重要的功能,完整详尽的测试是非常有必要的。