我是JavaScript初学者,我有一些代码在功能方面完美运行但是 不 DRY和"脏"。 ..只是看着那段代码让我感到恶心。 所以,我决定做一个非常漂亮,现代,干净和干燥的版本。 但是现在我完全陷入了困境,尽管搜索高低也无法找到任何可以理解的东西我做错了什么? 最重要的是:为什么这是错的?
所以,这是当前的代码:
document.addEventListener("DOMContentLoaded", function() {
// parent div that holds the navigation wheel:
var navDiv = document.querySelector("#wrapper > section > div");
navDiv.addEventListener("mousedown", moveEye, false);
navDiv.addEventListener("mouseup", stopEye, false);
var eye = document.querySelector("#eyeball"),
iris = document.querySelector("#iris"),
reqID;
function moveEye(e) {
var btnClicked = e.target.id;
// alert("Button clicked: " + btnClicked);
if (btnClicked === "right") {
eye.style.left = (eye.offsetLeft += 3) + "px";
} else if (btnClicked === "left") {
eye.style.left = (eye.offsetLeft -= 3) + "px";
} else if (btnClicked === "top") {
eye.style.top = (eye.offsetTop -= 3) + "px";
} else if (btnClicked === "bottom") {
eye.style.top = (eye.offsetTop += 3) + "px";
}
reqID = window.requestAnimationFrame(moveEye);
}
function stopEye(e) {
cancelAnimationFrame(reqID);
}
}, false);

<div id="wrapper">
<p>Description comes here.</p>
<section>
<p>Navigation Wheel:</p>
<div>
<span id="top"></span>
<span id="bottom"></span>
<span id="left"></span>
<span id="right"></span>
<span id="hub"></span>
</div>
</section>
<section id="stage">
<figure id="eyeball">
<span id="shadow"></span>
<span id="iris" class="irisMove"></span>
</figure>
</section>
</div>
&#13;
请注意,我特别想保持这个:
var navDiv = document.querySelector("#wrapper > section > div");
因为我希望将代码保持为DRY并且尽可能保持干净。 这就是为什么我选择包含4个按钮的父 div的原因 而不是单独的4个按钮中的每一个。 所以,我想听父div来告诉我当前正在点击里面的4个按钮(即4个span元素)中的哪一个,当用户按住鼠标按下按钮/ span时我希望requestAnimationFrame为做它的工作! 那就是它!没问题,对吧?
但正如我所理解的那样,导致此错误的darn requestAnimationFrame: &#34;未捕获的TypeError:无法读取属性&#39; id&#39;未定义&#34;
最大的问题是:为什么??? 为什么requestAnimationFrame说它&#34;未定义&#34; ?? 它工作正常,而不会在这里使用requestAnimationFrame。
所以,请解释一下: 我究竟做错了什么? 最重要的是: 为什么这是错的?
答案 0 :(得分:1)
当响应鼠标单击调用moveEye
时,会为其提供一个事件对象作为第一个参数。事件对象具有target
属性。
从moveEye
调用requestAnimationFrame
作为回调时,会传递DOMHighResTimeStamp双精度数。 JavaScript允许尝试通过自动将数字转换为Number对象来访问数字上的属性。
但是,Number对象没有target
属性,因此从属性查找返回的值为undefined
。现在,尝试访问未定义的id
属性的target
属性会生成错误。
document.addEventListener("DOMContentLoaded", function() {
// parent div that holds the navigation wheel:
var navDiv = document.querySelector("#wrapper > section > div");
navDiv.addEventListener("mousedown", startEye, false);
navDiv.addEventListener("mouseup", stopEye, false);
var eye = document.querySelector("#eyeball"),
iris = document.querySelector("#iris"),
reqID,
btnClicked = "";
function startEye(e) {
btnClicked = e.target.id;
moveEye();
}
function moveEye() {
var left = parseFloat( eye.style.left);
var top = parseFloat( eye.style.top);
if ( btnClicked === "right") {
eye.style.left = (left + 3) + "px";
}
else if ( btnClicked === "left") {
eye.style.left = (left -3) + 'px';
}
else if ( btnClicked === "top") {
eye.style.top = (top - 3) + "px";
}
else if ( btnClicked === "bottom") {
eye.style.top = (top + 3) + "px";
}
reqID = window.requestAnimationFrame(moveEye);
}
function stopEye(e) {
cancelAnimationFrame(reqID);
}
},false);
<div id="wrapper">
<p>Description comes here.</p>
<section>
<p>Navigation Wheel:</p>
<div>
<span id="top">top</span>
<span id="bottom">bottom</span>
<span id="left">left</span>
<span id="right">right</span>
<span id="hub"></span>
</div>
</section>
<section id="stage">
<figure id="eyeball" style="position: relative; top:0px; left: 0px">
eyeball
<span id="shadow"></span>
<span id="iris" class="irisMove"></span>
</figure>
</section>
</div>
TLDR;
请注意,.offsetLeft
和offsetTop
是只读元素属性。像(eye.offsetTop += 3)
或(eye.offsetLeft -= 3)
这样的表达式不会更新属性的值,会严重误导,不应该留在代码中。
CSS属性left
/ top
和元素属性offSetLeft
/ offsetTop
不使用相同的参考来源。最初这导致单击“左”以向右移动元素。采用的解决方案是使用CSS left
和top
属性设置要移动的元素(#eyeball)的样式,并使用它们来读取和更新位置。这就是示例中未使用offSetLeft
和.offsetTop
的原因。
答案 1 :(得分:0)
此代码:
window.requestAnimationFrame(moveEye);
...将导致moveEye
被调用,有点像这样:
moveEye(timestamp);
请注意,没有传递任何事件,而是传递时间戳。因此函数中的e.target
将是未定义的,这就是e.target.id
失败的原因。
如果你的目的是做一个动画循环,你需要&#34;捕捉&#34;相关数据。关闭会使这成为可能:
function moveEye(e) {
var btnClicked = e.target.id;
function animate() {
if (btnClicked === "right") {
eye.style.left = (eye.offsetLeft += 3) + "px";
} else if (btnClicked === "left") {
eye.style.left = (eye.offsetLeft -= 3) + "px";
} else if (btnClicked === "top") {
eye.style.top = (eye.offsetTop -= 3) + "px";
} else if (btnClicked === "bottom") {
eye.style.top = (eye.offsetTop += 3) + "px";
}
reqID = window.requestAnimationFrame(animate);
}
animate();
}