Kendo TreeView 移动 Parent 节点以更改排序顺序但不允许将 Parent 拖到 Child 节点下

Kendo TreeView Move Parent nodes to change the Sort Order but not allow a Parent to be dragged under a Child node

我有 Kendo 个 TreeView,其中 parent 个节点有 child 个节点。

我想要的规则是用户可以

  1. 将parent节点拖到当前位置的上方或下方,从而改变排序顺序
  2. 不允许将 parent 拖到另一个 parent 节点上
  3. 不允许将 parent 拖到任何 child 节点上
  4. DO 允许将 child 节点项拖到另一个 parent 节点下

我当然更喜欢javascript或jquery

此代码只是防止所有 parent 节点被拖动,因此这不是我想要的。有人有这方面的样品吗?

 $(".k-treeview").data("kendoTreeView").bind("dragstart", function (e) {
    if ($(e.sourceNode).parentsUntil(".k-treeview", ".k-item").length == 0) {
       e.preventDefault();
    }
});

根据答案更新

如果我将它放在我的 $(document).ready(function() { ...

中,似乎几乎所有代码都可以根据答案进行更正

但是如果我将该代码放在 onDrop 下,则不会被调用。

例如

  var treeview = $("#treeview").kendoTreeView({
                                    expanded: true,
                                    dragAndDrop: true,
                                    select: onSelect,
                                    loadOnDemand: false,
                                    dataSource: homogeneous,
                                    dataTextField: "ReportGroupName",
                                    template: kendo.template($("#treeview-template").html()) //,
                                    ,
                                    onDrop: function(e) {
                                        kendoTreeView = $(".k-treeview").data("kendoTreeView");
                                        kendoTreeView.bind("drag", function (e) {

                                            //Check if we're trying to add the node as a child
                                            var dropAsChild = $(e.dropTarget).hasClass("k-in k-state-hover");

                                            var sourceDataItem = kendoTreeView.dataItem(e.sourceNode);
                                            var destinationDataItem = kendoTreeView.dataItem(e.dropTarget);

                                            if ($(e.sourceNode).is(e.dropTarget)) {
                                                //Dropping on itself
                                                e.setStatusClass("k-denied");
                                            } else if (destinationDataItem && !dropAsChild) {
                                                //Dropping as a sibling... that's ok if it's the same parent
                                                if (sourceDataItem.parent().uid != destinationDataItem.parent().uid) {
                                                    //Not the same parent
                                                    e.setStatusClass("k-denied");
                                                }
                                            } else {
                                                e.setStatusClass("k-denied");
                                            }
                                        });
                                    }

                                }).data("kendoTreeView");

图像 这是一张红色箭头指向 child 的图像,我要移动到另一个 parent(成为带有蓝色箭头的 parent 的 child)

dragstart 事件的问题是它不会为您提供放置目标,因为它在事件序列的早期。

实现此目的的最佳方法是根据源节点和目标节点拒绝删除操作。您可以通过在传递给 drag 事件的事件对象上调用 setStatusClass(带有 k-denied)来完成此操作。

var treeview = $("#treeview").kendoTreeView({
    expanded: true,
    dragAndDrop: true,
    select: onSelect,
    loadOnDemand: false,
    dataSource: homogeneous,
    dataTextField: "ReportGroupName",
    template: kendo.template($("#treeview-template").html()),
    drag: function (e) {
        //Check if we're trying to add the node as a child
        var kendoTreeView = $("#treeview").data("kendoTreeView");
        var dropAsChild = $(e.dropTarget).hasClass("k-in k-state-hover");

        var sourceDataItem = kendoTreeView.dataItem(e.sourceNode);
        var destinationDataItem = kendoTreeView.dataItem(e.dropTarget);

        if ($(e.sourceNode).is(e.dropTarget)) {
            //Dropping on itself
            e.setStatusClass("k-denied");
        } else if (destinationDataItem && !dropAsChild) {
            //Dropping as a sibling... that's ok if it's the same parent
            if (sourceDataItem.parent().uid != destinationDataItem.parent().uid) {
                //Not the same parent
                e.setStatusClass("k-denied");
            }
        } else {
            e.setStatusClass("k-denied");
        }
    }
}).data("kendoTreeView");

我现在无法测试上面的代码,所以它们可能存在一些错误......我相信你仍然会理解它背后的逻辑。

我们可以在拖动事件中检查e.statusClass。因此,如果元素作为子元素添加,请取消拖动。对 The_Black_Smurf 代码进行了一些更改。下面的代码对我有用

drag: function (e) {
    //Check if are we adding node as a child
    if(e.statusClass == "i-plus") {
      e.setStatusClass("k-i-cancel"); //Cancel drop
      return;
    }
    var kendoTreeView = $("#treeViewAttr").data("kendoTreeView");
    var sourceDataItem = kendoTreeView.dataItem(e.sourceNode);
    var destinationDataItem = kendoTreeView.dataItem(e.dropTarget);
  
    if (destinationDataItem) { 
      if (sourceDataItem.parent()[0].uid != destinationDataItem.parent()[0].uid) { 
        e.setStatusClass("k-i-cancel");
      }
    }        
  }

在我的 kendo 树视图版本中 classes 命名不同,请阅读下面的 class 名称并根据您的 kendo 版本定义 class 名称.

根据 API 参考 kendoTreeView 拖动事件

预定义状态class是:

k-插入顶部

  • 表示该项目将被插入到顶部。

k-插入中间

  • 表示该项目将被插入 中间.

k-插入底部

  • 表示项目将被插入 底部。

k-加法

  • 表示该项目将是added/appended。

k-拒绝

  • 表示无效操作。使用此 class 将 自动使drop操作无效,所以不会有 需要在drop事件中调用setValid(false)

这个最重要:-

请注意,从版本 2016.3.914 开始,预定义状态 classes 的命名约定为 k-i-className。自版本 2017.1.118 起,使用以下状态 classes:k-i-insert-up, k-i-insert-down, k-i-insert-middle, k-i-plus, k-i-cancel.

请注意,e.statusClass 返回的状态 classes 没有 k- 前缀,但是通过 [=14] 设置预定义状态 class 时需要此前缀=].如果设置自定义状态 CSS class.

,则不需要前缀