我的代码正在按预期运行,我正在从一个数组创建一个下拉菜单。然后,我将获取每个下拉列表的值,并根据下拉列表的选择将变量分配给数字。然后通过innerHTML在p>中显示变量结果。 (我尝试做appendChild(document.createTextNode)
而不是innerHTML,但这只会继续将结果添加到p>。
我需要它根据下拉列表进行更改(而不是添加)。此外,我需要将变量结果(数字)和下拉列表的event.target.value
信息传递到输入字段中的另一个事件侦听器,该输入侦听器接受用户输入并乘以第一个事件侦听器中的变量输入。然后,将innerHTML注入第二个<p>
。
我可以正常工作了,但问题是将事件监听器放在另一个事件监听器中是不正确的做法吗?还有其他解决方案吗?我尝试提取第一个回调函数并使用返回的变量创建其自己的函数。我将其称为第二事件监听器,但最终导致项未定义(特别是event.target.value
)。
这是我的代码库:
HTML
<select id='cameraMakes' class='cameraSelects'></select>
<p id='yourCrop'></p>
<input id="length" type="text" name="lens" placeholder="Enter lens mm a" /><br>
<p id='results'></p>
JS
const cameraMakeArray = ['Canon5DM2', 'PanasonicGH5', 'SonyA7CropMode']
const cameraMake = document.getElementById("cameraMakes")
const length = document.getElementById("length")
const yourCrop = document.querySelector("#yourCrop")
const results = document.querySelector("#results")
cameraMakeArray.forEach(camera => {
let opt = document.createElement('option');
opt.innerHTML = camera;
opt.value = camera;
document.createElement
cameraMake.appendChild(opt);
})
cameraMake.addEventListener('change', (event) => {
let crop = 0
if (event) {
results.innerHTML = '';
length.value = ''
}
if (event.target.value === 'Canon5DM2') {
crop = 1;
} else if (event.target.value === 'PanasonicGH5') {
crop = 2;
} else if (event.target.value === 'SonyA7CropMode') {
crop = 1.5
}
yourCrop.innerHTML = `The ${event.target.value} has a ${crop}x factor`;
length.addEventListener('input', () => {
if (length.value) {
results.innerHTML = `A ${length.value}mm lens is equivalent to a ${length.value * crop}mm lens on the ${event.target.value}`
} else {
results.innerHTML = ''
}
})
})
答案 0 :(得分:1)
这取决于每个用例。但是,在您的情况下,这是多余的,因为每次更改React
时,您实际上并不想要全新的功能,您只需要更改输出。如果您只是扩大select
的范围,则可以只设置一次输入处理程序。
此外,当所涉及的字符串不包含任何HTML时,您不应使用crop
,因为.innerHTML
具有性能和安全性。请改用.innerHTML
。
.textContent
const cameraMakeArray = ['Canon5DM2', 'PanasonicGH5', 'SonyA7CropMode']
const cameraMake = document.getElementById("cameraMakes")
const length = document.getElementById("length")
const yourCrop = document.querySelector("#yourCrop")
const results = document.querySelector("#results")
// With the output variable stored at a higher scope than
// either callback function, one function can set it and the
// other can use it. This allows you to get rid of the nested
// event handler.
let crop = 0
cameraMakeArray.forEach(camera => {
let opt = document.createElement('option');
opt.textContent = camera;
opt.value = camera;
document.createElement
cameraMake.appendChild(opt);
});
cameraMake.addEventListener('change', (event) => {
if (event) {
results.textContent = '';
length.value = ''
}
if (event.target.value === 'Canon5DM2') {
crop = 1;
} else if (event.target.value === 'PanasonicGH5') {
crop = 2;
} else if (event.target.value === 'SonyA7CropMode') {
crop = 1.5
}
yourCrop.textContent = `The ${event.target.value} has a ${crop}x factor`;
});
length.addEventListener('input', (evt) => {
if (length.value) {
results.textContent = `A ${length.value}mm lens is equivalent to a ${length.value * crop}mm lens on the ${cameraMake.options[cameraMake.selectedIndex].textContent}`
} else {
results.textContent = '';
}
});
您可能还需要考虑将<select id='cameraMakes' class='cameraSelects'></select>
<p id='yourCrop'></p>
<input id="length" type="text" name="lens" placeholder="Enter lens mm a" /><br>
<p id='results'></p>
数组值更改为一个对象。这样,您可以将键和值一起存储,而不必进行任何select
来根据选择来设置变量。另外,如果将第二个回调分隔为一个命名函数,则可以在选择更改时调用它,以在输出区域中立即获得更新。
if/then
// Now, each camera can store a key along with a value:
const cameras = {
Canon5DM2: 1,
PanasonicGH5: 2,
SonyA7CropMode: 1.5
};
const cameraMakes = document.getElementById("cameraMakes")
const length = document.getElementById("length")
const yourCrop = document.querySelector("#yourCrop")
const results = document.querySelector("#results")
// Loop through the object:
for(camera in cameras){
let opt = document.createElement('option');
opt.textContent = camera;
opt.value = cameras[camera]; // Get the value that goes with the key
cameraMakes.appendChild(opt);
}
cameraMakes.addEventListener('change', (event) => {
yourCrop.textContent =
`The ${cameraMakes.options[cameraMakes.selectedIndex].textContent} has a ${cameraMakes.value}x factor`;
if(results.textContent !== ""){
displayResults(); // Update the output because the camera changed
}
});
// By making this a function declaration, you can call it manually
function displayResults() {
results.textContent =
`A ${length.value}mm lens is equivalent to a ${length.value * cameraMakes.value}mm lens on the ${cameraMakes.options[cameraMakes.selectedIndex].textContent}`;
}
length.addEventListener('input', displayResults);
答案 1 :(得分:0)
看看这个版本
const cameraMakeObject = {
'Canon5DM2': 1,
'PanasonicGH5': 2,
'SonyA7CropMode': 1.5
}
const cameraMake = document.getElementById("cameraMakes")
const length = document.getElementById("length")
const yourCrop = document.querySelector("#yourCrop")
const results = document.querySelector("#results")
let crop = 0
const calc = function() {
results.textContent = (length.value) ?
`A ${length.value}mm lens is equivalent to a ${length.value * cameraMakeObject[cameraMake.value]}mm lens on the ${cameraMake.value}` : '';
};
Object.keys(cameraMakeObject).forEach(camera => {
let opt = document.createElement('option');
opt.innerHTML = camera;
opt.value = camera;
cameraMake.appendChild(opt);
})
cameraMake.addEventListener('change', function() {
let val = cameraMakeObject[this.value] || "unknown"
yourCrop.innerHTML = val === "unknown" ? "" : `The ${this.value} has a ${val}x factor`;
})
length.addEventListener('input', calc)
<select id='cameraMakes' class='cameraSelects'>
<option value="">Please select</option>
</select>
<p id='yourCrop'></p>
<input id="length" type="text" name="lens" placeholder="Enter lens mm a" /><br>
<p id='results'></p>
答案 2 :(得分:0)
在您的用例中,每次对#cameraMake
进行更改时,您都将创建一个新的事件侦听器,因此,在进行五次更改后,#length
上的输入事件将有五个事件侦听器。
您要做的是一次创建事件侦听器,因此从更改事件侦听器中删除它是正确的用例。
// create crop here so you can access it in either listener
let crop = 0;
cameraMake.addEventListener('change', event => {
// modify crop
crop = /* a value */
})
// attached only once
length.addEventListener('input', () => {
// instead of using `event.target.value` use `cameraMake.value`
// you can now access crop here
})
将事件侦听器放置在另一个事件侦听器中的正确用例可能是创建一个事件侦听器,该事件侦听器在外部侦听器触发后仅触发一次。
注意:还有其他用例,请确保在嵌套事件侦听器时检查代码的工作方式,并删除多余的/陈旧的事件侦听器。
示例:
function listener(event) {
// defined here so it can be removed
}
el1.addEventListener('some-event', event => {
el2.removeEventListener('some-event', listener)
el2.addEventListener('some-event', listener, { once: true })
})