簡體   English   中英

How can I use my logo slider JavaScript function inside an Angular component / TypeScript?

[英]How can I use my logo slider JavaScript function inside an Angular component / TypeScript?

由於我對 Angular 很陌生,我需要你的幫助。 我看了很多教程並嘗試了很多東西,但這次我需要將 JavaScript function 合並到我的 Angular 組件中。

這是我想在 Angular 中使用的實際 slider(非常感謝 SomoKRoceS):

 document.getElementsByTagName("body")[0].onload = createAnimation; function createAnimation(){ let e = document.getElementById("logo-gallery"); // Get the element var style = document.createElement('style'); // Create styling element style.type = 'text/css'; // Append a css type // Now create the dynamic keyFrames (that are depend on logo-gallery final width) // Notice that the width of e is given to translateX at 100% let keyframes = '\ @keyframes scroll-left {\ 0% {\ transform: translateX(0);\ }\ 100% {\ transform: translateX(-'+e.scrollWidth+'px);\ }\ }'; style.innerHTML = keyframes; // Set innerHTML of the styling element to the keyframe document.getElementsByTagName('head')[0].appendChild(style); // append the element to the head of the document as a stylesheet e.setAttribute("style","animation: scroll-left 20s linear infinite; animation-iteration-count: infinite;"); // Give the element its animation properties. }
 #logo-gallery-wrapper { overflow: hidden; position: relative; } #logo-gallery { margin: 0; padding: 0; position: relative; list-style-type: none; display: flex; } #logo-gallery.logo-gallery-figure { margin: 0; padding: 0 1.6rem; overflow: hidden; } #logo-gallery.logo-gallery-figure img { height: auto; max-height: 50px; position: relative; filter: grayscale(1); transition: all.4s; } #logo-gallery.logo-gallery-figure img:hover { filter: grayscale(0); }
 <div id="logo-gallery-wrapper"> <ul id="logo-gallery"> <li> <figure class="logo-gallery-figure"> <img src="https://www.ikea.com/de/de/static/ikea-logo.f88b07ceb5a8c356b7a0fdcc9a563d63.svg"> </figure> </li> <li> <figure class="logo-gallery-figure"> <img src="https://www.ikea.com/de/de/static/ikea-logo.f88b07ceb5a8c356b7a0fdcc9a563d63.svg"> </figure> </li> <li> <figure class="logo-gallery-figure"> <img src="https://www.ikea.com/de/de/static/ikea-logo.f88b07ceb5a8c356b7a0fdcc9a563d63.svg"> </figure> </li> <li> <figure class="logo-gallery-figure"> <img src="https://www.ikea.com/de/de/static/ikea-logo.f88b07ceb5a8c356b7a0fdcc9a563d63.svg"> </figure> </li> <li> <figure class="logo-gallery-figure"> <img src="https://www.ikea.com/de/de/static/ikea-logo.f88b07ceb5a8c356b7a0fdcc9a563d63.svg"> </figure> </li> <li> <figure class="logo-gallery-figure"> <img src="https://www.ikea.com/de/de/static/ikea-logo.f88b07ceb5a8c356b7a0fdcc9a563d63.svg"> </figure> </li> <li> <figure class="logo-gallery-figure"> <img src="https://www.ikea.com/de/de/static/ikea-logo.f88b07ceb5a8c356b7a0fdcc9a563d63.svg"> </figure> </li> </ul> </div>

實際上,我的組件帶有.css.html.ts文件。 HTML 和 CSS 文件的內容屬於此處的內容,但現在我不知何故需要將 JavaScript 轉換為 ZCDE41C335EF37218。 這是我的.ts文件:

import { Component, Input } from '@angular/core';

@Component({
  selector   : 'app-logo-gallery',
  templateUrl: './logo-gallery.component.html',
  styleUrls  : ['./logo-gallery.component.css']
})
export class LogoGalleryComponent {

  @Input()
  logos: string[];

  constructor() {
  }
}

我知道 @Component 裝飾器中有一個動畫命令可用,但這是正確的方法嗎?如果是,我該如何在那里使用它? 關鍵是我需要以某種方式計算滾動寬度並將其設置為關鍵幀,否則 animation 將出現故障。

我已經知道我可以通過這種方式獲取元素的寬度:

HTML

<ul id="logo-gallery" #logoGallery>

TypeScript class

@ViewChild('logoGallery', {static: false}) logoGallery: ElementRef;

this.logoGallery.nativeElement.offsetWidth

謝謝你的幫助!

您可以將 js function 放入組件中。 演示

import { Component, OnInit } from "@angular/core";

function createAnimation() {
  let e = document.getElementById("logo-gallery");
  var style = document.createElement("style");
  style.type = "text/css";
  let keyframes =
    "@keyframes scroll-left { 0% {transform: translateX(0);}100% {transform: translateX(-" +
    e.scrollWidth +
    "px); }}";
  style.innerHTML = keyframes;
  document.getElementsByTagName("head")[0].appendChild(style);
  e.setAttribute(
    "style",
    "animation: scroll-left 20s linear infinite; animation-iteration-count: infinite;"
  );
}
@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent implements OnInit {
  name = "Angular";
  ngOnInit() {
    createAnimation();
  }
}

但我一般不選擇使用 function 作為一種方式,我選擇在組件 css Demo中放置一個 css

@keyframes scroll-left 
{
   0% {transform: translateX(0)}
  100% {transform: translateX(var(--m,100%))}
}

並將 animation 給 css

#logo-gallery {
  animation: scroll-left 20s linear infinite; 
  animation-iteration-count: infinite;
}

