簡體   English   中英

Firefox 中的 event.offsetX

[英]event.offsetX in Firefox

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script language="javascript">
function main(){
    var canvas = document.getElementById("canvas");
    canvas.addEventListener("mousemove", function(e){
        if (!e) e = window.event;
        var ctx = canvas.getContext("2d");

        var x = e.offsetX;
        var y = e.offsetY;

        ctx.fillRect(x, y, 1, 1);
    });
}
</script>
</head>
<body onload="main();">
<div style="width: 800px; height: 600px; -webkit-transform: scale(0.75,0.75); -moz-transform: scale(0.75,0.75)">
    <canvas id="canvas" width="400px" height="400px" style="background-color: #cccccc;"></canvas>
</div>
</body>
</html>

請考慮上面的快速和骯臟的例子。 請注意,我的畫布包含在應用了縮放變換的 div 中。 上面的代碼在任何基於 webkit 的瀏覽器上都能完美運行。 移動鼠標時,它會在畫布上繪制點。 不幸的是,它不在 Firefox 中,因為它的事件模型不支持 offsetX / Y 屬性。 如何將鼠標坐標從(可能)event.clientX(firefox 也支持)轉換為畫布相對坐標,同時考慮畫布位置、變換等? 謝謝,盧卡。

來自JQuery bug tracker page - 一個很好的 polyfill 是這樣的:

var offX  = (e.offsetX || e.pageX - $(e.target).offset().left);

.. 其中 e 是從 jquery 事件返回的事件。 顯然,只有當你的項目中已經安裝了 Jquery 時,否則你將不得不手動執行offset()操作。

試試 layerX, layerY

var x = (e.offsetX === undefined) ? e.layerX : e.offsetX;
var y = (e.offsetY === undefined) ? e.layerY : e.offsetY;

小提琴

不幸的是,沒有解決方案對我有用。

我在這里找到了一個很好的實現:

var target  = e.target || e.srcElement,
              rect    = target.getBoundingClientRect(),
              offsetX = e.clientX - rect.left,
              offsetY  = e.clientY - rect.top;

e.offsetX   = offsetX;
e.offsetY   = offsetY;

不幸的是,offsetX 和 layerX 並不完全相同,因為 offsetX 是當前元素內的偏移量,而 layerX 是頁面的偏移量。 以下是我目前正在使用的修復程序:

function fixEvent(e) {
    if (! e.hasOwnProperty('offsetX')) {
        var curleft = curtop = 0;
        if (e.offsetParent) {
           var obj=e;
           do {
              curleft += obj.offsetLeft;
              curtop += obj.offsetTop;
           } while (obj = obj.offsetParent);
        }
        e.offsetX=e.layerX-curleft;
        e.offsetY=e.layerY-curtop;
    }
    return e;
}

Musa 的解決方案中有一個錯誤:想想如果e.offsetX === 0e.layerX === undefined會發生什么......

var x = e.offsetX || e.layerX; // x is now undefined!

更健壯的版本如下:

var x = e.hasOwnProperty('offsetX') ? e.offsetX : e.layerX;
var y = e.hasOwnProperty('offsetY') ? e.offsetY : e.layerY;

或者,因為我們可以假設如果定義了offsetX ,那么offsetY也將是:

var hasOffset = e.hasOwnProperty('offsetX'),
    x         = hasOffset ? e.offsetX : e.layerX,
    y         = hasOffset ? e.offsetY : e.layerY;

offset實際上並沒有直接轉化為layer offset屬性不考慮元素的邊距。 下面的代碼應該說明這一點。

function(e) {
    var x = e.offsetX, y = e.offsetY;
    if(e.hasOwnProperty('layerX')) {
      x = e.layerX - e.currentTarget.offsetLeft;
      y = e.layerY - e.currentTarget.offsetTop;
    }
}

由於各種原因,沒有一個非 jquery 版本可以完全工作。 在你的幫助下,我得到了這個工作:

if(!event.hasOwnProperty('offsetX')) {
    event.offsetX = event.layerX - event.currentTarget.offsetLeft;
    event.offsetY = event.layerY - event.currentTarget.offsetTop;
}

我發現這里發布的所有答案除了EnotionZ 和 laz brannigan 的最后兩個答案(之前每個答案都為零)在 div 中包含多個元素的情況下都是錯誤的。 在我的例子中,我在一個 div 中有幾個畫布元素,我正在分別收聽每個畫布。

經過大量的試驗和錯誤后,我得出了最終的正確答案,它在 FireFox 和 Chrome 中對我來說完美且相同,如下所示:

//inside my mouse events handler:
var anOffsetX = (inEvent.offsetX !== undefined) ? inEvent.offsetX : (inEvent.layerX - inEvent.target.offsetLeft);
var anOffsetY = (inEvent.offsetY !== undefined) ? inEvent.offsetY : (inEvent.layerY - inEvent.target.offsetTop);

據推測,這也適用於邊距,例如 EnotionZ 在他的帖子中指出的那樣,但我還沒有嘗試過。

但是,如果沒有layerXlayerY字段,你會怎么做?

 var xe=e.offsetX,ye=e.offsetY;
  if(!xe){
     xe=e.clientX - $(e.target).offset().left;
  }
  if(!ye){
    ye= e.clientY - $(e.target).offset().top;
  }

這個問題需要更新的答案。


首先,正如我在評論中提到的,關於所有使用layerXlayerY的舊答案:

“此功能是非標准的,不在標准軌道上。不要在面向 Web 的生產站點上使用它:它不會對每個用戶都有效。實現之間也可能存在很大的不兼容性,並且行為可能會在未來發生變化”

(來源: developer.mozilla.org/en-US/docs/Web/API/UIEvent/layerX


其次,我發現當你在 Firefox 中使用console.log(event)時, offsetXoffsetY顯示 0,但是當你使用console.log(event.offsetX)時,它不是 0。所以要小心,因為你可能被騙了到。

此行為在此處解釋:

記錄對象

不要使用console.log(obj) ,使用console.log(JSON.parse(JSON.stringify(obj)))

這樣您就可以確定在記錄時看到了 obj 的值。 否則,許多瀏覽器會提供實時視圖,隨着值的變化不斷更新 這可能不是你想要的。

(另請注意, JSON.stringify()不會在這里執行您想要的操作...它不會對整個事件對象進行字符串化。)

OffsetX/Y 行為在 FireFox、Chrome/Edge 中不同。 您可能需要通過添加代碼片段來計算該值:

const offsetX = evt.clientX - this.myRef.current.getBoundingClientRect().left;
const offsetY = evt.clientY - this.myRef.current.getBoundingClientRect().top;

myRef是其最近的父元素的引用。 因此偏移量將是此元素 (clientX) 減去其父元素之間的距離。

如果有些人仍然需要解決方案,那么這個解決方案在 Firefox 中可以完美運行:

var x = e.offsetX || e.originalEvent.layerX;
var y = e.offsetY || e.originalEvent.layerY;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM