菜单树是常见的前端特效, 一般长下面这样

还有各种形态的变种, 有长这样的

也有长这样的

尽管这些菜单的相貌都不尽相同, 在功能实现的本质上却都是相同的。实现程序的大致流程如下

  1. 读取服务器端的菜单数据

  2. 将数据转换成html菜单结构

  3. 为菜单结构绑定各种交互事件,如展开、关闭等。

然而, 随着需求的变化, 菜单往往会需要一些基础之外的功能, 比如说添加菜单项、删除菜单项、修改菜单名、拖拽子菜单至其它父菜单项之下等, 实现这些额外的功能将增加菜单制作的难度。就拿添加菜单项这个功能来讲, 添加菜单项事件中代码的常规实现流程如下

  1. 为菜单的html结构添加一个菜单项元素结点并指定节点的名称

  2. 将菜单新节点数据添加至初始化菜单html结构的数据中

  3. 将新菜单的数据通过ajax发送至服务器端持久存储

删除菜单的流程亦如此

  1. 删除菜单中菜单项html节点

  2. 删除初始化菜单的数据中对应的数据项

  3. 将菜单的标识通过ajax发送至执行删除操作的服务器端程序

这种做法不能说有问题, 但是并不完美。 尤其是对于添加菜单项功能, 当菜单项添加完成时还需要为新添加的菜单节点绑定对应的事件 , 这不但使原本只需要3步的添加操作变成了4步, 还导致了代码逻辑的不一致、程序实现的复杂化,因为绑定事件这一步是重复的,在初始化菜单的时候执行过这项操作。 如何避免此类情况的出现呢? 其实并不难,换种思路即可。

拿添加菜单项这个功能来说, 我们完全可以使用3步操作来替代上面的4步实现操作

  1. 直接在菜单的数据源中添加菜单的数据项

  2. 重新渲染(初始化)

  3. 将数据发送至服务器端持久保存

这样做程序逻辑是不是清晰了很多, 而且渲染这个操作之前就已经实现了, 现在只需要拿来用就可以了,因此看似3步的操作实质上只有2步而已, 整个过程得到了极大的简单。 而且这种做法也适用于删除和修改两个功能项

删除操作

  1. 删除菜单数据中要删除的菜单数据项,并且重新初始化菜单

  2. 将数据保存至服务器

修改操作

  1. 修改菜单数据中的需要修改的数据项,并且重新初始化菜单

  2. 将数据保存至服务器

如你所见, 所有对菜单的修改操作只需要针对菜单的数据源就可以了, 对菜单html元素结构的操作都可以省略掉,因为这些功能都已经包含在初始化菜单的过程中了,完全没有多此一举的必要再去调用一遍。

这种做法看起来有一个坏处, 就是程序比较耗费性能, 因为每次对菜单的改动都会触发一次重新初始化菜单的操作。 事实上不必为此担忧, 首先现代的浏览器对于界面的渲染优化已至极致, 其次执行一次菜单初始化操作所占用的用户计算机资源消耗量几乎可以忽略不计, 对于用户体验更是完全没有丝毫影响 , 用户的感观能力远没有灵敏到可以感知如此微乎其微的变化。反而实现菜单代码逻辑复杂度的降低为程序员带来的好处却非常明显, 简化逻辑的好处从开发维护时间成本到程序员的编码体验都会有不同程度的体现。

前端和后端不同, 前端程序消耗的资源和运行程序的机器总是一对一的, 因此性能消耗只要不是太过分, 对于用户的影响不会很明显 ; 而后端程序消耗的资源和运行程序的机器往往是多对一的, 只有拼命的压榨程序的资源消耗才能降低服务器的负荷。

所以, 在开发前端程序的时候, 完全可以牺牲部分性能以达到程序逻辑的简化目的, 这是值得的。

