Javascript 并非所有组件中都出现Stencil js-requestAnimationFrame

Javascript 并非所有组件中都出现Stencil js-requestAnimationFrame,javascript,canvas,components,requestanimationframe,stenciljs,Javascript,Canvas,Components,Requestanimationframe,Stenciljs,我使用stencil.js创建了一个简单的目录项组件。在组件中有一个画布标签,我在上面画了动画曲线。 在componentDidLoad函数中,我定义画布,初始化它并调用animate函数。这是组件本身的代码: import { Component, Host, h, Prop, Element } from "@stencil/core"; import { Item } from "../hotb-catalog-container/data"; i

我使用stencil.js创建了一个简单的目录项组件。在组件中有一个画布标签,我在上面画了动画曲线。 在componentDidLoad函数中,我定义画布,初始化它并调用animate函数。这是组件本身的代码:

import { Component, Host, h, Prop, Element  } from "@stencil/core";
import { Item } from "../hotb-catalog-container/data";
import { initCanvas, init, animate } from "./wave.js";
import axios from "axios";

@Component({
  tag: "hotb-catalog-item",
  styleUrl: "hotb-catalog-item.scss",
  shadow: false,
})
export class HotbCatalogItem {
  @Prop() item: Item;
  @Element() el: HTMLElement;

  // @Event({ bubbles: true, composed: true }) itemSelect: EventEmitter<Item>;

  itemSelected(event: Event) {
    event.preventDefault();
    //sessionStorage.setItem("item", JSON.stringify(this.item));
    axios.post("/item", { item: this.item }).then(() => {
      window.location.href = "http://localhost:3000/item";
    });
  }

  componentDidLoad() {
    let canvas = this.el.querySelector('canvas');
    initCanvas(canvas);
    init();
    animate();
  }

  render() {
    return (
      <Host>
        <div class="heading">
          <h1>{this.item.name}</h1>
          <span> מ{this.item.origin} &#183; {this.item.taste}</span>
        </div>
        <div class="center-part">
          <div class="center-part__img"></div>
          <div class="center-part__icon center-part__icon--temp">
            {this.item.temp}&deg;C
          </div>
          <div class="center-part__icon center-part__icon--time">
            {this.item.time}
          </div>
        </div>
        <a
          href="/item"
          onClick={this.itemSelected.bind(this)}
          class="primary-btn homepage__tea"
        >
          לצפיה
        </a>
        <canvas></canvas>
      </Host>
    );
  }
}
从“@stencil/core”导入{Component,Host,h,Prop,Element}”;
从“./hotb目录容器/数据”导入{Item};
从“/wave.js”导入{initCanvas,init,animate};
从“axios”导入axios;
@组成部分({
标签:“hotb目录项”,
styleUrl:“hotb目录项.scss”,
影子:错,
})
导出类HotbCatalogItem{
@Prop()项目:项目;
@Element()el:HTMLElement;
//@Event({bubbles:true,composited:true})itemSelect:EventEmitter;
已选择项(事件:事件){
event.preventDefault();
//setItem(“item”,JSON.stringify(this.item));
post(“/item”,{item:this.item})。然后(()=>{
window.location.href=”http://localhost:3000/item";
});
}
componentDidLoad(){
让canvas=this.el.querySelector('canvas');
初始画布(画布);
init();
制作动画();
}
render(){
返回(
{this.item.name}
{this.item.origin}&{this.item.taste}
{this.item.temp}°;C
{this.item.time}
);
}
}
如您所见,我导入了画布代码,如下所示:

let line1;
let line2;
var ctx;
var canvasElem;

function initCanvas(canvas) {
  canvasElem = canvas;
  ctx = canvas.getContext("2d");
  const parent = canvas.parentElement;
  canvas.width = parent.clientWidth;
  canvas.height = parent.scrollHeight;
}

