加入收藏 | 设为首页 | 会员中心 | 我要投稿 厦门网 (https://www.xiamenwang.cn/)- 数据采集、建站、AI开发硬件、专属主机、云硬盘!
当前位置: 首页 > 教程 > 正文

javascript下如何实现可拖动的树

发布时间:2023-09-25 11:00:11 所属栏目:教程 来源:网络
导读:   这篇文章主要介绍“javascript如何实现可拖动的树”,在日常操作中,相信很多人在javascript如何实现可拖动的树问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方
  这篇文章主要介绍“javascript如何实现可拖动的树”,在日常操作中,相信很多人在javascript如何实现可拖动的树问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”javascript如何实现可拖动的树”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
 
  一、实现的目标
 
  本文所描述的可拖动的树,是指网页上的一个结构,其中包含树形结构的节点,而我们可以通过拖拽来重新组织它们的层次关系。实现这样的树,需要完成以下两个关键方面。
 
  实现树形结构
 
  首先我们需要在页面中为树形结构创建节点,并确定节点之间的层次和关联。这些内容可以使用JSON来表示。例如,我们可以以下列JSON格式存储树的结构:
 
  {
 
      name: "节点A",
 
      children: [{
 
          name: "子节点A1",
 
          children: []
 
      }, {
 
          name: "子节点A2",
 
          children: [{
 
              name: "子节点A2-1",
 
              children: []
 
          }]
 
      }]
 
  }
 
  将其呈现为树状结构时,应该是这样的:
 
  - 节点A
 
    |- 子节点A1
 
    |- 子节点A2
 
       |- 子节点A2-1
 
  实现拖放功能
 
  让节点可以拖放需要使用一些JavaScript技术。有关拖放的API,常规来说涉及到三种类:
 
  可拖动的元素
 
  放置目标元素
 
  拖动的数据
 
  使用这些API,我们可以轻松实现节点的拖拽功能。
 
  二、技术细节
 
  了解了我们的目标后,现在我们来详细讨论实现细节。下面是实现的步骤:
 
  构建树形结构
 
  我们需要先创建节点元素,并添加它们到HTML中,通常使用ul和li元素层次来实现。对于每一个节点,都需要一个li元素,而且要在子节点ul中嵌套更多的li元素。为了将树形结构和JSON数据关联,可以使用data-*属性,将JSON数据存储在相应的li元素中。
 
  <ul id="tree">
 
      <li data-name="节点A">
 
          <div class="node">节点A</div>
 
          <ul>
 
              <li data-name="子节点A1">
 
                  <div class="node">子节点A1</div>
 
              </li>
 
              <li data-name="子节点A2">
 
                  <div class="node">子节点A2</div>
 
                  <ul>
 
                      <li data-name="子节点A2-1">
 
                          <div class="node">子节点A2-1</div>
 
                      </li>
 
                  </ul>
 
              </li>
 
          </ul>
 
      </li>
 
  </ul>
 
  给节点添加拖拽事件
 
  我们需要为每一个节点添加拖拽事件,包括mousedown、dragstart、dragover、dragleave、drop和dragend。其中,mousedown和dragstart事件需要在拖拽开始前处理,和后续处理分别依次为dragover、dragleave、drop和dragend。这些拖拽事件的处理函数可以通过事件监听器来完成。
 
  // 获取所有节点并添加事件监听器
 
  const nodes = document.querySelectorAll('.node');
 
  nodes.forEach((node) => {
 
      node.addEventListener('mousedown', onMouseDown);
 
      node.addEventListener('dragstart', onDragStart);
 
      node.addEventListener('dragover', onDragOver);
 
      node.addEventListener('dragleave', onDragLeave);
 
      node.addEventListener('drop', onDrop);
 
      node.addEventListener('dragend', onDragEnd);
 
  });
 
  实现拖拽事件的处理函数
 
  拖拽事件的处理函数有些复杂,需要仔细设计每一个步骤的操作。以下是每一个步骤的说明:
 
  mousedown:记录下拖拽开始的元素,并将isDragged设置为true。
 
  dragstart:设置数据传输类型和需要传输的数据。另外,需要根据isDragged的状态,判定是否能进行拖拽操作。设置数据传输类型可以使用setData()方法。
 
  function onDragStart(event) {
 
      if (!isDragged) {
 
          draggedItem = event.currentTarget.parentNode;
 
          event.dataTransfer.setData('text/plain', event.currentTarget.dataset.name);
 
          isDragged = true;
 
      }
 
  }
 
  dragover:阻止默认事件,并在当前元素上添加isOver的属性。这个属性表示当前元素被置于其他元素上方,可以执行放置操作。可以通过event.preventDefault()方法来阻止默认事件。
 
  function onDragOver(event) {
 
      event.preventDefault();
 
      if (!event.currentTarget.dataset.isOver) {
 
          event.currentTarget.parentNode.classList.add('over');
 
          event.currentTarget.dataset.isOver = true;
 
      }
 
  }
 
  dragleave:移除当前元素的over属性,表示没有鼠标悬停在该元素上了。
 
  function onDragLeave(event) {
 
      if (event.currentTarget.dataset.isOver) {
 
          event.currentTarget.parentNode.classList.remove('over');
 
          event.currentTarget.dataset.isOver = false;
 
      }
 
  }
 
  drop:根据当前元素是否有over属性,判定是否可以进行放置操作。如果不行,直接退出;如果可以,则进行放置操作,调整树的结构。
 
  function onDrop(event) {
 
      event.preventDefault();
 
      if (event.currentTarget.dataset.isOver) {
 
          const droppedItem = event.currentTarget.parentNode;
 
          const parent = draggedItem.parentNode;
 
          parent.removeChild(draggedItem);
 
          event.currentTarget.parentNode.insertBefore(draggedItem, droppedItem.nextSibling);
 
      }
 
  }
 
  dragend:实现拖拽操作的终止事件。在该事件中,重置isDragged的值,并移除所有的over属性。
 
  function onDragEnd(event) {
 
      event.currentTarget.parentNode.classList.remove('over');
 
      event.currentTarget.dataset.isOver = false;
 
      isDragged = false;
 
  }
 
  三、完整代码
 
  最后,我们将以上的Javascript代码整合在一起,展示一个完整的可拖动的树。可以直接使用该代码,将其复制到文本编辑器中,保存为html文件即可在浏览器中运行。
 
  <!DOCTYPE html>
 
  <html>
 
  <head>
 
      <meta charset="utf-8">
 
      <title>可拖动的树</title>
 
      <style>
 
          .over {
 
              border-top: 5px solid blue !important;
 
          }
 
      </style>
 
  </head>
 
  <body>
 
  <ul id="tree">
 
      <li data-name="节点A">
 
          <div class="node">节点A</div>
 
          <ul>
 
              <li data-name="子节点A1">
 
                  <div class="node">子节点A1</div>
 
              </li>
 
              <li data-name="子节点A2">
 
                  <div class="node">子节点A2</div>
 
                  <ul>
 
                      <li data-name="子节点A2-1">
 
                          <div class="node">子节点A2-1</div>
 
                      </li>
 
                  </ul>
 
              </li>
 
          </ul>
 
      </li>
 
  </ul>
 
  <script>
 
      let draggedItem = null;
 
      let isDragged = false;
 
      const nodes = document.querySelectorAll('.node');
 
      nodes.forEach((node) => {
 
          node.addEventListener('mousedown', onMouseDown);
 
          node.addEventListener('dragstart', onDragStart);
 
          node.addEventListener('dragover', onDragOver);
 
          node.addEventListener('dragleave', onDragLeave);
 
          node.addEventListener('drop', onDrop);
 
          node.addEventListener('dragend', onDragEnd);
 
      });
 
      function onMouseDown(event) {
 
          event.preventDefault();
 
      }
 
      function onDragStart(event) {
 
          if (!isDragged) {
 
              draggedItem = event.currentTarget.parentNode;
 
              event.dataTransfer.setData('text/plain', event.currentTarget.dataset.name);
 
              isDragged = true;
 
          }
 
      }
 
      function onDragOver(event) {
 
          event.preventDefault();
 
          if (!event.currentTarget.dataset.isOver) {
 
              event.currentTarget.parentNode.classList.add('over');
 
              event.currentTarget.dataset.isOver = true;
 
          }
 
      }
 
      function onDragLeave(event) {
 
          if (event.currentTarget.dataset.isOver) {
 
              event.currentTarget.parentNode.classList.remove('over');
 
              event.currentTarget.dataset.isOver = false;
 
          }
 
      }
 
      function onDrop(event) {
 
          event.preventDefault();
 
          if (event.currentTarget.dataset.isOver) {
 
              const droppedItem = event.currentTarget.parentNode;
 
              const parent = draggedItem.parentNode;
 
              parent.removeChild(draggedItem);
 
              event.currentTarget.parentNode.insertBefore(draggedItem, droppedItem.nextSibling);
 
          }
 
      }
 
      function onDragEnd(event) {
 
          event.currentTarget.parentNode.classList.remove('over');
 
          event.currentTarget.dataset.isOver = false;
 
          isDragged = false;
 
      }
 
  </script>
 
  </body>
 
  </html>
 

(编辑:厦门网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章