Home Web Front-end Front-end Q&A JavaScript implements draggable tree

JavaScript implements draggable tree

May 12, 2023 am 10:17 AM

As Web applications are increasingly used, we increasingly need to design more efficient methods for interaction with web pages. One of them is to use JavaScript to implement a draggable tree (Drag & Drop Tree). This article will introduce how to use JavaScript to create a draggable tree, detailing the implementation process and related technical details.

1. Goals to be achieved

The draggable tree described in this article refers to a structure on the web page, which contains nodes of the tree structure, and we can drag and drop them. Reorganize their hierarchical relationships. To implement such a tree, the following two key aspects need to be completed.

  1. Implementing the tree structure

First we need to create nodes for the tree structure in the page and determine the levels and associations between the nodes. These contents can be represented using JSON. For example, we can store the structure of the tree in the following JSON format:

1

2

3

4

5

6

7

8

9

10

11

12

13

{

    name: "节点A",

    children: [{

        name: "子节点A1",

        children: []

    }, {

        name: "子节点A2",

        children: [{

            name: "子节点A2-1",

            children: []

        }]

    }]

}

Copy after login

When rendered as a tree structure, it should look like this:

1

2

3

4

- 节点A

  |- 子节点A1

  |- 子节点A2

     |- 子节点A2-1

Copy after login
  1. Implementing drag and drop functionality

Making nodes drag-and-drop requires the use of some JavaScript techniques. Regarding the drag and drop API, generally speaking, it involves three categories:

  • Dragable elements
  • Place target elements
  • Drag data

Using these APIs, we can easily implement the drag-and-drop function of nodes.

2. Technical details

After understanding our goals, let’s now discuss the implementation details in detail. The following are the steps to implement:

  1. Build a tree structure

We need to create node elements first and add them to HTML, usually using ul and li element levels. accomplish. For each node, a li element is required, and more li elements must be nested in the child node ul. In order to associate the tree structure with JSON data, you can use the data-* attributes to store the JSON data in the corresponding li element.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

<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>

Copy after login
  1. Add drag events to nodes

We need to add drag events for each node, including mousedown, dragstart, dragover, dragleave, drop and dragend. Among them, mousedown and dragstart events need to be processed before dragging starts, and subsequent processing is dragover, dragleave, drop and dragend respectively. The handling functions of these drag and drop events can be completed through event listeners.

1

2

3

4

5

6

7

8

9

10

// 获取所有节点并添加事件监听器

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);

});

Copy after login
  1. Implementing the processing function of the drag event

The processing function of the drag event is somewhat complicated, and each step of the operation needs to be carefully designed. The following are instructions for each step:

  • mousedown: Record the element where the drag starts and set isDragged to true.
  • dragstart: Set the data transmission type and the data to be transmitted. In addition, it is necessary to determine whether the drag operation can be performed based on the status of isDragged. To set the data transmission type, you can use the setData() method.

1

2

3

4

5

6

7

function onDragStart(event) {

    if (!isDragged) {

        draggedItem = event.currentTarget.parentNode;

        event.dataTransfer.setData('text/plain', event.currentTarget.dataset.name);

        isDragged = true;

    }

}

Copy after login
  • dragover: Prevent the default event and add the isOver attribute to the current element. This attribute indicates that the current element is placed above other elements and can be placed. Default events can be prevented through the event.preventDefault() method.

1

2

3

4

5

6

7

function onDragOver(event) {

    event.preventDefault();

    if (!event.currentTarget.dataset.isOver) {

        event.currentTarget.parentNode.classList.add('over');

        event.currentTarget.dataset.isOver = true;

    }

}

Copy after login
  • dragleave: Remove the over attribute of the current element, indicating that there is no mouse hovering over the element.

1

2

3

4

5

6

function onDragLeave(event) {

    if (event.currentTarget.dataset.isOver) {

        event.currentTarget.parentNode.classList.remove('over');

        event.currentTarget.dataset.isOver = false;

    }

}

