以正确的姿势实现一棵JavaScript菜单树
菜单树是常见的前端特效, 一般长下面这样
还有各种形态的变种, 有长这样的
也有长这样的
尽管这些菜单的相貌都不尽相同, 在功能实现的本质上却都是相同的。实现程序的大致流程如下
-
读取服务器端的菜单数据
-
将数据转换成html菜单结构
-
为菜单结构绑定各种交互事件,如展开、关闭等。
然而, 随着需求的变化, 菜单往往会需要一些基础之外的功能, 比如说添加菜单项、删除菜单项、修改菜单名、拖拽子菜单至其它父菜单项之下等, 实现这些额外的功能将增加菜单制作的难度。就拿添加菜单项这个功能来讲, 添加菜单项事件中代码的常规实现流程如下
-
为菜单的html结构添加一个菜单项元素结点并指定节点的名称
-
将菜单新节点数据添加至初始化菜单html结构的数据中
-
将新菜单的数据通过ajax发送至服务器端持久存储
删除菜单的流程亦如此
-
删除菜单中菜单项html节点
-
删除初始化菜单的数据中对应的数据项
-
将菜单的标识通过ajax发送至执行删除操作的服务器端程序
这种做法不能说有问题, 但是并不完美。 尤其是对于添加菜单项功能, 当菜单项添加完成时还需要为新添加的菜单节点绑定对应的事件 , 这不但使原本只需要3步的添加操作变成了4步, 还导致了代码逻辑的不一致、程序实现的复杂化,因为绑定事件这一步是重复的,在初始化菜单的时候执行过这项操作。 如何避免此类情况的出现呢? 其实并不难,换种思路即可。
拿添加菜单项这个功能来说, 我们完全可以使用3步操作来替代上面的4步实现操作
-
直接在菜单的数据源中添加菜单的数据项
-
重新渲染(初始化)
-
将数据发送至服务器端持久保存
这样做程序逻辑是不是清晰了很多, 而且渲染这个操作之前就已经实现了, 现在只需要拿来用就可以了,因此看似3步的操作实质上只有2步而已, 整个过程得到了极大的简单。 而且这种做法也适用于删除和修改两个功能项
删除操作
-
删除菜单数据中要删除的菜单数据项,并且重新初始化菜单
-
将数据保存至服务器
修改操作
-
修改菜单数据中的需要修改的数据项,并且重新初始化菜单
-
将数据保存至服务器
如你所见, 所有对菜单的修改操作只需要针对菜单的数据源就可以了, 对菜单html元素结构的操作都可以省略掉,因为这些功能都已经包含在初始化菜单的过程中了,完全没有多此一举的必要再去调用一遍。
这种做法看起来有一个坏处, 就是程序比较耗费性能, 因为每次对菜单的改动都会触发一次重新初始化菜单的操作。 事实上不必为此担忧, 首先现代的浏览器对于界面的渲染优化已至极致, 其次执行一次菜单初始化操作所占用的用户计算机资源消耗量几乎可以忽略不计, 对于用户体验更是完全没有丝毫影响 , 用户的感观能力远没有灵敏到可以感知如此微乎其微的变化。反而实现菜单代码逻辑复杂度的降低为程序员带来的好处却非常明显, 简化逻辑的好处从开发维护时间成本到程序员的编码体验都会有不同程度的体现。
前端和后端不同, 前端程序消耗的资源和运行程序的机器总是一对一的, 因此性能消耗只要不是太过分, 对于用户的影响不会很明显 ; 而后端程序消耗的资源和运行程序的机器往往是多对一的, 只有拼命的压榨程序的资源消耗才能降低服务器的负荷。
所以, 在开发前端程序的时候, 完全可以牺牲部分性能以达到程序逻辑的简化目的, 这是值得的。
知乎:https://www.zhihu.com/people/aspwebchh
github:https://github.com/aspwebchh
email: aspwebchh@gmail.com