【问题标题】:Can't trigger mouse events on an SVG in Angular 7无法在 Angular 7 中触发 SVG 上的鼠标事件
【发布时间】:2019-06-14 10:53:48
【问题描述】:

我正在开发一个以交互式地图为中心的 Angular 应用程序,该地图已作为 SVG 图像提供。地图的某些区域会有热点,我可以点击这些热点来触发某些事件,例如当我点击位置标记时放大某个部分。

但是,没有鼠标事件起作用。我可以在 TypeScript 中更改 SVG 的属性(例如,更改 SVG 视图框以进行平移和缩放,或在事件发生时以红色突出显示标签),但我无法触发 SVG 本身内的任何单击、滚动、悬停等事件.

到目前为止我已经尝试过:

  • 向 SVG 添加角度事件属性,这显然不是有效的 XML,因此浏览器无法解析它以进行渲染,并且;
  • 通过它的 ID 查找元素(我可以),然后将匿名 onclick 函数附加到它 - 但它永远不会被触发

SVG 通过object 标签包含在内。

<!--map.component.html-->
<object id="svg-object" #svgObject type="image/svg+xml" data="../../../assets/img/map_large.svg"></object>

在 SVG 加载后的组件中,我执行以下操作,但没有任何反应。它甚至没有进入函数。

// map.component.ts
this.svgDocument = this.svgObject.nativeElement.contentDocument.documentElement;
let el = this.svgDocument.getElementById("zoomToThis");
// this never gets triggered
el.addEventListener("click", function(event)
    {
        event.currentTarget.style.opacity = "1";
    }
);

但是,这很好用。所以很明显,访问文档元素不是问题。

// map.component.ts
this.svgDocument = this.svgObject.nativeElement.contentDocument.documentElement;
let el = this.svgDocument.getElementById("zoomToThis");
el.style.opacity = "1";

我该如何解决这个问题?我正在玩弄把它全部撕掉并在 iFrame 中使用 vanilla JavaScript 的想法,但我被告知领导拒绝这样做。鉴于地图的庞大规模,我们也拒绝将其内联。

【问题讨论】:

标签: javascript angular typescript svg


【解决方案1】:

即使在办公时间之外,我也为此绞尽脑汁,我发现了一些可行的方法。感觉很脏,但很管用。

首先,我得到的是对象标签的内容窗口,而不是内容文档

// map.component.ts
let cw = this.svgObject.nativeElement.contentWindow;

内容窗口的行为方式与 iFrame 类似。为了让点击事件在 SVG 中起作用,我可以在内容窗口中注入一个函数。

// map.component.ts
cw.nameOfMyFunction = (event) => { /* do something */ }

然后,在 SVG 本身内部,我可以向元素添加点击处理程序(通过直接编辑 XML 或在 Inkskape 等软件中编辑)。

<!--map_large.svg-->
<rect onclick="nameOfMyFunction(event)" />

我单击矩形,函数按预期触发。

【讨论】:

    【解决方案2】:

    您可以使用带有检查点击事件是否在 SVG 元素上的函数的 HostListener:

    // map.component.ts
    @ViewChild('svgObject')    svgEl:    ElementRef;
    @HostListener('click', ['$event.target'])
    clickEvent(target: any) {
        if (target === svgEl.nativeElement) {
            svgEl.nativeElement.style.opacity = '1';
        }
    }
    

    编辑:另一种方法是给元素添加一个onClick事件:

    <!--map.component.html-->
    <object id="svg-object" #svgObject (click)=changeOpacity() type="image/svg+xml"data="../../../assets/img/map_large.svg"></object>
    
    // map.component.ts
    changeOpacity() {
        this.svgDocument = this.svgObject.nativeElement.contentDocument.documentElement;
        let el = this.svgDocument.getElementById("zoomToThis");
        el.style.opacity = "1";
    }
    

    【讨论】:

    • 不幸的是,这不是我想要的。如前所述,我需要点击 SVG 中的热点,而不是整个 SVG 本身。
    【解决方案3】:

    可以使用render方法来捕捉事件

    this.renderer.listen(document.querySelector('svg'),'click',(evt)=&gt;{console.log(evt)});

    导入 renderer2 并在您的组件构造函数中启动它

    private renderer: Renderer2

    【讨论】:

    • 这个问题是两年前回答的。我也不是点击整个 SVG 本身,而是点击 SVG 中的热点。这已通过将函数注入 SVG 的内容窗口来解决。
    猜你喜欢
    • 1970-01-01
    • 2014-08-13
    • 2020-03-26
    • 1970-01-01
    • 1970-01-01
    • 2015-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多