slotchange事件赋值后image变量为何恢复默认值?
问题
我有一个代表图标的自定义元素,为其设置了默认图片,通过slot实现,插槽中的图片能正常显示。
我需要将图片路径保存到变量中,因此先在constructor中设置为默认图片路径,再在slotchange事件中更新。事件处理程序中已将image设置为插槽内容的图片路径,日志显示正确,但在点击图标处理程序中,image又变回默认值。
相关代码片段如下:
constructor() { this.image = this.shadowRoot.querySelector('slot[name="icon"] img').src // ... this.slots = this.shadowRoot.querySelectorAll('slot') this.slots.forEach(slot => { slot.addEventListener('slotchange', this.handleSlotChanges) }) }
此处设置图标默认图片并添加slotchange事件监听器。
handleSlotChanges (e) { if (e.target.name === 'icon') { this.image = e.target.assignedNodes()[0].src console.log(this.image) } }
此处将image设置为插槽内容的源路径,日志显示正确,该操作在元素创建时立即触发,因为图片已在HTML文件中插槽。
而在图标点击处理程序中,image又变回默认值:
handleClicks (e) { // ... console.log(this.image) }
我仅在constructor和slotchange事件处理程序中设置过image,为何会出现这种情况?
解决方案
问题出在事件处理函数的this指向错误。当你直接将this.handleSlotChanges作为回调传给addEventListener时,事件触发时的this会指向触发事件的<slot>元素,而非自定义元素实例。这意味着你在handleSlotChanges里修改的this.image其实是给slot元素新增了一个属性,根本没改动自定义元素实例上的this.image——所以点击时打印的还是constructor里设置的默认值。
可以通过以下几种方式修复:
- 绑定this到实例:在constructor中提前把handleSlotChanges的this绑定到自定义元素实例
constructor() { this.image = this.shadowRoot.querySelector('slot[name="icon"] img').src // 绑定this this.handleSlotChanges = this.handleSlotChanges.bind(this) this.slots = this.shadowRoot.querySelectorAll('slot') this.slots.forEach(slot => { slot.addEventListener('slotchange', this.handleSlotChanges) }) }
- 使用箭头函数包裹:箭头函数会继承外层作用域的this,确保指向自定义元素实例
constructor() { this.image = this.shadowRoot.querySelector('slot[name="icon"] img').src this.slots = this.shadowRoot.querySelectorAll('slot') this.slots.forEach(slot => { slot.addEventListener('slotchange', (e) => this.handleSlotChanges(e)) }) }
- 在回调中使用实例引用:在constructor里保存实例的引用,在事件回调中使用该引用修改属性
constructor() { const self = this this.image = this.shadowRoot.querySelector('slot[name="icon"] img').src this.slots = this.shadowRoot.querySelectorAll('slot') this.slots.forEach(slot => { slot.addEventListener('slotchange', function(e) { if (e.target.name === 'icon') { self.image = e.target.assignedNodes()[0].src console.log(self.image) } }) }) }
内容的提问来源于stack exchange,提问作者Dominus
相关产品推荐
相关产品推荐

