如何在动态创建的 HTML 中使用拖放功能? (SortableJS)
Posted
技术标签:
【中文标题】如何在动态创建的 HTML 中使用拖放功能? (SortableJS)【英文标题】:How do I use drag and drop with dynamically created HTML? (SortableJS) 【发布时间】:2021-11-05 16:23:42 【问题描述】:我开始学习 javascript,并且我有一个简单的待办事项应用程序,我希望能够拖放创建的不同待办事项。一个简单的方法是使用 SortableJS 库,但它不能按照我想要的方式工作。在实现了简单的可排序功能后,当拖动一个待办事项时,它会抓取整个待办事项列表而不是单个待办事项
我认为问题在于我动态创建了 html,但我有点卡住了,如果有任何建议,我将不胜感激。
//Selectors
const todoInput = document.querySelector(".todos-input"); //input for adding a todo
const todoButton = document.querySelector(".todos-button"); //add todo-button
const todoList = document.querySelector(".todos-list"); //the todo-list
//Event listeners
todoButton.addEventListener("click", addTodo);
todoList.addEventListener("click", deleteTodo);
todoList.addEventListener("click", completeTodo);
//Functions
function addTodo(event)
//prevent form from submitting
event.preventDefault();
//create a div for the todos-list
const todoDiv = document.createElement("div");
//add classlist for styling
todoDiv.classList.add("todo");
//Create LI
const newTodo = document.createElement("li");
//output the value from the add-todo field
if (todoInput.value != "")
newTodo.innerText = todoInput.value;
else
return false;
//classlist for styling
newTodo.classList.add("todo-item");
//append child to div
todoDiv.appendChild(newTodo);
//complete button
const completedButton = document.createElement("button");
completedButton.innerHTML = '<i class="fas fa-check"><i/>';
completedButton.classList.add("completed-btn");
todoDiv.appendChild(completedButton);
//delete button
const deletedButton = document.createElement("button");
deletedButton.innerHTML = '<i class="fas fa-trash"><i/>';
deletedButton.classList.add("deleted-btn");
todoDiv.appendChild(deletedButton);
//drag button
const dragButton = document.createElement("button");
dragButton.innerHTML = '<i class="icon fa fa-bars"><i/>';
dragButton.classList.add("drag-btn");
dragButton.classList.add("handle");
todoDiv.appendChild(dragButton);
//append div to list of todos
todoList.appendChild(todoDiv);
//clear input field after adding a new todo
todoInput.value = "";
//DRAG AND DROP
const dragArea = document.querySelector('.todos-section');
new Sortable(dragArea,
animation: 300
);
//deleting todo
function deleteTodo(e)
//grab the item, whatever we are clicking on
const item = e.target;
//delete todo
if (item.classList[0] === "deleted-btn")
//grab the parent element of the item, which is the todolist element in this case
const todo = item.parentElement;
//remove the todo
todo.remove();
//completing todo
function completeTodo(e)
//grab the item, whatever we are clicking on
const item = e.target;
//complete todo
if (item.classList[0] === "completed-btn")
const todo = item.parentElement;
//use the toggle because if the element has a class, then the classList.toggle method
//behaves like classList.remove and the class is removed from the element.
//And if the element does not have the specified class
//then classList.toggle, just like classList.add, adds this class to the element.
//So it basically does the add/remove operation for us depending on the state.
todo.classList.toggle("completed-todo");
/*Apply to all elements*/
*
box-sizing: border-box;
list-style-type: none;
margin: 0;
padding: 0;
body
font-family: "Merriweather Sans", sans-serif;
background: rgba(216, 206, 206, 0.787);
.wrapper
display: flex;
position: relative;
/* Add todos-section */
.todos-bar
position: fixed;
top: 5%;
left: 50%;
font-size: 17px;
border: 0;
transform: translate(-50%, -50%);
padding-left: 100px;
.todos-bar input
width: 600px;
height: 50px;
border: 0px;
outline: none;
font-size: 20px;
padding-left: 20px;
border-radius: 5px;
.todos-bar button
position: fixed;
background: rgba(20, 33, 93, 0.952);
color: white;
font-size: 20px;
border: 0;
outline: none;
height: 50px;
padding: 10px 20px;
right: 0px;
border-radius: 0px 5px 5px 0px;
cursor: pointer;
.todos-bar button:hover
background: rgb(43, 54, 73);
/* Todos section */
.todos-section
display: flex;
position: fixed;
top: 15%;
left: 37%;
.todos-list
width: 600px;
.todo
margin: 1.5rem;
background: white;
color: black;
font-size: 1.5rem;
display: flex;
justify-content: space-between;
align-items: center;
border-radius: 5px;
padding-left: 0.5rem;
margin: 15px;
transition: all 0.5s ease;
.todo li
flex: 1;
.todo-item
padding: 0rem 0.5rem;
padding-left: 2.5rem;
.deleted-btn,
.completed-btn
background: rgb(248, 56, 56);
color: white;
border: none;
padding: 1rem;
cursor: pointer;
font-size: 1rem;
.completed-btn
background: green;
.deleted-btn
border-radius: 0px 5px 5px 0px;
.drag-btn
display: block;
position: absolute;
background: white;
border: 2px solid white;
.fa-bars
padding: 5px;
margin: 2px;
cursor: pointer;
.fa-trash,
.fa-check
pointer-events: none;
.completed-todo
text-decoration: line-through;
opacity: 0.5;
<head>
<link rel="stylesheet" href="style.css">
<script src="https://kit.fontawesome.com/47440aba67.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.14.0/Sortable.min.js"></script>
</head>
<body>
<div class="wrapper">
<!--ADD TODO-->
<div class="todos-bar">
<input type="text" class="todos-input" placeholder="Add to list...">
<button class="todos-button" type="submit"><i class="fas fa-plus"></i></button>
</div>
<!--TODO LIST-->
<div class="todos-section">
<ul class="todos-list"></ul>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
【问题讨论】:
【参考方案1】:根据documentation,
您可以为列表及其元素使用任何元素,而不仅仅是 ul/li
您实现的内容实际上符合此描述,因为里面有一个带有div
标签的ul
。但是,您没有在 dragArea
中引用正确的元素,因为它应该是您想要的可拖动子级的直接父级 (.todos-list
)。
因此,将其更改为.todos-list
,并将handle
属性传递给Sortable
构造函数以引用您要在其中拖动的icon
。
const dragArea = document.querySelector('.todos-list');
new Sortable(dragArea,
animation: 300,
handle: '.fa-bars'
)
工作example
【讨论】:
以上是关于如何在动态创建的 HTML 中使用拖放功能? (SortableJS)的主要内容,如果未能解决你的问题,请参考以下文章