gpt4 book ai didi

javascript - addEventListener 和 `this` 未按预期工作

转载 作者:搜寻专家 更新时间:2023-11-01 05:04:28 25 4
gpt4 key购买 nike

我是一名经验丰富的程序员,但对网络编程有些陌生。我正在尝试通过编写一个使用 Javascript 玩井字游戏的 HTML 页面来使用 VS2010 学习 Javascript、HTML5 和 SVG。

我成功地将九个正方形中的每一个创建为 SVG <rect...>元素,但是我在处理每个方 block 的点击事件处理程序时遇到了问题。

这是存在于 HTML 文件中的基本 SVG 元素:

  <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"
id="svgTTT" width="150" height="150" viewBox="0 0 300 300" >
<rect width="3" height="300" x="99" fill="#008d46" />
<rect width="3" height="300" x="199" fill="#000000" />
<rect width="300" height="3" y="99" fill="#008d46" />
<rect width="300" height="3" y="199" fill="#d2232c" />
</svg>

这些静态 <rect>元素绘制井字棋盘的交叉哈希线。九个棋盘方 block 是在从 Windows 加载事件(如下)调用的 javascript 函数中创建的。

这是 javascript(内嵌在 HTML 正文中的 <script> 元素中):

<script type="text/javascript">
function getEl(s) { return document.getElementById(s); }

var svg; // get the TTT svg

// execute after HTML has rendered
window.onload = function () {
svg = getEl("svgTTT");
tttSetupSquares(svg);
alert("click-squares are setup.");
}

var cells = new Array(3);
// setup the click squares
function tttSetupSquares(brd) {
for (var i = 0; i < 3; i++) {
cells[i] = new Array(3);
for (var j = 0; j < 3; j++) {
var x = 3 + (i * 100);
var y = 3 + (j * 100);
var newId = "svgTTTsqr" + i.toString() + j.toString();
// add in new rect with html
brd.innerHTML += "<rect id='"+newId+"' width='93' height='93' "
+ "fill='#00DD00' x='" + x.toString() + "' y ='" + y.toString() + "'"
+ " />";
//find it using the newId
var rect = document.getElementById(newId);
//make a cell object to contain all of this
var cell = {
col: i,
row: j,
pSvg: svg,
rect: rect,

handleClick: function (event) {
try {
// this line fails because `this` is the target, not the cell
var svgNS = this.pSvg.namespaceURI;

var line = document.createElementNS(svgNS, 'line');
this.pSvg.appendChild(line);
}
catch (err) {
alert("handlClick err: " + err);
}
}
}

//add a click handler for the rect/cell
cell.rect.addEventListener("click", cell.handleClick, false);
//(only seems to work the last time it is executed)

//save the cell object for later use
cells[i][j] = cell;
}
}
}
</script>

(我可以提供完整的页面源代码,但它只是包含这些的 HTML 元素。)

问题有两个:

  1. 只有最后一个addEventListener似乎工作。单击所有其他方 block 没有任何作用。单击最后一个方 block (svgTTTsqr22) 会运行 cell.handleClick但会导致问题 2(如下)。 Chrome 开发者工具 (F12) 显示所有 <rect>除了最后一个元素没有事件监听器。

  2. cell.handleClick确实运行,它在第一行 (var svgNS = this.pSvg.namespaceURI;) 上失败,并出现类似“ undefined object 没有名为“namespaceURI”的错误。在 Devleoper 工具中检查显示它失败了,因为 this未设置为 cell 对象,而是设置为被单击的 SVG <rect> 元素。

所以我的问题是:

一个。我在这里做错了什么,

B.我怎么能/应该这样做?

最佳答案

<强>1。缺少事件处理程序

使用 innerHTML更改元素的内部结构将导致其所有子元素被删除,并通过重新解析 HTML 内容来重建元素的 DOM 子树。通过删除子元素,所有以前注册的事件监听器都将丢失,并且在从 HTML 重建 DOM 时不会自动恢复。要规避此行为,最好避免 innerHTML ,如果可能,并改用直接 DOM 操作。你可以使用这样的东西来插入你的 <rect>小号:

// Use DOM manipulation instead of innerHTML
var rect = document.createElementNS(svg.namespaceURI, 'rect');
rect.setAttributeNS(null, "id", newId);
rect.setAttributeNS(null, "fill", "#00DD00");
rect.setAttributeNS(null, "width", "93");
rect.setAttributeNS(null, "height", "93");
rect.setAttributeNS(null, "x", x);
rect.setAttributeNS(null, "y", y);
svg.appendChild(rect);

<强>2。 this事件处理程序中的上下文

每当事件监听器被调用时 this将绑定(bind)到触发事件的元素。但是,在您的代码中,您不需要 this因为所有信息都可以通过参数 brd 获得它被传递给函数 .tttSetupSquares() .

handleClick: function (event) {
try {
var svgNS = brd.namespaceURI;
var line = document.createElementNS(svgNS, 'line');
brd.appendChild(line);
}
catch (err) {
alert("handlClick err: " + err);
}
}

有关工作示例,请参阅以下代码段:

function getEl(s) { return document.getElementById(s); }

var svg; // get the TTT svg
var cells = new Array(3);

// execute after HTML has rendered
!(function () {
svg = getEl("svgTTT");
tttSetupSquares(svg);
alert("click-squares are setup.");
}());

// setup the click squares
function tttSetupSquares(brd) {
for (var i = 0; i < 3; i++) {
cells[i] = new Array(3);
for (var j = 0; j < 3; j++) {
var x = 3 + (i * 100);
var y = 3 + (j * 100);
var newId = "svgTTTsqr" + i.toString() + j.toString();

// Use DOM manipulation instead of innerHTML
var rect = document.createElementNS(svg.namespaceURI, 'rect');
rect.setAttributeNS(null, "id", newId);
rect.setAttributeNS(null, "fill", "#00DD00");
rect.setAttributeNS(null, "width", "93");
rect.setAttributeNS(null, "height", "93");
rect.setAttributeNS(null, "x", x);
rect.setAttributeNS(null, "y", y);
svg.appendChild(rect);

//make a cell object to contain all of this
var cell = {
col: i,
row: j,
pSvg: brd,
rect: rect,

handleClick: function (event) {
try {
//console.log(this);
var svgNS = brd.namespaceURI;
var line = document.createElementNS(svgNS, 'line');
line.setAttributeNS(null, "x1", this.x.baseVal.value);
line.setAttributeNS(null, "y1", this.y.baseVal.value);
line.setAttributeNS(null, "x2", this.x.baseVal.value + this.width.baseVal.value);
line.setAttributeNS(null, "y2", this.y.baseVal.value + this.height.baseVal.value);
brd.appendChild(line);
}
catch (err) {
alert("handlClick err: " + err);
}
}
}

//add a click handler for the rect/cell
cell.rect.addEventListener("click", cell.handleClick, false);

//save the cell object for later use
cells[i][j] = cell;
}
}
}
line {
stroke: red;
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"
id="svgTTT" width="150" height="150" viewBox="0 0 300 300" >
<rect width="3" height="300" x="99" fill="#008d46" />
<rect width="3" height="300" x="199" fill="#000000" />
<rect width="300" height="3" y="99" fill="#008d46" />
<rect width="300" height="3" y="199" fill="#d2232c" />
</svg>

关于javascript - addEventListener 和 `this` 未按预期工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32800782/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com