问题描述
我有一个带有自定义事件的子 Web 组件 (exercise-input
),该事件将一些数据发送到嵌套在其中的父 Web 组件 (muscle-group
)。问题是当我添加将父组件的其他实例添加到页面中,子组件中更新父组件中值的按钮将在父组件的每个实例上更新该值。
我在子进程中使用了 document.dispatchEvent(numSetsDecrease)
,在父进程中使用了 document.addEventListener
- 我需要用什么来替换“文档”?我需要以某种方式stop propagation吗?
子组件:
const exerciseInputTemplate = document.createElement('template');
exerciseInputTemplate.innerHTML = `
<div class="exercises">
<hr>
<div class="exerciseSetsRepRange">
<div class="sideBySide">
<input type="text" placeholder="Exercise">
<div class="numSetsBtns">
<button class="subtractSetBtn">-</button>
<span class="numSets"></span>
<button class="addSetBtn">+</button>
</div>
</div>
<div class="sideBySide">
<input type="number" placeholder="Rep Range Low" min="1">
<input type="number" placeholder="Rep Range High" min="1">
</div>
</div>
</div>
`;
class ExerciseInput extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open'});
this.shadowRoot.appendChild(exerciseInputTemplate.content.cloneNode(true));
}
connectedCallback() {
const subtractSetBtn = this.shadowRoot.querySelector('.subtractSetBtn');
const numSets = this.shadowRoot.querySelector('.numSets');
const addSetBtn = this.shadowRoot.querySelector('.addSetBtn');
numSets.textContent = 3 + ' sets';
// Click listner for subtract set btn with nested custom event
subtractSetBtn.addEventListener('click',function(event){
let numSetsInt = parseInt(numSets.textContent);
numSetsInt -= 1;
numSets.textContent = numSetsInt + ' sets';
if (parseInt(numSets.textContent) === 0) {
subtractSetBtn.disabled = true;
}
// Custom event sending -1 to the parent
const numSetsDecrease = new CustomEvent('numSetsDecrease',{
bubbles: false,detail: {
numSetValue: -1
}
});
document.dispatchEvent(numSetsDecrease);
});
// Click listner for add set btn with nested custom event
addSetBtn.addEventListener('click',function(event){
let numSetsInt = parseInt(numSets.textContent);
numSetsInt += 1;
numSets.textContent = numSetsInt + ' sets';
if (parseInt(numSets.textContent) > 0) {
subtractSetBtn.disabled = false;
}
// Custom event sending +1 to the parent
const numSetsIncrease = new CustomEvent('numSetsIncrease',detail: {
numSetValue: 1
}
});
document.dispatchEvent(numSetsIncrease);
});
}
}
window.customElements.define('exercise-input',ExerciseInput);
父组件:
const muscleGroupTemplate = document.createElement('template');
muscleGroupTemplate.innerHTML = `
<form class="programBuilder">
<div class="inputDiv muscleGroupDiv">
<input id="muscleGroupInput" name="muscleGroupInput" list="muscleGroupsList" placeholder="Muscle Group">
<datalist id="muscleGroupsList">
</datalist>
</div>
<div class="inputDiv setsDiv">
<label for="setsRange" class="setsValue"></label>
<input type="range" min="1" max="30" class="setsRange" value="15">
<p class="numSetsOutput"></p>
</div>
<exercise-input></exercise-input>
<exercise-input></exercise-input>
<exercise-input></exercise-input>
<button class="addExerciseBtn">Add Exercise</button>
</form>
`;
class MuscleGroup extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open'});
this.shadowRoot.appendChild(muscleGroupTemplate.content.cloneNode(true));
}
connectedCallback() {
// Updating the number sets output with data from the child elements
const numSetsOutput = this.shadowRoot.querySelector('.numSetsOutput');
numSetsOutput.textContent = '9 total sets';
document.addEventListener('numSetsDecrease',function(event){
let numSetsOutputValue = parseInt(numSetsOutput.textContent);
numSetsOutputValue += event.detail.numSetValue;
numSetsOutput.textContent = `${numSetsOutputValue} total sets`;
});
document.addEventListener('numSetsIncrease',function(event){
let numSetsOutputValue = parseInt(numSetsOutput.textContent);
numSetsOutputValue += event.detail.numSetValue;
numSetsOutput.textContent = `${numSetsOutputValue} total sets`;
});
}
}
window.customElements.define('muscle-group',MuscleGroup);
任何帮助将不胜感激!我一整天都在想办法解决这个问题。
解决方法
一个事件冒泡 DOM。
https://javascript.info/bubbling-and-capturing
document.addEventListener
从其子项中捕获所有命名事件
代替你:
- 来自按钮的dispatchEvent
- 事件需要
bubbles:true
和composed:true
才能穿越shadowRoots -
<muscle-group>
处的侦听器然后捕获冒泡事件并对其进行处理
它只接收来自它的孩子的事件! - 如果你没有有嵌套组你没有使用
stopPropagation
,事件冒泡到document
没有伤害立>
附注。您的 <exercise-iput>
有 2 个按钮,它们的作用相同,一个是加,一个是减。
在您复制/粘贴第一个按钮代码的那一刻,“This Needs A Component” 警报应该会警告您创建一个 <exercise-input-button add="-1">