使用vanilla JS开发Web Components时如何在函数内部访问shadowRoot
问题根因
你当前的问题出在forEach回调的this指向错误:你使用普通匿名函数作为panels.forEach的回调,普通函数的this由调用方决定,Array.prototype.forEach默认回调的this在非严格模式下指向window,严格模式下为undefined,你在回调内部执行divVisibility.bind(this)时,绑定的this已经不是外层的Web Component实例了,自然传递到hideNonVisibleDivs里的this不符合预期。
另外你提供的代码末尾多了一个多余的闭合符});,会触发语法错误,修复时需要删除。
修复方案
- 方案1:用箭头函数改写forEach回调(最简单)
箭头函数的this继承自外层词法作用域,不需要额外绑定,同时可以把重复的bind改成call减少不必要的新函数生成开销,修改后代码如下:
var visibleDivId = null; var i, divId, div; console.log('shadowroot', this); // 这里的this是组件实例,能正常拿到shadowRoot function divVisibility(divId) { hideNonVisibleDivs.call(this, divId); // 直接call指定上下文即可 } function hideNonVisibleDivs(divId) { console.log('shadowroot', this); // 这里的this和外层一致,可以正常访问this.shadowRoot } var panels = this.shadowRoot.querySelectorAll("#tab-info> .share-tab") // 箭头函数的this继承自外层作用域 panels.forEach(el => { divVisibility.call(this, el.getAttribute('custom-id')); });
- 方案2:提前缓存外层实例(不需要处理this绑定)
如果不想处理this指向问题,可以在外层提前把组件实例存到变量中,所有需要的地方直接调用该变量访问shadowRoot即可:
const componentInstance = this; // 提前缓存外层组件实例 var visibleDivId = null; var i, divId, div; console.log('shadowroot', componentInstance); function divVisibility(divId) { hideNonVisibleDivs(divId); } function hideNonVisibleDivs(divId) { // 直接用缓存的实例访问shadowRoot,无需处理this指向 console.log('shadowroot', componentInstance); console.log(componentInstance.shadowRoot); } var panels = componentInstance.shadowRoot.querySelectorAll("#tab-info> .share-tab") panels.forEach(function(el) { divVisibility(el.getAttribute('custom-id')); });
- 方案3:使用forEach的第二个参数指定回调上下文
Array.prototype.forEach支持传入第二个参数作为回调函数的this指向:
var visibleDivId = null; var i, divId, div; console.log('shadowroot', this); function divVisibility(divId) { hideNonVisibleDivs.call(this, divId); } function hideNonVisibleDivs(divId) { console.log('shadowroot', this); } var panels = this.shadowRoot.querySelectorAll("#tab-info> .share-tab") // 第二个参数传入this,指定回调内部的this为外层组件实例 panels.forEach(function(el) { divVisibility.call(this, el.getAttribute('custom-id')); }, this);
内容的提问来源于stack exchange,提问作者The Dead Man
相关产品推荐
相关产品推荐