並與 Viwchild

 @ViewChild('logoGallery', {static: false}) logoGallery: ElementRef;
    
      ngAfterViewInit(): void {
        let element=this.logoGallery.nativeElement;  
        element.style.setProperty('--m',element.scrollWidth+"px");
      }

另一種方法是使用 Angular 動畫。 您唯一需要考慮的是使用@ViewChildren獲取“htmlElement”。 如果我可以使用 *ngFor,我不喜歡寫多個,所以我使用一個數組並使用數組寫一個 li 和另一個。 有些喜歡

有些喜歡

<div #wrapper id="logo-gallery-wrapper">
    <ul #banner id="logo-gallery"  >
    <li #logo>
            <figure class="logo-gallery-figure">
                <img (load)="resize()" src="https://www.ikea.com/de/de/static/ikea-logo.f88b07ceb5a8c356b7a0fdcc9a563d63.svg">
      </figure>
        </li>
        <li *ngFor="let i of items;let first=first">
            <figure class="logo-gallery-figure">
                <img  src="https://www.ikea.com/de/de/static/ikea-logo.f88b07ceb5a8c356b7a0fdcc9a563d63.svg">
      </figure>
        </li>
    </ul>
</div>

看到第一個“圖像”有一個事件“加載”,這個事件讓我計算需要多少元素並啟動 animation。

  logoWidth: number = 0;
  items: number[] = [0];
  public player: AnimationPlayer;

  @ViewChild("wrapper") wrapper: ElementRef;
  @ViewChild("logo") logo: ElementRef;
  @ViewChild("banner") banner: ElementRef;

  constructor(private builder: AnimationBuilder) {}


  resize() {
    this.logoWidth = this.logo.nativeElement.getBoundingClientRect().width;
    this.createAnimation();
  }

  createAnimation() {
    if (this.wrapper && this.logo) {
     //width of the "wrapper"
      const totalWidth = this.wrapper.nativeElement.getBoundingClientRect()
        .width;
      //number of element I go to paint
      const element = 2 * Math.floor(totalWidth / this.logoWidth);

      //I go to translate the "half" of the "ul"
      const inc = this.logoWidth * (element / 2);

      //I recalculate the number of elements if you resize the window
      if (this.items.length != element)
        this.items = new Array(element > 0 ? element : 1);

      // the time spend in the animation is proportional to the "total width"
      const time = 9.2 * totalWidth + "ms";

      //create a manual animation
      const myAnimation: AnimationFactory = this.builder.build([
        style({ transform: `translateX(0px)` }),
        animate(time, style({ transform: `translateX(${-inc}px)` }))
      ]);
      this.player = myAnimation.create(this.banner.nativeElement);

      //when finish repeat process
      this.player.onDone(() => {
        this.createAnimation();
      });

      //finally lauch the animation
      this.player.play();
    }
  }

你可以在這個 stackblitz中看到要小心。 如果您更改代碼,您需要刷新 .html 以在之前步進動畫 - 否則您可能會使導航器崩潰 -

另一個優點是您可以使用 mouseover 和 mouseout 暫停/啟動 animation

<ul (mouseover)="player.pause()" 
    (mouseout)="player.play()" 
   #banner id="logo-gallery"  >
...
</ul>

更新如果我們想要一系列的 imgs 而只有一個會發生什么?

技術是一樣的,我們需要重復一系列圖像以覆蓋總寬度。 想象一下,我們有一個數組“重復”。 我們需要做兩個循環。 我們的圖像數組稱為“徽標”

