温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Angular中如何实现树形结构视图

发布时间:2021-07-07 14:06:34 来源:亿速云 阅读:258 作者:小新 栏目:web开发

这篇文章主要为大家展示了“Angular中如何实现树形结构视图”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Angular中如何实现树形结构视图”这篇文章吧。

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

<!DOCTYPE html>  <html ng-app="treeDemo">   <body>    <div ng-controller="TreeController">      <folder-tree current-folder="folder"></folder-tree>    </div>    <script src="node_modules/angular/angular.min.js"></script>    <script src="js/app.js"></script>   </body>  </html>

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

angular.module('treeDemo', [])   .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() {    return {      restrict: "E",      scope: {        currentFolder: '='      },      templateUrl: 'template/tree.html'    };   });

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

<p>{{currentFolder.name}}</p>  <ul>    <li ng-repeat="subfolder in currentFolder.children">      <folder-tree current-folder="subfolder"></folder-tree>    </li>  </ul>

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

Angular中如何实现树形结构视图

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

<p>{{currentFolder.name}}</p>  <ul>    <li ng-repeat="subfolder in currentFolder.children"       ng-include="'template/tree.html'"       ng-init="currentFolder = subfolder">    </li>  </ul>

我们在模板中去掉了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-linking 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方法,即可修复上面的问题。

以上是“Angular中如何实现树形结构视图”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI