Angular中实现树形结构视图实例代码

网友投稿 425 2023-05-18


Angular中实现树形结构视图实例代码

近两年当中使用Angular开发过很多项目,其中也涉及到一些树形结构视图的显示,最近的在项目中封装了大量的组件,一些组件也有树形结构的展示,所以写出来总结一下。

相信大家都知道,树结构最典型的例子就是目录结构了吧,一个目录可以包含很多子目录,子目录又可以包含若干个子孙目录,那咱们今天就以目录结构为例来说明一下Angular中树结构的实现。

首先,我们希望封装一个组件,用于显示整个目录的树形机构,代码如下:

就像上面的代码一样,我们直接声明folder-tree标签,将controller中的folder数据作为参数传递进去,预期会显示出一个完整的树状目录结构。接下来我们就来定义模块,控制器,以及相应的指令部分:

angular.module('treeDemo', [])

.controller("TreeController", function($scope) {

$scope.folder = {

name: 'techs',

children: [

{

name: 'server-shttp://ide',

children: [

{

name: 'java'

},

{

name: 'python'

},

{

name: 'Node'

}

]

},

{

name: 'front-end',

children: [

{

name: 'jquery'

},

{

name: 'Angular'

},

{

name: 'React'

}

]

}

]

}

})

.directive("folderTree", function() {

return {

restrict: "E",

scope: {

currentFolder: '='

},

templateUrl: 'template/tree.html'

};

});

如上所述,在控制器中我们在$scope中绑定了一个folder的数据对象,包含整个的目录结构数据,接着定义了folderTree指令,它会使用tree.html作为模板进行视图渲染,我们这就来look look模板中的内容:

{{currentFolder.name}}

可以看到,在模板中有个很重要的环节,那就是使用ng-repeat指令遍历当前目录的子集,然后再次使用folder-tree组件来渲染相应的子目录,这种方式简直是完美,现在我们来看看渲染的结果:

这种在模板中嵌套使用指令的方法很完美,只可惜低版本的Angular中是无法实现的,会出现无限递归循环,造成页面假死,这是Angular本身的解析机制造成的。经测试,Angular 1.5.0及以上版本是没有问题的,但在Angular 1.4.9及以下版本中就会运行失败。假如你在项目中真的使用了低版本的Angular并且造成运行失败,我们还可以稍微改动一下模板,采用ng-include来实现同样的功能:

{{currentFolder.name}}

<ul>

ng-include="'template/tree.html'"

ng-init="currentFolder = subfolder">

我们在模板中去掉了folder-tree指令,使用了ng-include指令,再次将tree.html模板引入进来,需要注意的是,因为ng-include会创建一个独立的作用域,为了让其正确的引用到currentFolder变量,我们需要在每个ng-include中初始化currentFolder,将其赋值为ng-repeat中的当前subfolder,另外,别忘了ng-include指令中模板路径前后加上单引号。

这样确实可以,但是你可能觉得有些遗憾,没能使用最好的解决方案来实现这个树结构。

其实这个问题早就有人吐槽了,令人惊喜的是,有个叫Mark的伙计写了一个service专门解决这个问题:

/*

* An Angular service which helps with creating recursive directives.

* @author Mark Lagendijk

* @license MIT

*/

angular.module('RecursionHelper', []).factory('RecursionHelper', ['$compile', function($compile){

return {

/**

* Manually compiles the element, fixing the recursion loop.

* @param element

* @param [link] A post-link function, or an object with function(s) registered via pre and post properties.

* @returns An object containing the linking functions.

*/

compile: function(element, link){

// Normalize the link parameter

// 如果link参数是对象类型link:{pre: function(...){}, post: function(...){}}则不做处理

// 如果link参数是函数类型则将其作为post-link函数在$compile之后调用

if(angular.isFunction(link)){

link = { post: link };

}

// Break the recursion loop by removing the contents

// 获取并清空当前元素的内容,后面进行编译

var contents = element.contents().remove();

var compiledContents;

return {

pre: (link && link.pre) ? link.pre : null,

/**

* Compiles and re-adds the contents

* 编译和重新添加内容到当前元素

*/

post: function(scope, element){

// Compile the contents

if(!compiledContents){

compiledContents = $compile(contents);

}

// Re-add the compiled contents to the element

compiledContents(scope, function(clone){

element.append(clone);

});

// Call the post-liUOamoRnking function, if any

if(link && link.post){

link.post.apply(null, arguments);

}

}

};

}

};

}]);

现在我们只需引入这个模块,然后在directive中使用RecursionHelper这个service,调用其compile手动编译指令对应的元素节点:

angular.module('treeDemo', ['RecursionHelper'])

.controller("TreeController", function($scope) {

$scope.folder = {

name: 'techs',

children: [

{

name: 'server-side',

children: [

{

name: 'Java'

},

{

name: 'Python'

},

{

name: 'Node'

}

]

},

{

name: 'front-end',

children: [

{

name: 'jQuery'

},

{

name: 'Angular'

},

{

name: 'React'

}

]

}

]

}

})

.directive("folderTree", function(RecursionHelper) {

return {

restrict: "E",

scope: {

currentFolder: '='

},

templateUrl: 'template/tree.html',

compile: function(element) {

// 我们这里使用RecursionHelper的compile方法编译指令当前元素,这里第二个参数指定一个函数,相当于常用的link函数

// 当然我们也可以指定一个对象,里面包含pre和post函数,分别对应pre-link和post-link

return RecursionHelper.compile(element, function(scope, iElement, iAttrs, controller, transcludeFn){

// Define your normal link function here.

// Alternative: instead of passing a function,

// you can also pass an object with

// a 'pre'- and 'post'-link function.

// 这里可以往scope中绑定一些变量

scope.variable = 'hello world';

});

}

};

});

在上面代码中,我们在创建treeDemo模块时引入RecursionHelper模块,然后在创建folderTree指令时使用RecursionHelper服务,并且在compile方法中调用RecursionHelper的compile方法,即可修复上面的问题。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java中Object toString方法简介_动力节点Java学院整理
下一篇:springboot集成activemq的实例代码
相关文章

 发表评论

暂时没有评论,来抢沙发吧~