![](/img/trans.png)
[英]How can I use a JavaScript function in a Angular TypeScript component?
[英]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.