4

我观察到在处理各种浏览器(Chrome、Edge、Firefox)之间的点击事件时存在不一致/错误。

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

要检查这一点,您需要在画布上创建至少 2 个矩形。您可以用鼠标拖动它们(矩形初始位置相同)。如果在元素上触发单击事件,通常矩形的边框会变为棕色。

奇怪的是,Firefox 会按预期触发点击事件,但 Chrome 根本不会触发该事件。MS Edge 浏览器在双击时触发click事件。

PS:这里的代码是完整的,所以你可以运行这个例子:

"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>

4

1 回答 1

4

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

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

  1. Chrome 问题线程

  2. W3C 问题讨论线程

于 2017-10-07T10:04:53.887 回答