以正确的姿势实现一棵JavaScript菜单树的更多相关文章

  1. xpath轴的正确使用姿势

    网上看了许多关于轴的介绍,只介绍了语法,而没有明说具体实际中该怎么使用,百思不得其解. 背景--python中使用xpath:  ----------------------------------- ...

  2. 高版本jquery尤其是1.10.2的版本设置input radio设置值的最正确的姿势。

    $("input:radio[name="analyshowtype"]").attr("checked",false); $(" ...

  3. NSnotificationCenter 正确使用姿势, removeObject 探索

    最近在做平板的过程中,发现了一些很不规范的代码.偶然修复支付bug的时候,看到其他项目代码,使用通知的地方没有移除,我以为我这个模块的支付闪退是因为他通知没有移除的缘故.而在debug和看了具体的代码 ...

  4. 微信H5中静默登录及非静默登录的正确使用姿势

    在微信中打开网页且需要调用微信登录接口时,微信官方给我们提供了两种登录调用方式:静默登录和非静默登录:但是官方文档中却没有说明在何种情况下使用静默登录,何种情况下使用非静默登录,所以在这里,我想将之前 ...

  5. Java日志正确使用姿势

    前言 关于日志,在大家的印象中都是比较简单的,只须引入了相关依赖包,剩下的事情就是在项目中“尽情”的打印我们需要的信息了.但是往往越简单的东西越容易让我们忽视,从而导致一些不该有的bug发生,作为一名 ...

  6. MongoDB系列:五、MongoDB Driver使用正确的姿势连接复制集

    MongoDB复制集(Replica Set)通过存储多份数据副本来保证数据的高可靠,通过自动的主备切换机制来保证服务的高可用.但需要注意的时,连接副本集的姿势如果不对,服务高可用将不复存在. 使用复 ...

  7. 基于winserver的Apollo配置中心分布式&集群部署实践(正确部署姿势)

    基于winserver的Apollo配置中心分布式&集群部署实践(正确部署姿势)   前言 前几天对Apollo配置中心的demo进行一个部署试用,现公司已决定使用,这两天进行分布式部署的时候 ...

  8. 玩转java多线程(wait和notifyAll的正确使用姿势)

    转载请标明博客的地址 本人博客和github账号,如果对你有帮助请在本人github项目AioSocket上点个star,激励作者对社区贡献 个人博客:https://www.cnblogs.com/ ...

  9. Gradle的依赖方式——Lombok在Gradle中的正确配置姿势

    写过java的都知道,lombok几乎在项目中处于不可或缺的一部分,但是lombok在Gradle的项目中配置并非人人都知道. 很多人在项目依赖中直接这样写 1 compile "org.p ...

随机推荐

  1. SDOI Day1

    好了做了SDOI day1的3道题,来讲下做法及感想吧 T1:排序(暴力,搜索) 题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3990 我们可 ...

  2. Angular企业级开发(8)-控制器的作用域

    scope概念 scope(作用域)是视图和控制器之间的桥梁,scope本身是一个对象,有方法和属性.scope可以应用在视图和控制器上. scope简单示例 <!DOCTYPE html> ...

  3. 存储可靠性技术之 --RAID

    云计算项目交付时,不可避免的需要考虑存储磁盘采用何种RAID.例如:我们的项目工程师可能会建议大家连接克隆虚拟机系统盘组RAID 10,完整复制虚拟机数据盘 使用RAID5或者RAID6等,那么RAI ...

  4. .net平台的rabbitmq使用封装

    前言 RabbitMq大家再熟悉不过,这篇文章主要整对rabbitmq学习后封装RabbitMQ.Client的一个分享.文章最后,我会把封装组件和demo奉上. Rabbitmq的运作 从下图可以看 ...

  5. Redis从入门到精通

    什么是Redis? Redis是非关系型数据库,是一个高性能的key-value数据库,它是开源的,更是免费的. Redis能做什么? 存储数据 Redis的优点有哪些? 1.它支持存储丰富的数据类型 ...

  6. fmt标签格式化数字和时间

    有时候需要格式化输出数字和时间,fmt 标签是个很好用的标签,下面是我做的总结: 在页面的头部加入这个标签 <%@ taglib uri="http://java.sun.com/js ...

  7. 关于Xmanager使用问题的总结

    做大数据的人对Xmanager这类远程连接工具应该都不陌生,我在使用Xmanager时遇到了一些问题并经过google和亲测解决,写在这里与大家分享. 1. [问题描述] 在windows上使用Xma ...

  8. [POJ1028]Web Navigation(栈)

    这题是01年East Central North的A题,目测是签到题 Description Standard web browsers contain features to move backwa ...

  9. MySQL中的完整性约束条件(主键、外键、唯一、非空)

    数据库的完整性约束用来防止对数据的意外破坏,来保证数据的安全性和一致性. 主键 1.创建表时候指定主键 创建表user(id, username, age),并且id字段非空自增. CREATE TA ...

  10. swift -- 构造/析构函数

     一.构造函数 //当一个类实例化一个对象时候,第一个调用的方法 class Student { //属性 var name = "ser" let age : Int //1.重 ...