AngularJS - 如何制作可拖动的树?

Posted

技术标签:

【中文标题】AngularJS - 如何制作可拖动的树?【英文标题】:AngularJS - How to make a draggable tree? 【发布时间】:2012-12-27 05:46:47 【问题描述】:

我想创建一个树状结构,用户可以在其中拖放叶子。我的出发点如下:

HTML

<div ng:controller="controller">
  <ul ui-sortable ng-model="items" ui-options="connectWith: '.item'" class="item">
    <li ng-repeat="item in items" class="item">
       item.name 
      <ul ui-sortable ng-model="item.children" ui-options="connectWith: '.item'" class="item">
        <li ng-repeat="item in item.children" class="item"> item.name </li>
      </ul>
    </li>
  </ul>

  <pre> items | json </pre>
</div>

<script src="http://code.angularjs.org/1.0.2/angular.min.js"></script>
<script src="https://raw.github.com/angular-ui/angular-ui/master/build/angular-ui.min.js"></script>

CoffeeScript

myapp = angular.module 'myapp', ['ui']

myapp.controller 'controller', ($scope) ->

    $scope.items = [
      id: 1, name: 'Item 1', children: [
        id: 5, name: 'SubItem 1.1', children: [
          id: 11, name: 'SubItem 1.1.1', children: [],
          id: 12, name: 'SubItem 1.1.2', children: []
        ],
        id: 6, name: 'SubItem 1.2', children: []
      ],
      id: 2, name: 'Item 2', children: [
        id: 7, name: 'SubItem 2.1', children: [],
        id: 8, name: 'SubItem 2.2', children: []
        id: 9, name: 'SubItem 2.3', children: []
      ],
      id: 3, name: 'Item 3', children: [
        id: 10, name: 'SubItem 3.1', children: []
      ]
    ]

angular.bootstrap document, ['myapp']

代码也在这个 JSFiddle 中:http://jsfiddle.net/bESrf/1/

在我的“真实”代码中,我将第二个 &lt;ul&gt; 提取到模板中并递归渲染它,而不是只为孩子设置一个级别,这工作正常,但我找不到办法做到这一点JSFiddle。

什么是递归渲染它并且仍然允许拖放会改变由 ng-model 表示的对象和子对象数组的最佳方法?

【问题讨论】:

【参考方案1】:

看看这个例子:http://jsfiddle.net/furf/EJGHX/

我刚刚完成了这个解决方案,所以它还没有被正确记录,但你应该能够为你的解决方案挖掘它。

你需要用到一些东西:

    ezTree 指令 - 渲染树 Manuele J Sarfatti's nestedSortable plugin for jQuery UI (可选)uiNestedSortable 指令 - 从您的模板启用nestedSortable。 用于更新模型的控制器代码 - 请参阅$scope.update

使用ezTree 指令

给定一个递归数据结构:

$scope.data = 
  children: [
    text: 'I want to create a tree like structure...',
    children: [
      text: 'Take a look at this example...',
      children: []
    ]
  ]
;

此模板将构建树:

<ol>
  <li ez-tree="child in data.children at ol">
    <div>item.text</div>
    <ol></ol>
  </li>
</ol>

ez-tree 表达式应写为item in collection at selector,其中item 是迭代的子代(又名ng-repeat),collection 是根级集合,selector 是 CSS 选择器指令应该递归的模板内的节点。集合的终端属性的名称,在本例中为 children,将用于递归树,在本例中为 child.children这可以重写为可配置的,但我将把它作为练习留给读者。

使用uiNestedSortable 指令

<ol ui-nested-sortable=" listType: 'ol', items: 'li', doNotClear: true "
  ui-nested-sortable-stop="update($event, $ui)">
</ol>

ui-nested-sortable 属性应包含用于嵌套排序插件的 JSON 配置。该插件要求您指定listTypeitems。我的解决方案要求doNotCleartrue。使用ui-nested-sortable-*eventName* 为事件分配回调。我的指令为回调提供可选的 $event 和 $ui 参数。有关其他选项,请参阅nestedSortable 的文档。

更新您的模型

给这只猫剥皮的方法不止一种。这是我的。在停止事件上,它提取元素作用域的子属性来确定移动了哪个对象,提取元素父作用域的子属性来确定对象的目的地,以及元素的位置来确定对象的位置在其目的地。然后它遍历数据结构并将对象从其原始位置移除并将其插入到新位置。

$scope.update = function (event, ui) 

  var root = event.target,
    item = ui.item,
    parent = item.parent(),
    target = (parent[0] === root) ? $scope.data : parent.scope().child,
    child = item.scope().child,
    index = item.index();

  target.children || (target.children = []);

  function walk(target, child) 
    var children = target.children,
      i;
    if (children) 
      i = children.length;
      while (i--) 
        if (children[i] === child) 
          return children.splice(i, 1);
         else 
          walk(children[i], child)
        
      
    
  
  walk($scope.data, child);

  target.children.splice(index, 0, child);
;

【讨论】:

哇,谢谢!我会试一试,然后告诉你。 FYI - 这在 IE 中不起作用...要使其在 IE10 中起作用,请更改:cursor = parentNode.childNodes[i]; to be @ 987654348@ 感谢this response 您能否更新此答案以使其适合链接的小提琴?另请评论有关 nestedSortable 的更改,这些更改从当前链接的小提琴中丢失但在此答案中提到。【参考方案2】:

furf 对小提琴进行了轻微编辑,使其在 IE 中工作。

当第二个参数为 null 时,IE 在 insertNode 上给出错误,因此在这种情况下,请改用 appendNode。

http://jsfiddle.net/michieljoris/VmtfR/

if (!cursor) parentNode.appendChild(cached.element);
else parentNode.insertBefore(cached.element, cursor);

嵌套排序插件在 js 中内联,因为 IE 从 github 包含时会出现 MIME 类型不匹配。

【讨论】:

raw.github.com/ETC 文件可以通过 rawgithub.com/ETC 链接(注意点被移除) 我更新了小提琴并直接链接了嵌套排序插件。希望它仍然可以在 IE 中使用。我还添加了使用 isAllowed 来实现条件拖放。另一种设置 isAllowed 的方法请参见 fiddle 我认为在 Github 上给它一个家可能会很好,因为它非常通用,并且还在继续改进:github.com/nelsonblaha/draggable-tree【参考方案3】:

试试Angular-NestedSortable,它是一个Angularjs插件,可以对嵌套列表进行排序和绑定数据,不需要依赖jQuery。 https://github.com/jimliu/Angular-NestedSortable

【讨论】:

以上是关于AngularJS - 如何制作可拖动的树?的主要内容,如果未能解决你的问题,请参考以下文章

如何修复 AngularJS 指令中的“jQuery 可拖动不是函数”

如何使用angularJS突出显示可拖动元素下的拖放区?

react可拖动的好用的树结构插件

AngularJs 使元素在 DOM 中可动态拖动或放置

如何在 Qt 中制作部分可编辑的树模型

使 ngDialog 可拖动 AngularJs jQueryUI