1. 시작
Drag And Drop 기능을 외부 Library없이 Javascript로 개발해보자.
이 프로젝트에서는 TypeScript로 작성이 되었으며, Html을 직접 작성하지 않고 코드화 되어 있다.
2. Draggable 속성 추가
우선 원하는 요소에 드래그가 가능하게 draggable 속성을 추가해준다.
export class Options extends FormItem {
panel : View;
options : Array<any> = [];
constructor(model : OptionModel, parent? : View) {
super("simms-options", parent);
const _this = this;
new Button({
name: I18n.get("add"),
listener: () => {
//실제로 드래그가 될 요소 생성
this.createOption();
}
}, this);
this.panel = new View("simms-option-list", this);
}
createOption(value? : string){
const optionTag = new View("simms-option", this.panel)
const option = new TextInput(optionTag);
if(value) option.value = value;
new Icon({name:"delete", listener: e => {this.delete(e);}}, optionTag);
//draggable 속성을 주어서 드래그가 가능하게 설정
optionTag.el.setAttribute("draggable", "true");
this.options?.push(option);
}
...
}
3. Drag에 따른 Event 설정
드래그의 start, end, over Event를 설정해 준다.
start와 end 이벤트는 드래그가 될 자식 요소에 작성하고, over 이벤트는 드래그가 될 요소의 부모 요소에 작성한다.
드래그시 바뀌어야될 위치는 getDragAfterElement 함수에서 계산한다.
...
createOption(value? : string){
const optionTag = new View("simms-option", this.panel)
const option = new TextInput(optionTag);
if(value) option.value = value;
new Icon({name:"delete", listener: e => {this.delete(e);}}, optionTag);
optionTag.el.setAttribute("draggable", "true");
optionTag.el.addEventListener("dragstart", () => {
//dragging 클래스는 css opacity : 0.5로 불투명하게 설정
optionTag.el.classList.add("dragging");
});
optionTag.el.addEventListener("dragend", () => {
optionTag.el.classList.remove("dragging");
});
//dragover는 drag가 되는 요소들의 부모 Element에서 작성
//여기서는 부모 요소가 this.panel 이다.
this.panel.el.addEventListener("dragover", e => {
//이 if문은 드래그앤드랍을 위로 했을 시 afterElement가 dragging과 같은 값으로 바뀌는 이슈 때문에 추가했다.
if(this.dragging != this.getDragAfterElement(e.clientY)) this.afterElement = this.getDragAfterElement(e.clientY);
const dragging = document.querySelector(".dragging");
if(dragging) this.panel.el.insertBefore(dragging, afterElement);
});
this.options?.push(option);
}
getDragAfterElement(y : number){
return this.options.reduce(
(closest, currentValue) => {
const child = currentValue.el.parentElement;
const box = child.getBoundingClientRect();
const offset = y - box.top - box.height / 2;
if(offset < 0 && offset > closest.offset) return {offset: offset, element: child};
else return closest;
}
, {offset: Number.NEGATIVE_INFINITY}
).element;
}
...
Reduce 함수의 자세한 설명은 아래 링크 참조
https://pinokio5600.tistory.com/69
Array.reduce()
1. 설명 배열의 각 요소에 Reducer 함수를 실행하고, 하나의 결과값( 누산값 )을 반환한다. arr.reduce(callback[, initialValue]); 2. 매개변수 callback : 배열의 각 요소에 대해 실행할 함수. 네 개의 인수를 받
pinokio5600.tistory.com
반응형
'Client Side' 카테고리의 다른 글
forEach 순차처리의 불가능 (for문, for of문의 순차처리) (0) | 2023.04.06 |
---|---|
Array.reduce() (0) | 2023.04.05 |
Modal Drag (0) | 2023.02.22 |
Datepicker MinDate (0) | 2023.01.30 |
필수사항 체크 (0) | 2023.01.27 |