Copy after login
  • drop: Determine whether the placement operation can be performed based on whether the current element has the over attribute. If it doesn't work, exit directly; if it works, perform a placement operation and adjust the tree structure.

1

2

3

4

5

6

7

8

9

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);

    }

}

Copy after login
  • dragend: implements the termination event of drag operation. In this event, reset the value of isDragged and remove all over attributes.

1

2

3

4

5

function onDragEnd(event) {

    event.currentTarget.parentNode.classList.remove('over');

    event.currentTarget.dataset.isOver = false;

    isDragged = false;

}

Copy after login

3. Complete code

Finally, we integrate the above Javascript code to display a complete draggable tree. You can use this code directly, copy it into a text editor, save it as an html file and run it in the browser.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

<!DOCTYPE html>

<html>

<head>

    <meta charset="utf-8">

    <title>可拖动的树</title>

    <style>

        .over {

            border-top: 5px solid blue !important;

        }

    </style>

</head>

<body>

&lt;ul id=&quot;tree&quot;&gt;

    &lt;li data-name=&quot;节点A&quot;&gt;

        &lt;div class=&quot;node&quot;&gt;节点A&lt;/div&gt;

        &lt;ul&gt;

            &lt;li data-name=&quot;子节点A1&quot;&gt;

                &lt;div class=&quot;node&quot;&gt;子节点A1&lt;/div&gt;

            &lt;/li&gt;

            &lt;li data-name=&quot;子节点A2&quot;&gt;

                &lt;div class=&quot;node&quot;&gt;子节点A2&lt;/div&gt;

                &lt;ul&gt;

                    &lt;li data-name=&quot;子节点A2-1&quot;&gt;

                        &lt;div class=&quot;node&quot;&gt;子节点A2-1&lt;/div&gt;

                    &lt;/li&gt;

                &lt;/ul&gt;

            &lt;/li&gt;

        &lt;/ul&gt;

    &lt;/li&gt;

&lt;/ul&gt;

<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>

Copy after login

Through the above code implementation, we successfully created a draggable tree structure. In the web page, users can easily adjust the tree structure by dragging and dropping. At the same time, we also introduced in detail various technical details during the implementation process. This is undoubtedly a very useful practical case for developers who are learning JavaScript.

The above is the detailed content of JavaScript implements draggable tree. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot Article Tags

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Explain the concept of lazy loading. Explain the concept of lazy loading. Mar 13, 2025 pm 07:47 PM

Explain the concept of lazy loading.

What is useEffect? How do you use it to perform side effects? What is useEffect? How do you use it to perform side effects? Mar 19, 2025 pm 03:58 PM

What is useEffect? How do you use it to perform side effects?

How does the React reconciliation algorithm work? How does the React reconciliation algorithm work? Mar 18, 2025 pm 01:58 PM

How does the React reconciliation algorithm work?

How does currying work in JavaScript, and what are its benefits? How does currying work in JavaScript, and what are its benefits? Mar 18, 2025 pm 01:45 PM

How does currying work in JavaScript, and what are its benefits?

What are higher-order functions in JavaScript, and how can they be used to write more concise and reusable code? What are higher-order functions in JavaScript, and how can they be used to write more concise and reusable code? Mar 18, 2025 pm 01:44 PM

What are higher-order functions in JavaScript, and how can they be used to write more concise and reusable code?

Explain the purpose of each lifecycle method and its use case. Explain the purpose of each lifecycle method and its use case. Mar 19, 2025 pm 01:46 PM

Explain the purpose of each lifecycle method and its use case.

What are React's performance optimization techniques (memoization, code splitting, lazy loading)? What are React's performance optimization techniques (memoization, code splitting, lazy loading)? Mar 18, 2025 pm 01:57 PM

What are React's performance optimization techniques (memoization, code splitting, lazy loading)?

What is useContext? How do you use it to share state between components? What is useContext? How do you use it to share state between components? Mar 19, 2025 pm 03:59 PM

What is useContext? How do you use it to share state between components?

See all articles