阻止事件传播到同一 Web 组件的另一个实例?
Stop event from propagating to another instance of same web component?
我有一个 child 网络组件 (exercise-input
),它带有一个自定义事件,可以将一些数据发送到我的 parent 网络组件 (muscle-group
) 它是问题是,当我将 parent 组件的其他实例添加到页面时,child 组件中更新 parent 组件中的值的按钮将更新该值在 parent 组件的每个实例上。
我在 child 中使用了 document.dispatchEvent(numSetsDecrease)
,在 parent 中使用了 document.addEventListener
- 有什么我需要用什么来替换“文档”吗?我需要以某种方式 stop propagation 吗?
child 组件:
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', {
bubbles: false,
detail: {
numSetValue: 1
}
});
document.dispatchEvent(numSetsIncrease);
});
}
}
window.customElements.define('exercise-input', ExerciseInput);
parent 组件:
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
从其 children
捕获 all 命名事件
代替你:
- 来自您的按钮的 dispatchEvent
- 事件需要
bubbles:true
和composed:true
才能穿越shadowRoots
<muscle-group>
的监听器然后捕获冒泡事件并处理它们
它只接收来自其 children! 的事件
- 如果你没有有嵌套组你没有使用
stopPropagation
,事件冒泡到document
没有伤害
PS。您的 <exercise-iput>
有 2 个按钮,它们的功能相同,一个加,一个减。
当您 copy/pasted 第一个按钮代码时,"This Needs A Component" 警报应该警告您创建 <exercise-input-button add="-1">
我有一个 child 网络组件 (exercise-input
),它带有一个自定义事件,可以将一些数据发送到我的 parent 网络组件 (muscle-group
) 它是问题是,当我将 parent 组件的其他实例添加到页面时,child 组件中更新 parent 组件中的值的按钮将更新该值在 parent 组件的每个实例上。
我在 child 中使用了 document.dispatchEvent(numSetsDecrease)
,在 parent 中使用了 document.addEventListener
- 有什么我需要用什么来替换“文档”吗?我需要以某种方式 stop propagation 吗?
child 组件:
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', {
bubbles: false,
detail: {
numSetValue: 1
}
});
document.dispatchEvent(numSetsIncrease);
});
}
}
window.customElements.define('exercise-input', ExerciseInput);
parent 组件:
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
从其 children
代替你:
- 来自您的按钮的 dispatchEvent
- 事件需要
bubbles:true
和composed:true
才能穿越shadowRoots <muscle-group>
的监听器然后捕获冒泡事件并处理它们
它只接收来自其 children! 的事件
- 如果你没有有嵌套组你没有使用
stopPropagation
,事件冒泡到document
没有伤害
PS。您的 <exercise-iput>
有 2 个按钮,它们的功能相同,一个加,一个减。
当您 copy/pasted 第一个按钮代码时,"This Needs A Component" 警报应该警告您创建 <exercise-input-button add="-1">