Javascript 如何使我的组件的多个实例不共享@ViewChild映射/区域

Javascript 如何使我的组件的多个实例不共享@ViewChild映射/区域,javascript,html,angular,Javascript,Html,Angular,我有一个组件,上面有一个画布,完全由一个映射图像覆盖。基于图像顶部的鼠标移动,我高亮显示或取消高亮显示画布的一部分。我本来打算让这样的多个组件,每个组件彼此独立,在我的页面上一个接一个地垂直重复(因此,“上”画布是靠近页面顶部的画布,而“下”画布是在它之后的画布) 问题是,底部图像映射上的事件只影响第一个画布(即,如果我将鼠标移到第二个画布上的正确区域上,那么第一个画布就是被绘制的画布)。我希望每个组件都是独立的——如果我在第二个组件上做了一些事情,它应该会影响第二个画布,而不是第一个画布 换句

我有一个组件,上面有一个画布,完全由一个映射图像覆盖。基于图像顶部的鼠标移动,我高亮显示或取消高亮显示画布的一部分。我本来打算让这样的多个组件,每个组件彼此独立,在我的页面上一个接一个地垂直重复(因此,“上”画布是靠近页面顶部的画布,而“下”画布是在它之后的画布)

问题是,底部图像映射上的事件只影响第一个画布(即,如果我将鼠标移到第二个画布上的正确区域上,那么第一个画布就是被绘制的画布)。我希望每个组件都是独立的——如果我在第二个组件上做了一些事情,它应该会影响第二个画布,而不是第一个画布

换句话说,两个组件共享第一个组件的画布,而不是各自使用自己的画布。这是一个问题

这是一个MCVE:

dummy-component.html:

<div style="position: relative; display: inline-block; width: 520px; height: 160px; background-color: green">
    <canvas #myCanvas width="520" height="160" 
      style="position: absolute; left: 0; top: 0; background-color: green; user-select: none"></canvas>
    <img #mapOverlay width="520" height="160" 
      style="position: absolute; left: 0; top: 0; background-color: transparent; user-select: none" 
      usemap="#overlay">
  
    <map #overlay id="overlay" name="overlay">
      <area shape="rect" coords="0, 0, 259, 159" 
        (mouseover)="hover()" (mouseout)="unhover()" (click)="drawSmiley()">
    </map>
</div>

@Component({
  selector: 'app-dummy',
  templateUrl: './dummy.component.html',
})
export class DummyComponent implements AfterViewInit {
  @ViewChild('myCanvas') private myCanvasElement!: ElementRef<HTMLCanvasElement>
  private myCanvas!: CanvasRenderingContext2D;
  private smileyFace: HTMLImageElement = new Image();

  constructor() { this.smileyFace.src = "assets/smiley.png"; }

  ngAfterViewInit(): void {
    this.myCanvas = <CanvasRenderingContext2D> this.myCanvasElement.nativeElement.getContext('2d');
  }

  hover() {
    this.myCanvas.clearRect(0, 0, 520, 160);
    this.myCanvas.fillStyle = "#ffffff33";  // draw transparent highlight
    this.myCanvas.fillRect(0, 0, 260, 160);
  }
  unhover() { this.myCanvas.clearRect(0, 0, 520, 160); }
  drawSmiley() { this.myCanvas.drawImage(this.smileyFace, 15, 15); }
}



表示“变更检测器在视图DOM中查找与选择器匹配的第一个元素或指令”,这可能是相关的(我怀疑第二个元素借用了第一个元素的@ViewChild,并且自己使用它),但我不知道如何应用这些信息,并使其粘在自己的画布上。

问题似乎在于地图,它们都有相同的名称。当图像绑定到一个映射时,它会选择整个DOM中具有相同名称的第一个映射,这恰好是第一个组件的映射-由于函数和其他东西都没有绑定到第一个组件,因此看起来好像所有事情都发生在第一个组件上

我觉得这是一个bug,像这样的事情应该只局限于被激活的组件内部,但它可能是基于整个模板的呈现方式的预期行为

无论如何,解决方案:向
DummyComponent
添加一个
public id
属性,并将其注入到地图的名称和图像的
useMap
属性中:

HTML:

<div>
    <app-dummy></app-dummy>
    <app-dummy></app-dummy>
</div>
<img #mapOverlay width="520" height="160" 
  style="position: absolute; left: 0; top: 0; background-color: transparent; user-select: none" 
  useMap="#{{name}}">

<map #overlay id="overlay" name="{{name}}">
  <area shape="rect" coords="0, 0, 259, 159" 
    (mouseover)="this.hover()" (mouseout)="this.unhover()" (click)="this.drawSmiley()">
</map>
let idGenerator = 0;

@Component({
  selector: 'app-dummy',
  templateUrl: './dummy.component.html',
})
export class DummyComponent implements AfterViewInit {
  public name: string;

  ...

  constructor() {
    this.smileyFace.src = "assets/smiley.png";
    this.name = "DummyComponent" + ++idGenerator;
  }
  ...
}