class LineGen {
  constructor(x, y, directionY, cpX, directionCPX, cpY, directionCPY, size, color) {
    this.x = x;
    this.y = y;
    this.directionY = directionY;
    this.cpX = cpX;
    this.directionCPX = directionCPX;
    this.cpY = cpY;
    this.directionCPY = directionCPY;
    this.size = size;
    this.color = color;
  }

  draw() {
    ctx.beginPath();
    ctx.moveTo(this.x, this.y);
    ctx.quadraticCurveTo(this.cpX, this.cpY, 400, this.y);
    ctx.strokeStyle = this.color;
    ctx.lineWidth = this.size;
    ctx.stroke();
  }

  update() {
    if (this.y > 490 || this.y < 400) {
      this.directionY = -this.directionY;
    }

    if (this.color === '#E07D31') {
      if (this.cpX > 390 || this.cpX < 10) {
        this.directionCPX = -this.directionCPX;
      }
      if (this.cpY > 590 || this.cpY < 150) {
        this.directionCPY = -this.directionCPY;
      }
    } else if (this.color === '#49E048') {
      if (this.cpX > 390 || this.cpX < 10) {
        this.directionCPX = -this.directionCPX;
      }
      if (this.cpY > 560 || this.cpY < 240) {
        this.directionCPY = -this.directionCPY;
      }
    }

    //this.y += this.directionY;
    this.cpX += this.directionCPX;
    this.cpY += this.directionCPY;
    this.draw();
  }
}

class Line extends LineGen {
  constructor(x, y, directionY, cpX, directionCPX, cpY, directionCPY, size, color) {
    super(x, y, directionY, cpX, directionCPX, cpY, directionCPY, size, color);
  }
}

function init() {
  let x = 0;
  let y = 400;
  let y2 = 380;

  let directionY = -.2;
  let cpX = 100;
  let cpX2 = 100;
  let directionCPX = .15;

  let cpY = 300;
  let cpY2 = 300;
  let directionCPY = .15;
  let directionCPY2 = .178125;

  let size = 2;

  let color = '#E07D31';
  let color2 = '#49E048';

  line1 = new Line(x, y, directionY, cpX, directionCPX, cpY, directionCPY2, size, color);
  line2 = new Line(x, y2, directionY, cpX, directionCPX, cpY, directionCPY, size, color2);
}

function animate() {
  requestAnimationFrame(animate);
  ctx.clearRect(0, 0, canvasElem.width, canvasElem.height);

  line1.update();
  line2.update();
}

export { initCanvas, init, animate };

