Angular 6 变换动画不会改变元素的样式

Angular 6 Transform Animation doesn't change styles on Element

要点

我正在用 Angular6 创建一个图像滑块,它可以通过拖动来移动。位置通过 transform: translateX(percentage) 更改。当用户不再单击时,我正在为 x 位置设置动画。

问题

显示问题 in this video

(1) 动画有效但未更改元素的 transform 样式。 (所以动画结束后translateX的值是错误的)

(2)动画一次后,拖动不再起作用(仅在破坏动画时,会导致奇怪的行为)

代码

Html:

<div
    class="slider"
    (mousedown)="onMouseDown($event)"
    (touchstart)="onTouchStart($event)"
    (mouseup)="onMouseUp($event)"
    (touchend)="onTouchEnd($event)"
    (mousemove)="onMouseMove($event)"
    (touchmove)="onTouchMove($event)"
    (mouseleave)="onMouseLeave($event)"
    #slider
>

    <div
        class="vis-container"
        [style.transform]="translateXValue"
        [class.grabbing]="grabbing"
        [class.grab]="!grabbing"
        #container
    >
        <div
            class="item"
            *ngFor="let i of images; let j = index"
            [style.left]="j * 100 + '%'"
        >
            <img
                dyImagePositioning
                src="{{i}}"
            >
        </div>
    </div>
    <div>{{translateXValue}}</div>
</div>

打字稿:

images: string[] = [
        'https://images.unsplash.com/photo-1533147722845-4078740ae714?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=c8e866ca41f36ad560c435c1bb51e0fd&auto=format&fit=crop&w=1350&q=80',
        'https://images.unsplash.com/photo-1504415724575-56cef5e3da72?ixlib=rb-0.3.5&s=89c39a767a764693bcc2e2c2ecad59ce&auto=format&fit=crop&w=1350&q=80',
        'https://s3.eu-central-1.amazonaws.com/drakery-4/product-files/5b5c8d96823eba53e45ba5ac/5b5c8d9a823eba53e45ba5ad-normal.webp',
    ];

    grabbing: boolean = false;
    startX: number;
    startXPerc: number;
    translateX: number = 0;
    animationDurance: number = 300;

    @ViewChild('slider') slider;
    @ViewChild('container') container;

    constructor(
        private builder: AnimationBuilder,
    ) { }

    ngOnInit(): void { }

    start(pageX: number): void {
        this.grabbing = true;
        this.startX = pageX - this.slider.nativeElement.offsetLeft;
        this.startXPerc = this.translateX;
    }
    onMouseDown(event: MouseEvent): void {
        this.start(event.pageX);
    }
    onTouchStart(event: TouchEvent): void {
        this.start(event.changedTouches[0].pageX);
    }

    end(): void {
        this.grabbing = false;
        const endX = Math.round(this.translateX / 100) * 100;
        const animationFactory = this.builder.build(this.translate(
            this.translateX,
            endX,
        ));
        const animationPlayer: AnimationPlayer = animationFactory.create(this.container.nativeElement);
        animationPlayer.play();
        // Destroying the animation makes it able
        // to drag again, but results in weird behaviour
        /* animationPlayer.onDone(() => {
            animationPlayer.destroy();
        }) */
    }
    onMouseUp(event: MouseEvent): void {
        this.end();
    }
    onTouchEnd(event: TouchEvent): void {
        this.end();
    }

    move(pageX: number): void {
        if (!this.grabbing) return;
        event.preventDefault();
        const x = pageX - this.slider.nativeElement.offsetLeft;
        const diff = this.startX - x;
        const diffPerc = 100 * diff / this.slider.nativeElement.offsetWidth;
        this.translateX = this.startXPerc - diffPerc;
    }
    onMouseMove(event: MouseEvent): void {
        this.move(event.pageX);
    }
    onTouchMove(event: TouchEvent): void {
        this.move(event.changedTouches[0].pageX);
    }

    onMouseLeave(event: MouseEvent): void {
        if (!this.grabbing) return;
        this.grabbing = false;
        this.end();
    }

    get translateXValue(): string {
        return `translateX(${this.translateX}%)`
    }

    private translate(startX: number, endX: number): AnimationMetadata[] {
        return [
            style({ transform: `translateX(${startX}%)` }),
            animate(`${this.animationDurance}ms ease-out`, style({ transform: `translateX(${endX}%)` })),
        ];
    }

在您的情况下,我会放弃 angular 动画,而只使用 css 动画。 所以在你的情况下它会是这样的:

.slider
    ...
    transition-duration: 500ms
    transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1)

我遇到了和你一样的问题。仅销毁动画是不够的,因为样式 属性 被重置为动画之前的状态,因此具有不希望的行为。在 onDone 回调中,您应该在销毁动画之前,将新样式 属性 设置为元素:

// ...

animation.onDone(() => {
  this.container.nativeElement.style.transform = this.translate(
    this.translateX,
    endX,
  );
  animation.destroy();
});