각도 방향으로 자유롭게 드래그하기 위한 명령 생성
42149 단어 draggabledirectiveangulartypescript
인코딩을 시작해보도록 하겠습니다.
1 기본 자유 드래그 명령 만들기
우리는 우선 간단한 기본 명령을 만들고 더 많은 기능을 추가할 것이다.
1.1 작업공간 만들기
npm i -g @angular/cli
ng new angular-free-dragging --defaults --minimal
Do not use --minimal
option in production applications, it creates a workspace without any testing frameworks. You can read more about CLI options.
1.2 공유 모듈 만들기
ng g m shared
1.3.1 자유 드래그 명령 만들기
ng g d shared/free-dragging
1.3.2 수출지령
만든 후 공유 모듈의 내보내기 배열에 추가합니다.
// src/app/shared/shared.module.ts
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { FreeDraggingDirective } from "./free-dragging.directive";
@NgModule({
declarations: [FreeDraggingDirective],
imports: [CommonModule],
exports: [FreeDraggingDirective], // Added
})
export class SharedModule {}
1.3.3 자유 드래그 논리
자유롭게 드래그하려면 다음과 같이 하십시오.
npm i -g @angular/cli
ng new angular-free-dragging --defaults --minimal
Do not use --minimal
option in production applications, it creates a workspace without any testing frameworks. You can read more about CLI options.
ng g m shared
ng g d shared/free-dragging
// src/app/shared/shared.module.ts
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { FreeDraggingDirective } from "./free-dragging.directive";
@NgModule({
declarations: [FreeDraggingDirective],
imports: [CommonModule],
exports: [FreeDraggingDirective], // Added
})
export class SharedModule {}
mousedown
사건.이것은 드래그 시작 트리거로 사용할 것입니다.mousemove
이벤트를 듣습니다.이것은 드래그 트리거로 작동합니다.또한 마우스 포인터를 기준으로 요소의 위치도 업데이트됩니다.mouseup
이벤트를 듣습니다.이것은 드래그 끝 트리거로 사용할 것입니다.이것으로 우리는 청취를 중지할 것이다mousemove
사건.// src/app/shared/free-dragging.directive.ts
@Directive({
selector: "[appFreeDragging]",
})
export class FreeDraggingDirective implements OnInit, OnDestroy {
private element: HTMLElement;
private subscriptions: Subscription[] = [];
constructor(
private elementRef: ElementRef,
@Inject(DOCUMENT) private document: any
) {}
ngOnInit(): void {
this.element = this.elementRef.nativeElement as HTMLElement;
this.initDrag();
}
initDrag(): void {
// main logic will come here
}
ngOnDestroy(): void {
this.subscriptions.forEach((s) => s.unsubscribe());
}
}
위 코드에서 우리는 주로 세 가지 일을 한다.// src/app/shared/free-dragging.directive.ts
...
initDrag(): void {
// 1
const dragStart$ = fromEvent<MouseEvent>(this.element, "mousedown");
const dragEnd$ = fromEvent<MouseEvent>(this.document, "mouseup");
const drag$ = fromEvent<MouseEvent>(this.document, "mousemove").pipe(
takeUntil(dragEnd$)
);
// 2
let initialX: number,
initialY: number,
currentX = 0,
currentY = 0;
let dragSub: Subscription;
// 3
const dragStartSub = dragStart$.subscribe((event: MouseEvent) => {
initialX = event.clientX - currentX;
initialY = event.clientY - currentY;
this.element.classList.add('free-dragging');
// 4
dragSub = drag$.subscribe((event: MouseEvent) => {
event.preventDefault();
currentX = event.clientX - initialX;
currentY = event.clientY - initialY;
this.element.style.transform =
"translate3d(" + currentX + "px, " + currentY + "px, 0)";
});
});
// 5
const dragEndSub = dragEnd$.subscribe(() => {
initialX = currentX;
initialY = currentY;
this.element.classList.remove('free-dragging');
if (dragSub) {
dragSub.unsubscribe();
}
});
// 6
this.subscriptions.push.apply(this.subscriptions, [
dragStartSub,
dragSub,
dragEndSub,
]);
}
...
[fromEvent](https://rxjs.dev/api/index/function/fromEvent)
함수에서 본 것이다.mousedown
우리 요소에 관한 사건을 들을 것이다.사용자가 마우스를 누르면, 우리는 초기 위치를 저장하고, 클래스 free-dragging
를 추가합니다. 이 클래스는 요소에 아름다운 음영을 추가합니다.mousemove
이벤트의 구독 서버에서 mousedown
이벤트를 감청하는 이유입니다.사용자가 마우스를 이동할 때, 우리도 transform 속성을 사용하여 마우스의 위치를 업데이트합니다.mouseup
사건을 듣고 있다.여기서 다음 드래그를 위해 초기 위치를 다시 업데이트합니다.free-dragging
클래스를 삭제하고 있습니다.ngOnDestroy
에서 구독을 취소할 수 있습니다.1.3.4 AppComponent 업데이트
컨텐트를 다음과 같이 바꿉니다.
// src/app/app.component.ts
import { Component } from "@angular/core";
@Component({
selector: "app-root",
// 1 use directive
template: ` <div class="example-box" appFreeDragging>Drag me around</div> `,
// 2 some helper styles
styles: [
`
.example-box {
width: 200px;
height: 200px;
border: solid 1px #ccc;
color: rgba(0, 0, 0, 0.87);
cursor: move;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
background: #fff;
border-radius: 4px;
position: relative;
z-index: 1;
transition: box-shadow 200ms cubic-bezier(0, 0, 0.2, 1);
box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2),
0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
}
.example-box.free-dragging {
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12);
}
`,
],
})
export class AppComponent {}
위의 코드는 매우 간단명료하다.이를 실행하려면 다음과 같이 하십시오.ng serve
출력을 보려면 다음과 같이 하십시오.현재 명령에서는 요소의 아무 곳에서나 마우스를 누른 채 이동하여 요소를 드래그할 수 있습니다.이렇게 하는 것은 텍스트 선택 등 다른 조작에서 매우 어렵다는 단점이 있다.더 실제적인 장면에서, 예를 들어 작은 위젯 같은 경우, 드래그를 편리하게 하기 위해 손잡이가 필요하다.
2. 드래그 핸들 지원 추가
우리는 명령을 다시 만들고 주 명령에
@ContentChild
접근해서 드래그 핸들에 대한 지원을 추가할 것입니다.2.1 드래그 핸들에 대한 명령 생성
ng g d shared/free-dragging-handle
2.2 공유 모듈에서 내보내기
// src/app/shared/shared.module.ts
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { FreeDraggingDirective } from "./free-dragging.directive";
import { FreeDraggingHandleDirective } from './free-dragging-handle.directive';
@NgModule({
declarations: [FreeDraggingDirective, FreeDraggingHandleDirective],
imports: [CommonModule],
exports: [FreeDraggingDirective, FreeDraggingHandleDirective], // Modified
})
export class SharedModule {}
2.3 드래그 핸들에서 ElementRef로 돌아가기
우리는 draghandle의 요소만 있으면 다음 작업을 완성할 수 있으며
ElementRef
를 사용하여 같은 기능을 실현할 수 있다.// src/app/shared/free-dragging-handle.directive.ts
import { Directive, ElementRef } from "@angular/core";
@Directive({
selector: "[appFreeDraggingHandle]",
})
export class FreeDraggingHandleDirective {
constructor(public elementRef: ElementRef<HTMLElement>) {} // Modified
}
2.4 손잡이로 드래그
논리는 다음과 같습니다.
mousedown
사건을 탐지하다.이것은 드래그 시작 트리거로 사용할 것입니다.mousemove
이벤트를 듣습니다.이것은 드래그 트리거로 작동합니다.또한 마우스 포인터에 따라 핸들 요소뿐만 아니라 주 요소의 위치도 업데이트됩니다.mouseup
이벤트를 듣습니다.이것은 드래그 끝 트리거로 사용할 것입니다.이것으로 우리는 청취를 중지할 것이다mousemove
사건.mousedown
사건을 들을 것이다.인코딩으로 돌아가겠습니다.
// src/app/shared/free-dragging.directive.ts
...
@Directive({
selector: "[appFreeDragging]",
})
export class FreeDraggingDirective implements AfterViewInit, OnDestroy {
private element: HTMLElement;
private subscriptions: Subscription[] = [];
// 1 Added
@ContentChild(FreeDraggingHandleDirective) handle: FreeDraggingHandleDirective;
handleElement: HTMLElement;
constructor(...) {}
// 2 Modified
ngAfterViewInit(): void {
this.element = this.elementRef.nativeElement as HTMLElement;
this.handleElement = this.handle?.elementRef?.nativeElement || this.element;
this.initDrag();
}
initDrag(): void {
// 3 Modified
const dragStart$ = fromEvent<MouseEvent>(this.handleElement, "mousedown");
// rest remains same
}
...
}
우리가 한 것은 코드가 논리에서 설명한 것과 같다.현재 우리가 사용하고 있는 것은 ngOnInit
이 아니라 ngAfterViewInit
입니다. 구성 요소의 보기가 완전히 초기화되었는지 확인하고 싶으므로 존재하면 FreeDraggingDirective
를 얻을 수 있습니다.너는 Angular - Hooking into the component lifecycle에서 이 방면에 관한 더 많은 정보를 읽을 수 있다.2.5 AppComponent 업데이트
// src/app/app.component.ts
@Component({
selector: "app-root",
template: `
<!-- 1 use directive -->
<div class="example-box" appFreeDragging>
I can only be dragged using the handle
<!-- 2 use handle directive -->
<div class="example-handle" appFreeDraggingHandle>
<svg width="24px" fill="currentColor" viewBox="0 0 24 24">
<path
d="M10 9h4V6h3l-5-5-5 5h3v3zm-1 1H6V7l-5 5 5 5v-3h3v-4zm14 2l-5-5v3h-3v4h3v3l5-5zm-9 3h-4v3H7l5 5 5-5h-3v-3z"
></path>
<path d="M0 0h24v24H0z" fill="none"></path>
</svg>
</div>
</div>
`,
// 3 helper styles
styles: [
`
.example-box {
width: 200px;
height: 200px;
padding: 10px;
box-sizing: border-box;
border: solid 1px #ccc;
color: rgba(0, 0, 0, 0.87);
display: flex;
justify-content: center;
align-items: center;
text-align: center;
background: #fff;
border-radius: 4px;
position: relative;
z-index: 1;
transition: box-shadow 200ms cubic-bezier(0, 0, 0.2, 1);
box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2),
0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
}
.example-box.free-dragging {
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12);
}
.example-handle {
position: absolute;
top: 10px;
right: 10px;
color: #ccc;
cursor: move;
width: 24px;
height: 24px;
}
`,
],
})
export class AppComponent {}
출력을 살펴보겠습니다.다행이다. 우리는 우리가 필요로 하는 것을 거의 실현했다.
그러나 그것은 여전히 문제가 있다.사용자는 요소를 뷰 외부로 이동할 수 있습니다.
3. 경계 드래그 지원 추가
국경에 대한 지원을 추가할 때가 되었다.경계는 요소를 원하는 영역 내에 유지하는 데 도움을 줍니다.
3.1 업데이트 명령
우리는 이러한 경계를 지지할 것이다.
@Input
를 추가합니다.기본적으로 우리는 그것을 body
에 유지한다.querySelector
로 경계원을 얻을 수 있는지 검사합니다. 만약 오류가 발생하지 않았다면.// src/app/shared/free-dragging.directive.ts
...
@Directive({
selector: "[appFreeDragging]",
})
export class FreeDraggingDirective implements AfterViewInit, OnDestroy {
...
// 1 Added
private readonly DEFAULT_DRAGGING_BOUNDARY_QUERY = "body";
@Input() boundaryQuery = this.DEFAULT_DRAGGING_BOUNDARY_QUERY;
draggingBoundaryElement: HTMLElement | HTMLBodyElement;
...
// 2 Modified
ngAfterViewInit(): void {
this.draggingBoundaryElement = (this.document as Document).querySelector(
this.boundaryQuery
);
if (!this.draggingBoundaryElement) {
throw new Error(
"Couldn't find any element with query: " + this.boundaryQuery
);
} else {
this.element = this.elementRef.nativeElement as HTMLElement;
this.handleElement =
this.handle?.elementRef?.nativeElement || this.element;
this.initDrag();
}
}
initDrag(): void {
...
// 3 Min and max boundaries
const minBoundX = this.draggingBoundaryElement.offsetLeft;
const minBoundY = this.draggingBoundaryElement.offsetTop;
const maxBoundX =
minBoundX +
this.draggingBoundaryElement.offsetWidth -
this.element.offsetWidth;
const maxBoundY =
minBoundY +
this.draggingBoundaryElement.offsetHeight -
this.element.offsetHeight;
const dragStartSub = dragStart$.subscribe((event: MouseEvent) => {
...
dragSub = drag$.subscribe((event: MouseEvent) => {
event.preventDefault();
const x = event.clientX - initialX;
const y = event.clientY - initialY;
// 4 Update position relatively
currentX = Math.max(minBoundX, Math.min(x, maxBoundX));
currentY = Math.max(minBoundY, Math.min(y, maxBoundY));
this.element.style.transform =
"translate3d(" + currentX + "px, " + currentY + "px, 0)";
});
});
const dragEndSub = dragEnd$.subscribe(() => {
initialX = currentX;
initialY = currentY;
this.element.classList.remove("free-dragging");
if (dragSub) {
dragSub.unsubscribe();
}
});
this.subscriptions.push.apply(this.subscriptions, [
dragStartSub,
dragSub,
dragEndSub,
]);
}
}
요소를 드래그할 수 있도록 body
의 높이를 100%로 설정해야 합니다.// src/styles.css
html,
body {
height: 100%;
}
이제 출력을 살펴보겠습니다.이렇게!영예🎉😀👍
결론
빠르게 수정:
✔️ 우리는 자유 드래그 명령을 만들었다
✔️ 그런 다음 사용자가 요소에 대해 다른 작업을 수행할 수 있도록 드래그 핸들에 대한 지원이 추가되었습니다.
✔️ 마지막으로 경계 요소를 추가하여 요소를 특정 경계 안으로 드래그하는 데 도움이 됩니다.
✔️ 이 모든 것은 제3자 창고가 없다😉
추가 기능을 추가할 수 있는 기능은 다음과 같습니다.
Github에 제공된 모든 코드는 다음과 같습니다.
슈다만 / 모서리 자유 드래그
Angular에서 모든 요소를 자유롭게 드래그할 수 있는 명령을 만듭니다. 제3자 라이브러리를 사용하지 않아도 됩니다.
각도 방향으로 자유롭게 드래그하기 위한 명령 생성
본고에서 우리는 Angular에서 명령을 만드는 방법을 배워서 제3자 라이브러리를 사용하지 않고 요소를 자유롭게 드래그할 수 있도록 할 것이다.
읽다
이 코드는 indepth에 있는 글을 위한 것입니다.데이브, Create a directive for free dragging in Angular 에서 읽을 수 있습니다.
발전시키다
git 클론https://github.com/shhdharmen/angular-free-dragging.git
모서리 없는 드래그
npm i
npm 시작
View on GitHub
본문을 읽어 주셔서 감사합니다.평론 부분에서 너의 생각과 피드백을 나에게 말해라.
크레디트
본문을 작성할 때, 나는 w3schools와 stackoverflow의 코드 세션을 참고했다.
Reference
이 문제에 관하여(각도 방향으로 자유롭게 드래그하기 위한 명령 생성), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/shhdharmen/create-a-directive-for-free-dragging-in-angular-goa
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Reference
이 문제에 관하여(각도 방향으로 자유롭게 드래그하기 위한 명령 생성), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/shhdharmen/create-a-directive-for-free-dragging-in-angular-goa텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)