let line1;
让线2;
var-ctx;
var canvasElem;
函数初始化画布(画布){
画布=画布;
ctx=canvas.getContext(“2d”);
const parent=canvas.parentElement;
canvas.width=parent.clientWidth;
canvas.height=parent.scrollHeight;
}
类LineGen{
构造函数(x,y,directionY,cpX,directionCPX,cpY,directionCPY,size,color){
这个.x=x;
这个。y=y;
this.directionY=directionY;
这个.cpX=cpX;
this.directionCPX=directionCPX;
this.cpY=cpY;
this.directionCPY=directionCPY;
这个。大小=大小;
这个颜色=颜色;
}
画(){
ctx.beginPath();
ctx.moveTo(this.x,this.y);
ctx.quadraticCurveTo(this.cpX,this.cpY,400,this.y);
ctx.strokeStyle=this.color;
ctx.lineWidth=这个.size;
ctx.stroke();
}
更新(){
如果(this.y>490 | | this.y<400){
this.directionY=-this.directionY;
}
如果(this.color=='#E07D31'){
如果(this.cpX>390 | | this.cpX<10){
this.directionCPX=-this.directionCPX;
}
如果(this.cpY>590 | | this.cpY<150){
this.directionCPY=-this.directionCPY;
}
}else if(this.color=='#49E048'){
如果(this.cpX>390 | | this.cpX<10){
this.directionCPX=-this.directionCPX;
}
如果(this.cpY>560 | | this.cpY<240){
this.directionCPY=-this.directionCPY;
}
}
//this.y+=this.directionY;
this.cpX+=this.directionCPX;
this.cpY+=this.directionCPY;
这个.draw();
}
}
类行扩展LineGen{
构造函数(x,y,directionY,cpX,directionCPX,cpY,directionCPY,size,color){
super(x,y,directionY,cpX,directionCPX,cpY,directionCPY,size,color);
}
}
函数init(){
设x=0;
设y=400;
设y2=380;
设方向y=-.2;
设cpX=100;
设cpX2=100;
设方向Cpx=0.15;
设cpY=300;
设cpY2=300;
设方向cpy=0.15;
设方向cpy2=0.178125;
设尺寸=2;
设颜色='#E07D31';
设color2='#49E048';
line1=新行(x,y,方向y,cpX,方向cpX,cpY,方向CPY2,大小,颜色);
line2=新行(x,y2,方向Y,cpX,方向cpX,cpY,方向cpY,大小,颜色2);
}
函数animate(){
请求动画帧(动画);
ctx.clearRect(0,0,画布宽度,画布高度);
line1.update();
line2.update();
}
导出{initCanvas,init,animate};
现在,目录项组件位于容器组件内部,如下所示:

    let items;
    if (this.newItemsArr.length == 0) {
      items = <div class="no-items">אין משקאות שתואמים לחיפוש שלך</div>;
    } else {
      items = this.newItemsArr.map((item) => (
        <hotb-catalog-item item={item}></hotb-catalog-item>
      ));
    }
    return (
      <Host>
        {items}
      </Host>
    );
let项目;
if(this.newItemsArr.length==0){
项目=项目;
}否则{
items=this.newItemsArr.map((项)=>(
));
}
返回(
{items}
);
最终结果是组件显示画布和线条,但动画仅在其中一个画布和线条中出现。其余的在初始状态下是静态的。请告诉我为什么会发生这种情况,以及我能做些什么来修复它,以便所有的组件都将动画化。需要注意的是,当我刷新代码并且浏览器通过热重新加载进行刷新时,另一个组件会在每次刷新时启动动画等等


谢谢您的帮助。

问题在于一些变量是在
initCanvas
函数之外定义的,因此在所有组件之间共享(
line1
line2
ctx
canvasElem
)。因此,每次调用
initCanvas
时,它们都会被覆盖

一个快速的解决方案是将其包装在一个类中:

export class WaveCanvas {
  constructor(canvas) {
    this.canvasElem = canvas;
    this.ctx = canvas.getContext("2d");
    const parent = canvas.parentElement;
    canvas.width = parent.clientWidth;
    canvas.height = parent.scrollHeight;
  }

  init() {
    // ...
    this.line1 = new Line(...);
  }

  animate() {
    requestAnimationFrame(() => this.animate());
    this.ctx.clearRect(0, 0, this.canvasElem.width, this.canvasElem.height);

    this.line1.update();
    this.line2.update();
  }
}
然后在组件中实例化它:

  componentDidLoad() {
    let canvas = this.el.querySelector('canvas');
    const waveCanvas = new WaveCanvas(canvas);
    waveCanvas.init();
    waveCanvas.animate();
  }

通过这种方式,
WaveCanvas
的每个实例都将保存对正确的
元素的引用。

非常感谢!!!我想补充一下你惊人的答案。我在重新讲述如何在WaveCanvas和Line这两个类中共享ctx变量时遇到了困难。我通过将WaveCanvas中的ctx变量通过构造函数传递给该行来解决这个问题<代码>this.line1=新行(this.ctx,x,y,directionY,cpX,directionCPX,cpY,directionCPY2,大小,颜色)在此之前,Line类是在没有ctx变量的情况下实例化的。很乐意提供帮助。我可能自己也应该提到这一点,但我会这么做的。IMO类永远不应该访问外部变量。我只是给了你一个快速修复,因为我没有