Как лучше сделать сортировальний драг - дроп?
Помогите создать драг дроп сортировальний, у меня получился только простой и то через пень колоду, если есть идея как сделать тень только по елементу а не всей доски подскажите как сделать, и помогите пожалуста сделать сортировальний драг дроп, буду очень боагодарен
const lists = document.querySelectorAll(".boards__list")
// ADD TASK
function addTask() {
const addTaskBtn = document.querySelector(".boards__item--add")
const form = document.querySelector(".boards__form")
const addBtn = document.querySelector(".boards__buttons--add")
const cancelBtn = document.querySelector(".boards__buttons--cancel")
const area = document.querySelector(".boards__form--area")
let areaValue
form.addEventListener("submit", (e) => {
e.preventDefault()
})
addTaskBtn.addEventListener("click", () => {
form.style.display = "block"
addTaskBtn.style.display = "none"
addBtn.style.display = "none"
area.addEventListener("input", (e) => {
value = e.target.value
if (value) {
addBtn.style.display = "block"
} else {
addBtn.style.display = "none"
}
})
})
cancelBtn.addEventListener("click", () => {
area.value = ""
value = ""
form.style.display = "none"
addTaskBtn.style.display = "block"
})
addBtn.addEventListener("click", () => {
let newItem = document.createElement("div")
newItem.classList.add("boards__list--item")
newItem.setAttribute("draggable", "true")
newItem.textContent = value
lists[0].append(newItem)
form.style.display = "none"
addTaskBtn.style.display = "block"
area.value = ""
value = ""
dragNdrop()
})
}
addTask()
// ADD BOARD
function addBoard() {
const addBoard = document.querySelector(".addBoard")
const boards = document.querySelector(".boards")
addBoard.addEventListener("click", () => {
const board = document.createElement("div")
board.classList.add("boards__item")
board.innerHTML = `
<span class="boards__title" contenteditable="true"> Board's name </span>
<div class="boards__list"></div>
`
boards.append(board)
changeTitle()
dragNdrop()
})
}
addBoard()
// CHANGE TITLE
function changeTitle() {
const titles = document.querySelectorAll(".boards__title")
titles.forEach((item) => {
item.addEventListener("click", (e) => {
e.target.textContent = ""
})
})
}
changeTitle()
// DRAGNDROP
let dragItem = null
function dragNdrop() {
const listItem = document.querySelectorAll(".boards__list--item")
const lists = document.querySelectorAll(".boards__list")
listItem.forEach((item) => {
item.addEventListener("dragstart", function () {
dragItem = this
setTimeout(() => {
item.style.display = "none"
}, 0)
})
item.addEventListener("dragend", function () {
dragItem = null
setTimeout(() => {
item.style.display = "block"
}, 0)
})
})
lists.forEach((item) => {
item.addEventListener("dragover", function (e) {
e.preventDefault()
})
item.addEventListener("dragenter", function (e) {
e.preventDefault()
this.style.backgroundColor = "#959595"
this.style.borderRadius = "3px"
})
item.addEventListener("dragleave", function (e) {
e.preventDefault()
this.style.backgroundColor = "transparent"
})
item.addEventListener("drop", function (e) {
e.preventDefault()
this.style.backgroundColor = "transparent"
this.appendChild(dragItem)
})
})
}
dragNdrop()
// VARIABLES
$body-color: #0079bf;
$card-color: #ebecf0;
$text-color: #3e4f6b;
$footer-text-color: #7f8a9d;
$danger-color: #de350b;
$white-color: #ffff;
/* MAIN STYLES */
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
html {
overflow-x: hidden;
}
body {
margin: 0;
font-family: "Roboto", sans-serif;
font-size: 15px;
background-color: $body-color;
color: $white-color;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0;
padding: 0;
}
ul {
list-style: none;
}
a {
text-decoration: none;
}
/* CONTAINER */
.container {
width: 100%;
max-width: 1170px;
margin: 0 auto;
padding: 15px;
}
// BOARDS
.boards {
display: flex;
width: 100%;
&__item {
display: flex;
flex-direction: column;
align-self: baseline;
max-width: 270px;
width: 100%;
padding: 10px;
margin-left: 30px;
border-radius: 3px;
background-color: $card-color;
color: $text-color;
transition: all 0.2s ease;
&:first-child {
margin-left: 0;
}
&--add {
margin-top: 5px;
padding: 7px;
cursor: pointer;
border-radius: 3px;
color: $footer-text-color;
&:hover {
background-color: #091e4214;
}
}
}
&__title {
padding: 7px;
font-size: 15px;
font-weight: 500;
&:focus {
outline: 2px solid $body-color;
}
}
&__list {
// min-height: 35px;
&--item {
padding: 7px;
margin: 5px 0;
cursor: pointer;
background-color: $white-color;
border-radius: 3px;
font-weight: 400;
}
}
&__form {
margin-top: auto;
display: none;
border-radius: 3px;
&--area {
width: 100%;
padding: 7px;
resize: none;
outline: none;
border: 0;
border-radius: 3px;
background-color: $white-color;
color: $text-color;
}
}
&__buttons {
display: flex;
&--add {
padding: 10px 15px;
background-color: $body-color;
outline: none;
border: 0;
border-radius: 3px;
color: $white-color;
cursor: pointer;
}
&--cancel {
padding: 10px 15px;
margin-left: 5px;
background-color: $danger-color;
outline: none;
border: 0;
border-radius: 3px;
color: $white-color;
cursor: pointer;
}
}
}
.addBoard {
width: 200px;
padding: 10px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
position: absolute;
bottom: 50px;
left: 50%;
transform: translate(-50%);
background-color: #ffffff3d;
transition: 0.2s all ease;
&:hover {
background-color: #dedede;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Trello Clone</title>
<!-- GOOGLE FONTS -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap"
rel="stylesheet"
/>
<!-- CSS -->
<link rel="stylesheet" href="./assets/css/style.css" />
</head>
<body>
<!-- container -->
<div class="container">
<!-- boards -->
<div class="boards">
<!-- boards__item -->
<div class="boards__item">
<span class="boards__title" contenteditable="true">First board</span>
<!-- boards__list -->
<div class="boards__list">
<div class="boards__list--item" draggable="true">Starts card</div>
</div>
<!-- /boards__list -->
<form class="boards__form">
<textarea
id="boards__form--area"
class="boards__form--area"
placeholder="Card's name"
></textarea>
<div class="boards__buttons">
<button class="boards__buttons--add">Add card</button>
<button class="boards__buttons--cancel">Cancel</button>
</div>
</form>
<div class="boards__item--add"><span>+</span> Add card</div>
</div>
</div>
<!-- /boards -->
<div class="addBoard"><span>+</span> Add more board</div>
</div>
<!-- /container -->
<!-- JavaScript -->
<script src="./assets/js/app.js"></script>
</body>
</html>
Ответы (1 шт):
Автор решения: nazarpunk
→ Ссылка
Попробуйте так.
const list = document.querySelector('.list');
const listItems = document.querySelectorAll('.list-item');
const listHidden = document.querySelector('.list-hidden');
// let dragIndex, dragSource
const getMouseOffset = evt => {
const targetRect = evt.target.getBoundingClientRect();
const offset = {
x: evt.pageX - targetRect.left,
y: evt.pageY - targetRect.top
};
return offset;
};
const getElementVerticalCenter = el => {
const rect = el.getBoundingClientRect();
return (rect.bottom - rect.top) / 2;
};
const appendPlaceholder = (evt, idx) => {
evt.preventDefault();
if (idx === dragIndex) {
return;
}
const offset = getMouseOffset(evt);
const middleY = getElementVerticalCenter(evt.target);
const placeholder = list.children[dragIndex];
// console.log(`hover on ${idx} ${offset.y > middleY ? 'bottom half' : 'top half'}`)
if (offset.y > middleY) {
list.insertBefore(evt.target, placeholder);
} else if (list.children[idx + 1]) {
list.insertBefore(evt.target.nextSibling || evt.target, placeholder);
}
return;
};
function sortable(rootEl, onUpdate) {
var dragEl;
// Making all siblings movable
[].slice.call(rootEl.children).forEach(function(itemEl) {
itemEl.draggable = true;
});
// Function responsible for sorting
function _onDragOver(evt) {
evt.preventDefault();
evt.dataTransfer.dropEffect = 'move';
var target = evt.target;
if (target && target !== dragEl && target.nodeName == 'DIV') {
// Sorting
const offset = getMouseOffset(evt);
const middleY = getElementVerticalCenter(evt.target);
if (offset.y > middleY) {
rootEl.insertBefore(dragEl, target.nextSibling);
} else {
rootEl.insertBefore(dragEl, target);
}
}
}
// End of sorting
function _onDragEnd(evt) {
evt.preventDefault();
dragEl.classList.remove('ghost');
rootEl.removeEventListener('dragover', _onDragOver, false);
rootEl.removeEventListener('dragend', _onDragEnd, false);
// Notification about the end of sorting
onUpdate(dragEl);
}
// Sorting starts
rootEl.addEventListener('dragstart', function(evt) {
dragEl = evt.target; // Remembering an element that will be moved
// Limiting the movement type
evt.dataTransfer.effectAllowed = 'move';
evt.dataTransfer.setData('Text', dragEl.textContent);
// Subscribing to the events at dnd
rootEl.addEventListener('dragover', _onDragOver, false);
rootEl.addEventListener('dragend', _onDragEnd, false);
setTimeout(function() {
// If this action is performed without setTimeout, then
// the moved object will be of this class.
dragEl.classList.add('ghost');
}, 0);
}, false);
}
// Using
sortable(list, function(item) {
console.log(item);
});
.list {
background: #4286f4;
width: 500px;
padding: 1rem;
}
.list-hidden {
position: absolute;
top: -9999px;
left: -9999px;
}
.ghost {
opacity: .4;
}
.list-item {
background: #8bb3f4;
padding: 0.5rem;
border: 1px solid white;
margin: 1px 0;
}
.placeholder {
display: none;
background: #303742;
pointer-events: none;
}
<div class='list-hidden'></div>
<div class="list">
<div class="list-item" draggable=true>
Item 1
</div>
<div class="list-item" draggable=true>
Item 2
</div>
<div class="list-item" draggable=true>
Item 3
</div>
<div class="list-item" draggable=true>
Item 4
</div>
</div>