Javascript 在另一个eventListener的函数中包含一个eventListener是一种不好的做法吗?

Javascript 在另一个eventListener的函数中包含一个eventListener是一种不好的做法吗?,javascript,html,Javascript,Html,我的代码按预期运行,我正在从数组创建一个下拉菜单。然后,我获取每个下拉列表的值,并根据下拉列表的选择将一个变量分配给一个数字。然后通过innerHTML在p>中显示变量结果。(我试着用appendChild(document.createTextNode)代替innerHTML,但它会一直把结果添加到p> 我需要它根据下拉列表进行更改(而不是添加)。此外,我需要将下拉列表的变量结果(数字)和event.target.value信息传递给输入字段上的另一个eventlistener,该字段接受用户

我的代码按预期运行,我正在从数组创建一个下拉菜单。然后,我获取每个下拉列表的值,并根据下拉列表的选择将一个变量分配给一个数字。然后通过innerHTML在p>中显示变量结果。(我试着用
appendChild(document.createTextNode)
代替innerHTML,但它会一直把结果添加到p>

我需要它根据下拉列表进行更改(而不是添加)。此外,我需要将下拉列表的变量结果(数字)和
event.target.value
信息传递给输入字段上的另一个eventlistener,该字段接受用户的输入,并将第一个eventlistener中变量的输入相乘。然后在第二个
上注入innerHTML

我让它工作了,但问题是把一个eventlistener放在另一个eventlistener中是不是很糟糕?还有别的解决办法吗?我尝试拉出第一个回调函数,并使用返回的变量创建自己的函数。我向第二个eventlistener调用了它,但最终没有定义项(
event.target.value

以下是我的代码库:

HTML


这取决于每个用例。但是,在您的情况下,这是过度的,因为每次更改
select
时,您并不真正想要一个全新的函数,您只想更改输出。如果只需扩大
裁剪的范围
,则只需设置一次输入处理程序

此外,当所涉及的字符串不包含任何HTML时,您不应该使用
.innerHTML
,因为
.innerHTML
具有性能和安全影响。改用
.textContent

const cameraMakeArray=['Canon5DM2','PanasonicGH5','SonyA7CropMode']
const cameraMake=document.getElementById(“cameraMakes”)
常量长度=document.getElementById(“长度”)
const yourCrop=document.querySelector(“yourCrop”)
const results=document.querySelector(“结果”)
//输出变量存储在比
//任何一个回调函数,一个函数都可以设置它和
//其他人可以使用它。这允许您摆脱嵌套的
//事件处理程序。
让作物=0
cameraMakeArray.forEach(摄影机=>{
让opt=document.createElement('option');
opt.textContent=摄像机;
opt.value=摄像机;
document.createElement
卡美拉梅。附加儿童(opt);
});
cameraMake.addEventListener('change',(事件)=>{
如果(事件){
results.textContent='';
length.value=“”
}
如果(event.target.value==='Canon5DM2'){
作物=1;
}else if(event.target.value=='PanasonicGH5'){
作物=2;
}else if(event.target.value=='SonyA7CropMode'){
作物=1.5
}
yourCrop.textContent=`The${event.target.value}有一个${crop}x因子`;
});
长度.addEventListener('input',(evt)=>{
if(长度值){
results.textContent=`A${length.value}mm镜头相当于${cameraMake.options[cameraMake.selectedIndex].textContent}上的${length.value*crop}mm镜头`
}否则{
results.textContent='';
}
});



看看这个版本

const cameraMakeObject={
“佳能5DM2”:1,
“PanasonicGH5”:2,
“SonyA7CropMode”:1.5
}
const cameraMake=document.getElementById(“cameraMakes”)
常量长度=document.getElementById(“长度”)
const yourCrop=document.querySelector(“yourCrop”)
const results=document.querySelector(“结果”)
让作物=0
常量计算=函数(){
results.textContent=(length.value)?
`${length.value}mm镜头相当于${cameraMake.value}`:''上的${length.value*cameraMakeObject[cameraMake.value]}mm镜头;
};
key(cameraMakeObject).forEach(camera=>{
让opt=document.createElement('option');
opt.innerHTML=照相机;
opt.value=摄像机;
卡美拉梅。附加儿童(opt);
})
cameraMake.addEventListener('change',function(){
让val=cameraMakeObject[this.value]| |“未知”
yourCrop.innerHTML=val==“未知”?“”:“${this.value}有一个${val}x因子”;
})
长度.addEventListener('输入',计算)

请选择


这是一种不错的做法,但在这里是不正确的 在您的用例中,每次对
#cameraMake
应用更改时,您都会创建一个新的事件侦听器,因此,在五次更改之后,
#length
上的输入事件将有五个事件侦听器

您要做的是创建一次事件监听器,因此从更改事件监听器中删除它是正确的用例

//在此处创建裁剪,以便您可以在任一侦听器中访问它
让crop=0;
cameraMake.addEventListener('change',event=>{
//修改作物
裁剪=/*一个值*/
})
//仅附加一次
length.addEventListener('input',()=>{
//不要使用`event.target.value`use`cameraMake.value``
//您现在可以在此处访问crop
})
何时嵌套事件侦听器 将事件监听器放置在另一个监听器内部的正确用例可以是创建一个事件监听器,该监听器在外部监听器触发后只触发一次

注意:还有其他用例,请确保在嵌套事件侦听器时检查代码的工作方式,并删除额外/过时的事件侦听器

例如:

函数侦听器(事件){
//在此处定义,以便将其删除
}
el1.addEventListener('some-event',event=>{
el2.removeEventListener('some-event',listener)
el2.addEventListener('some-event',listener,{once:true})
})

是的,这很糟糕。每次触发cameraMake.change事件时,它都会在length.input上分配一个新的事件处理程序。你最终会得到很多。只需添加
len即可
<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>
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 = ''
        }
    })
})