<div #wrapper id="logo-gallery-wrapper">
    <ul (mouseover)="player.pause()" (mouseout)="player.play()" #banner id="logo-gallery">
        <li #logo>
            <figure class="logo-gallery-figure">
                <img (load)="resize()" [src]="logos[0].url">
            </figure>
        </li>
        <ng-container *ngFor="let i of repeat;let firstRepeat=first">
            <ng-container *ngFor="let logo of logos;let firstLogo=first">
                <li *ngIf="!firstLogo || !firstRepeat">
                    <figure class="logo-gallery-figure">
                        <img  [src]="logo.url">
                    </figure>
                </li>
            </ng-container>
        </ng-container>
    </ul>
</div>

再次考慮我們首先編寫第一個圖像,然后進行兩個循環。 這是必要的,因為這是“加載”事件中的第一個圖像,它使 animation 失效。 並且不可能在循環中添加,因為我們要更改“重復數組”,這將使我們每次調整大小時都會創建一個新的 animation。

好吧,twoo 循環有點復雜,因為我們不需要繪制這個圖像

同樣,我們有一個 function createAnimations

createAnimation() {
    if (this.wrapper && this.logo) {

      //calculate the total width
      const totalWidth = this.wrapper.nativeElement.getBoundingClientRect()
        .width;

      //number of copies necesary
      let copies =
        2 * Math.floor(totalWidth / (this.logos.length * this.logoWidth)) + 1;
      //at least must be 2
      if (copies == 1) copies = 2;

      //create an array with somany elements than "copies"
      this.repeat = ".".repeat(copies).split("");

      //we are going to move lo the left only the width of the "first group of images"
      const inc = this.logoWidth * this.logos.length;

      //rest of code similar, but the speed is proportional to inc
      const time = 9.2 * inc+ "ms";
      const myAnimation: AnimationFactory = this.builder.build([
        style({ transform: `translateX(0px)` }),
        animate(time, style({ transform: `translateX(${-inc}px)` }))
      ]);
      this.player = myAnimation.create(this.banner.nativeElement);
      this.player.onDone(() => {
        this.createAnimation();
      });
      this.player.play();
    }
  }

(*)要檢查一切是否順利,我們可以將 .css 樣式更改為overflow:scroll並評論此行以確保我們計算好“副本”和“公司”

像往常一樣,一個新的堆棧閃電戰

更新和...徽標的寬度不同是怎么回事?

好吧,在這種情況下,我們將更改.html。 我們用徽標制作一個循環,另一個用重復循環

<div #wrapper id="logo-gallery-wrapper">
    <ul (mouseover)="player.pause()" (mouseout)="player.play()" #banner id="logo-gallery">
        <li *ngFor="let logo of logos" #logo>
            <figure class="logo-gallery-figure">
                <img (load)="loaded()" [src]="logo.url">
      </figure>
        </li>
        <ng-container *ngFor="let i of repeat">
                <li *ngFor="let logo of logos">
                    <figure class="logo-gallery-figure">
                        <img  [src]="logo.url">
          </figure>
                </li>
        </ng-container>
    </ul>
</div>

看到在這種情況下,加載了對 function 的(load)事件調用。 這個想法是,在這個 function 中增加一個變量 -picsLoaded- 當所有標志都被加載時,我們計算總寬度。 看到我們需要使用 ViewChildren,而不是 ViewChild

  totalLogoWidth: number = 0;
  picsLoaded=0;
  @ViewChildren("logo") logo: QueryList<ElementRef>;

 loaded()
  {
    this.picsLoaded++;
    if (this.picsLoaded==this.logos.length)
    {
      let totalWidth=0;
      this.logo.forEach(x=>{
        totalWidth+=x.nativeElement.getBoundingClientRect().width;
      })
      this.totalLogoWidth=totalWidth
      this.createAnimation()
    }
  }

現在,剛剛更新了 function createAnimation 以使用 totalLogoWidth 代替 this.logos.length*this.logoWidth

  createAnimation() {
    if (this.wrapper && this.logo) {
      const totalWidth = this.wrapper.nativeElement.getBoundingClientRect()
        .width;
      //in this case "copies" is simply Math.floor +1
      let copies =Math.floor(totalWidth / (this.totalLogoWidth)) + 1;
      this.repeat = ".".repeat(copies).split("");
      const inc = this.totalLogoWidth;
      const time = 9.2 * inc + "ms";
      const myAnimation: AnimationFactory = this.builder.build([
        style({ transform: `translateX(0px)` }),
        animate(time, style({ transform: `translateX(${-inc}px)` }))
      ]);
      this.player = myAnimation.create(this.banner.nativeElement);
      this.player.onDone(() => {
        this.createAnimation();
      });
      this.player.play();
    }
  }

另一個堆棧閃電戰

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM