Chrome不会触发SVG元素的click事件(Firefox会触发) [英] Chrome doesn't fire click event for SVG element (Firefox does)

查看:150
本文介绍了Chrome不会触发SVG元素的click事件(Firefox会触发)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发现在各种浏览器(Chrome,Edge,Firefox)中处理 click 事件时存在不一致/错误.

I observe inconsistency/bug in handling click event among various browsers (Chrome, Edge, Firefox).

在使用SVG的JavaScript库中,创建可单击和可拖动的矩形.当我在Chrome浏览器中运行代码段时,如果画布上存在2个或更多元素,则不会触发 click 事件.

In my JavaScript library that uses SVG I create clickable and draggable rectangles. When I run my snippet in Chrome browser the click event is not firing if 2 or more elements are present on canvas.

要对此进行检查,您需要在画布上至少创建2个矩形.您可以用鼠标拖动它们(矩形的初始位置是相同的).通常,如果在元素上触发了 click 事件,则矩形的边框会变成棕色.

To check this you need to create at least 2 rectangles on canvas. You can drag them with mouse (Rectangles initial position is the same). Normally rectangle's border become brown if click event was fired on element.

奇怪的是,Firefox按预期触发了 click 事件,但Chrome根本没有触发该事件. MS Edge浏览器在双击上触发 click 事件.

The strange things is that Firefox fires click event as expected but Chrome doesn't fire the event at all. MS Edge browser fires click event on double-click.

P.S:此代码以完整容量显示,因此您可以运行示例:

P.S: The code is presented here in full capacity so you can run the example:

"use strict";
var SVGCanvas = undefined;
var canvClientRect = {};

function initScript() {
    SVGCanvas = document.getElementById("playSVGCanvas");
    canvClientRect.width = SVGCanvas.getClientRects()[0].width;
    canvClientRect.height = SVGCanvas.getClientRects()[0].height;
}

function createRect() {
    var newRect = document.createElementNS("http://www.w3.org/2000/svg", "rect");

    var rectX0 = 20;
    var rectY0 = 20;
    var rectWidth = 100;
    var rectHeight = 50;

    newRect.setAttributeNS(null, "x", rectX0);
    newRect.setAttributeNS(null, "y", rectY0);
    newRect.setAttributeNS(null, "width", rectWidth);
    newRect.setAttributeNS(null, "height", rectHeight);
    newRect.setAttributeNS(null, "class", "draggable rect inactive");
    newRect.setAttributeNS(null, "onmousedown", "selectElement(evt)");
    newRect.setAttributeNS(null, "onclick", "clickHandler(evt)");
    SVGCanvas.appendChild(newRect);
}

var currentX = 0;
var currentY = 0;
var shapeWidth = undefined;
var shapeHeight = undefined;

var wasMoved = false;


function selectElement(evt) {
    evt.preventDefault();
    var targetEl = evt.target;
    currentX = evt.clientX;
    currentY = evt.clientY;
    shapeWidth = targetEl.getAttributeNS(null, "width");
    shapeHeight = targetEl.getAttributeNS(null, "height");

    if (SVGCanvas.childElementCount >= 2) {
        // change element's order to show selected item on the top
        SVGCanvas.appendChild(targetEl);
    }

    targetEl.setAttributeNS(null, "onmousemove", "moveElement(evt)");
    targetEl.setAttributeNS(null, "onmouseout", "deselectElement(evt)");
    targetEl.setAttributeNS(null, "onmouseup", "deselectElement(evt)");

    wasMoved = false;
}

function moveElement(evt) {
    evt.preventDefault();
    var targetEl = evt.target;

    var dx = evt.clientX - currentX;
    var dy = evt.clientY - currentY;
    currentX = evt.clientX;
    currentY = evt.clientY;
    var newX = parseInt(targetEl.getAttributeNS(null, "x")) + dx;
    var newY = parseInt(targetEl.getAttributeNS(null, "y")) + dy;

    if(newX < 0) {
        targetEl.setAttributeNS(null, "x", 0);
    } else if (newX > canvClientRect.width - shapeWidth) {
        targetEl.setAttributeNS(null, "x", canvClientRect.width - shapeWidth);
    } else {
        targetEl.setAttributeNS(null, "x", newX);
    }

    if (newY < 0) {
        targetEl.setAttributeNS(null, "y", 0);
    } else if (newY > canvClientRect.height - shapeHeight) {
        targetEl.setAttributeNS(null, "y", canvClientRect.height - shapeHeight);
    } else {
        targetEl.setAttributeNS(null, "y", newY);
    }

    wasMoved = true;
}

function deselectElement(evt) {
    if (evt == null) {
        console.log("Event == null");
        return;
    }
    evt.target.removeAttributeNS(null, "onmousemove");
    evt.target.removeAttributeNS(null, "onmouseout");
    evt.target.removeAttributeNS(null, "onmouseup");
}

function clickHandler(evt) {
    // click event fires even element was moved
    // we don't handle click if element was moved
    if (wasMoved) { return; }

    var targetEl = evt.target;
    if (targetEl.classList.contains("active")) {
        deActivateElm(targetEl);
    } else {
        activateElm(targetEl);
    }
}

function activateElm(elm) {
    elm.classList.remove("inactive");
    elm.classList.add("active");
}

function deActivateElm(elm) {
    elm.classList.remove("active");
    elm.classList.add("inactive");
}

#workCanv {
    width: 100%;
    height: 180px;
    border: 1px solid black;
}

.draggable {
    cursor: move;
}

.rect {
    stroke-width: 4;
    fill: lightgrey;
}

.active {
    stroke: brown
}

.inactive {
    stroke: black
}

<!DOCTYPE html>
<head>
    <meta charset="utf-8">
    <link rel="stylesheet" type="text/css" href="wcstyle.css">
    <script src="wccontroller.js"></script>
</head>

<body onload="initScript()">

<div id="panel">
    <button type="button" name="addRectagble" onclick="createRect()">Add rectangle</button>
</div>

<div id="workCanv">
    <svg xmlns="http://www.w3.org/2000/svg" height="100%" width="100%" id="playSVGCanvas">
    </svg>
</div>
</body>

推荐答案

一段时间后,我向Chrome开发团队报告了此问题,因为我认为这是一个错误.但事实并非如此. W3委员会尚未定义将元素从文档树中删除然后再添加回鼠标之前的情况(例如appendChild(lastChild)).结果,行为因浏览器而异.

After some time I reported this question to Chrome dev team because I thought it is a bug. But it's not. The behavior for cases when an element is removed from the document tree and then added back before mouseup (e.g. appendChild(lastChild)) is not defined yet by W3 committee. As result behavior varies from browser to browser.

可以通过以下链接跟踪问题的进展情况:

Progress for the problem can be tracked with following links:

  1. W3C问题讨论线程

    这篇关于Chrome不会触发SVG元素的click事件(Firefox会触发)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