如何使用 Rx 在 Angular 2 中实现可拖动的 div [英] How to implement a draggable div in Angular 2 using Rx

查看:26
本文介绍了如何使用 Rx 在 Angular 2 中实现可拖动的 div的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试使用 Angular 2 获得可拖动的 div.我正在使用 这个例子来自angular2-examples repo 作为起点,只是真正调整代码以解决toRx()方法.该代码有效,但它不考虑 mouseout 事件.这意味着如果我点击一个 Draggable div,然后移动鼠标 缓慢,div 将随鼠标移动.但是,如果我将鼠标移动得太快,则会发送 mouseout 事件而不是 mousemove 事件,并且拖动停止.

如何在鼠标移动到触发 mouseout 事件后继续拖动?我尝试将 mouseout 事件流与 mousemove 合并,这样 mouseout 事件就像 mousemove> 那些,但这不起作用.

我使用的是 Angular 2.0.0-beta.12.

从'angular2/core'导入{Component, Directive, HostListener, EventEmitter, ElementRef, OnInit};从'rxjs/Rx'导入{地图,合并};@指示({选择器:'[可拖动]'})导出类 Draggable 实现 OnInit {mouseup = new EventEmitter();mousedown = new EventEmitter();mousemove = new EventEmitter();mouseout = new EventEmitter();@HostListener('mouseup', ['$event'])onMouseup(事件){this.mouseup.emit(事件);}@HostListener('mousedown', ['$event'])onMousedown(事件){this.mousedown.emit(事件);返回假;//在事件上调用 preventDefault()}@HostListener('mousemove', ['$event'])onMousemove(事件){this.mousemove.emit(事件);}@HostListener('mouseout', ['$event'])onMouseout(事件){this.mouseout.emit(事件);返回假;//在事件上调用 preventDefault()}构造函数(公共元素:ElementRef){this.element.nativeElement.style.position = 'relative';this.element.nativeElement.style.cursor = '指针';地图;合并;this.mousedrag = this.mousedown.map(event => {返回 {顶部: event.clientY - this.element.nativeElement.getBoundingClientRect().top左:event.clientX - this.element.nativeElement.getBoundingClientRect().left,};}).flatMap(图像偏移 =>this.mousemove.merge(this.mouseout).map(pos => ({顶部:pos.clientY - imageOffset.top,左:pos.clientX - imageOffset.left})).takeUntil(this.mouseup));}ngOnInit() {this.mousedrag.subscribe({下一个: pos =>{this.element.nativeElement.style.top = pos.top + 'px';this.element.nativeElement.style.left = pos.left + 'px';}});}}@成分({选择器:'我的应用',模板:`<div可拖动><h1>你好,世界!</h1>

`,指令:[可拖动,],})导出类 AppComponent {}

解决方案

我在 RxJs 如何处理文档事件.问题的关键是鼠标事件仅在鼠标悬停在该元素上时才会发送到该元素.所以我们确实希望 mousedown 事件仅限于特定元素,但我们必须跟踪 global mousemovemouseup 事件.这是新代码.注意在 onMouseuponMousemove 上使用 @HostListener 装饰器将目标指定为 document:mouseup文档:鼠标移动.这就是全局事件通过管道传输到 Rx 流的方式.

HostListener 的官方 angular2 文档t 提到这个 target:eventName 语法,但是 2.0.0-alpha.24 的旧 dart 文档 确实提到了它.它似乎仍然适用于 2.0.0-beta.12.

@Directive({选择器:'[可拖动]'})导出类 Draggable 实现 OnInit {mouseup = new EventEmitter();mousedown = new EventEmitter();mousemove = new EventEmitter();mousedrag: Observable<{top, left}>;@HostListener('document:mouseup', ['$event'])onMouseup(事件:MouseEvent){this.mouseup.emit(事件);}@HostListener('mousedown', ['$event'])onMousedown(事件:MouseEvent){this.mousedown.emit(事件);返回假;//在事件上调用 preventDefault()}@HostListener('document:mousemove', ['$event'])onMousemove(事件:MouseEvent){this.mousemove.emit(事件);}构造函数(公共元素:ElementRef){this.element.nativeElement.style.position = 'relative';this.element.nativeElement.style.cursor = '指针';this.mousedrag = this.mousedown.map(event => {返回 {顶部: event.clientY - this.element.nativeElement.getBoundingClientRect().top左:event.clientX - this.element.nativeElement.getBoundingClientRect().left,};}).flatMap(图像偏移 =>this.mousemove.map(pos => ({顶部:pos.clientY - imageOffset.top,左:pos.clientX - imageOffset.left})).takeUntil(this.mouseup));}ngOnInit() {this.mousedrag.subscribe({下一个: pos =>{this.element.nativeElement.style.top = pos.top + 'px';this.element.nativeElement.style.left = pos.left + 'px';}});}}

I've been trying to get a draggable div working using Angular 2. I'm using this example from the angular2-examples repo as a starting point, only really adjusting the code to account for the removal of the toRx() method. The code works, but it does not account for mouseout events. This means that if I click on a Draggable div, and move the mouse slowly, the div will move with the mouse. But if I move the mouse too fast, a mouseout event is sent instead of a mousemove event, and the dragging stops.

How can I keep the drag going after the mouse is moved so far that a mouseout event is fired? I've tried merging the mouseout event stream with the mousemove one, so that mouseout events are treated just like mousemove ones, but that doesn't work.

I'm using Angular 2.0.0-beta.12.

import {Component, Directive, HostListener, EventEmitter, ElementRef, OnInit} from 'angular2/core';
import {map, merge} from 'rxjs/Rx';

@Directive({
    selector: '[draggable]'
})
export class Draggable implements OnInit {

    mouseup = new EventEmitter();
    mousedown = new EventEmitter();
    mousemove = new EventEmitter();
    mouseout = new EventEmitter();

    @HostListener('mouseup', ['$event'])
    onMouseup(event) {
        this.mouseup.emit(event);
    }

    @HostListener('mousedown', ['$event'])
    onMousedown(event) {
        this.mousedown.emit(event);
        return false; // Call preventDefault() on the event
    }

    @HostListener('mousemove', ['$event'])
    onMousemove(event) {
        this.mousemove.emit(event);
    }

    @HostListener('mouseout', ['$event'])
    onMouseout(event) {
        this.mouseout.emit(event);
        return false; // Call preventDefault() on the event
    }

    constructor(public element: ElementRef) {
        this.element.nativeElement.style.position = 'relative';
        this.element.nativeElement.style.cursor = 'pointer';

        map;
        merge;
        this.mousedrag = this.mousedown.map(event => {
            return {
                top: event.clientY - this.element.nativeElement.getBoundingClientRect().top
                left: event.clientX - this.element.nativeElement.getBoundingClientRect().left,
            };
        })
        .flatMap(
            imageOffset => this.mousemove.merge(this.mouseout).map(pos => ({
                top: pos.clientY - imageOffset.top,
                left: pos.clientX - imageOffset.left
            }))
            .takeUntil(this.mouseup)
        );
    }

    ngOnInit() {
        this.mousedrag.subscribe({
            next: pos => {
                this.element.nativeElement.style.top = pos.top + 'px';
                this.element.nativeElement.style.left = pos.left + 'px';
            }
        });
    }
}

@Component({
    selector: 'my-app',
    template: `
        <div draggable>
            <h1>Hello, World!</h1>
        </div>
        `,
    directives: [Draggable,],
})
export class AppComponent {
}

解决方案

I found the answer to this in RxJs How do deal with document events. The crux of the problem is that mouse events are only sent to an element when the mouse is over that element. So we do want the mousedown event limited to specific element, but we have to track global mousemove and mouseup events. Here's the new code. Notice the use of the @HostListener decorator on onMouseup and onMousemove specifies the target as document:mouseup and document:mousemove. This is how the global events are piped into the Rx stream.

The official angular2 documentation for HostListener doesn't mention this target:eventName syntax, but this old dart documentation for 2.0.0-alpha.24 does mention it. It seems to still work in 2.0.0-beta.12.

@Directive({
    selector: '[draggable]'
})
export class Draggable implements OnInit {

    mouseup = new EventEmitter<MouseEvent>();
    mousedown = new EventEmitter<MouseEvent>();
    mousemove = new EventEmitter<MouseEvent>();

    mousedrag: Observable<{top, left}>;

    @HostListener('document:mouseup', ['$event'])
    onMouseup(event: MouseEvent) {
        this.mouseup.emit(event);
    }

    @HostListener('mousedown', ['$event'])
    onMousedown(event: MouseEvent) {
        this.mousedown.emit(event);
        return false; // Call preventDefault() on the event
    }

    @HostListener('document:mousemove', ['$event'])
    onMousemove(event: MouseEvent) {
        this.mousemove.emit(event);
    }

    constructor(public element: ElementRef) {
        this.element.nativeElement.style.position = 'relative';
        this.element.nativeElement.style.cursor = 'pointer';

        this.mousedrag = this.mousedown.map(event => {
            return {
                top: event.clientY - this.element.nativeElement.getBoundingClientRect().top
                left: event.clientX - this.element.nativeElement.getBoundingClientRect().left,
            };
        })
        .flatMap(
            imageOffset => this.mousemove.map(pos => ({
                top: pos.clientY - imageOffset.top,
                left: pos.clientX - imageOffset.left
            }))
            .takeUntil(this.mouseup)
        );
    }

    ngOnInit() {
        this.mousedrag.subscribe({
            next: pos => {
                this.element.nativeElement.style.top = pos.top + 'px';
                this.element.nativeElement.style.left = pos.left + 'px';
            }
        });
    }
}

这篇关于如何使用 Rx 在 Angular 2 中实现可拖动的 div的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