自定义元素中在XMLHttpRequest回调内调用组件方法的问题
自定义HTML元素StaffList回调中访问组件方法的问题解决
问题描述
编写自定义HTML元素StaffList时遇到以下问题:
- 在
connectedCallback()方法中通过XMLHttpRequest请求数据后,调用组件的addStaff方法时,用super会触发语法错误:Uncaught SyntaxError: use of super property accesses only valid within methods or eval code within methods - 用
this时,this指向XMLHttpRequest对象而非自定义元素实例,导致无法调用组件方法
原代码(注:原代码存在语法错误,addStaff方法需移至类内部):
class StaffList extends HTMLElement { // selected属性的getter/setter get selected() { return this.hasAttribute('selected'); } set selected(val) { if (val) { this.setAttribute('selected', ''); } else { this.removeAttribute('selected'); } } constructor() { super(); // 绑定子元素点击事件 for (const item of this.children) { item.addEventListener('click', e => { console.log(e); }); } } connectedCallback() { var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { for (var item of JSON.parse(this.responseText)) { console.log(item); this.addStaff(item); } } }; xhttp.open('GET', "/api/get_staff"); xhttp.send(); } // 修正:将addStaff移至类内部 addStaff(item) { console.log("add staff", item); } } customElements.define('staff-list', StaffList);
问题原因
- 传统函数作为
onreadystatechange回调时,this会绑定到调用它的对象(即XMLHttpRequest实例),而非自定义元素实例 super只能在类的方法内部使用,回调函数不属于类的方法,因此使用super会触发语法错误
解决方法
方法1:使用箭头函数
箭头函数不会绑定自身的this,会继承外层作用域的this(即StaffList实例):
connectedCallback() { const xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = () => { if (xhttp.readyState == 4 && xhttp.status == 200) { for (const item of JSON.parse(xhttp.responseText)) { console.log(item); this.addStaff(item); // this指向StaffList实例 } } }; xhttp.open('GET', "/api/get_staff"); xhttp.send(); }
方法2:提前保存组件实例到变量
在connectedCallback中先将组件实例的this保存到变量,回调中使用该变量:
connectedCallback() { const self = this; // 保存组件实例引用 const xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { for (const item of JSON.parse(this.responseText)) { console.log(item); self.addStaff(item); // 使用self访问组件实例 } } }; xhttp.open('GET', "/api/get_staff"); xhttp.send(); }
方法3:使用bind绑定this
通过bind方法将回调函数的this强制绑定到组件实例:
connectedCallback() { const xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { for (const item of JSON.parse(this.responseText)) { console.log(item); this.addStaff(item); // this指向StaffList实例 } } }.bind(this); // 绑定组件实例到回调的this xhttp.open('GET', "/api/get_staff"); xhttp.send(); }
额外建议:使用fetch替代XMLHttpRequest
现代浏览器推荐使用fetch API,基于Promise的写法更简洁易读:
async connectedCallback() { try { const response = await fetch("/api/get_staff"); const staffList = await response.json(); for (const item of staffList) { this.addStaff(item); } } catch (error) { console.error('获取员工数据失败:', error); } }
内容的提问来源于stack exchange,提问作者user21776820
相关产品推荐
相关产品推荐

