无限级,无级限,你有多少层我不管。
在web开发中有时候会出现“无限层级”这样的需求,那什么是无限层级呢?什么时候需要考虑无限层级呢?最常见的是网页中的树菜单tree
了。一般网页中的树菜单长这样。(UI本人写的,比较简陋,看客勿怪)
之所以称之为“无限”,那主要是因为我们无法确定数据的层级深度到底有多少层。而我们前端拿到数据之后需要渲染页面,如果确定只有一两层的话,那直接使用一两层for
循环就搞定了。但是无法确定有多少层的话,那我们就需要考虑多层级的情况了。
例如:我们有如下的tree
数据结构,需要将它渲染到页面中去:
1 | var treeData = [{ |
数据里面一层套一层,层层相扣,大多数真实的场景中我们无法确知具体的层级到底有多深。这里目前演示为例。
字符串拼接
通过上面的结构我们可以通过JavaScript字符串拼接的方式,将生成好的所有html字符串插入到dom节点中。
HTML
1 | <div class="tree"> |
JavaScript
1 | var getTree = function(node) { |
上面的代码中重点在getTree
函数,getTree
函数直接返回拼接好的dom字符串。而函数内部做了逻辑判断,如果有子级children
的话,再嵌套一层,继续执行getTree
函数。这一步很重要:内部再次调用getTree
函数时的参数为node[i].children
。这样做就简单地实现无限级嵌套的树菜单了。
上面的代码虽然可行,但有一个很大的缺点就是不利于修改和维护。这还是简单的dom结构,如果结构比较复杂的话,那拼接起来可要仔仔细细的了。反正挺费劲儿,而且别人一看一大坨的字符串拼接肯定会头疼。这个问题很多前辈们也想到了,并且提出了解决方案,那就是前端模板引擎。
模板引擎
前端模板引擎实在是太多了,每个模板引擎的语法都很相似,这里我就以Simplite模板引擎来将上面的代码进行优化。关于Simplite模板引擎的源码,大家可以参考github。
html结构和上面一样,不一样的是多了一个script
标签模板
1 | <script type="text/html" id="treeTemplate"> |
注意:标签的type
属性是text/html
,这段代码浏览器在解析的时候是不会渲染,也不会报错,只是一段普通的文本。在里面<%
,%>
这样的符号就是Simplite模板引擎所特有的模板语法了,语法很简单。直接使用for
循环,输出html结构,然后如果有子模板的话就直接通过include
嵌套子模板,include
这个也是该模板引擎所自带的嵌套语法。其它的模板引擎大多数都带有这个功能。
那么使用了模板引擎之后,我们的JavaScript代码就变得简单多了。
1 | var tpl = new Simplite({ |
然后页面结构就会渲染出来。(这里的代码我只展示了一部分,需要demo源码的参考我的 github )。
Angular的方式
下面做一个简单的扩展,通过AngularJS的方式来展示上面这个例子。大家会发现语法更加简洁了。
HTML结构
1 | <div class="tree"> |
在这里的HTML结构有所更改,标签上直接使用的是angular的指令ng-include
,来实现模板的嵌套。而在angular中的模板使用的是ng-template
下面是它的模板
1 | <script type="text/ng-template" id="treeTemplate"> |
模板里面包含了一些指令,ng-repeat
、ng-if
、ng-init
等。ng-repeat
是用来遍历输出html结构的,相当于for
循环输出。ng-if
是做逻辑判断的,例如:ng-if="nd.children && nd.children.length > 0"
的意思是如果有子模板的话,就显示此标签。而模板里面的ng-init
是用来做数据初始化的,当再次调用当前模板的时候应该遍历的是子模板的数据(children
),于是指令就初始化重新遍历渲染。
使用Angular的方式只当做扩展,有兴趣的可以自己研究下Angular这个框架。无限层级还会在那些地方使用到呢?欢迎大家讨论。最后附上本篇文章的demo源码