继承自定义JS类时出现ReferenceError:超类未定义的原因与解决
核心问题:QuickaddDrawer类未被识别的原因及修复方案
你遇到的Uncaught ReferenceError: QuickaddDrawer is not defined错误,根源是类的作用域限制:QuickaddDrawer是定义在if(!customElements.get("quickadd-drawer"))这个块级作用域内的类,外部的CardBubbles无法访问到局部作用域里的类定义。
你的代码片段
if(!customElements.get("quickadd-drawer")) { customElements.define("quickadd-drawer", class QuickaddDrawer extends HTMLElement { constructor() { super(); this.sidecart = document.querySelector("side-cart"); } connectedCallback() { this.atcBtn = this.querySelector(".atc-btn"); this.atcBtn.addEventListener("click", this.toggleDrawer.bind(this)); this.quickaddBtns = this.querySelectorAll(".quickadd-btn:not([disabled])"); this.quickaddBtns.forEach(btn => btn.addEventListener("click", this.quickAddItem.bind(this))); } toggleDrawer() { this.atcBtn.classList.toggle("drawer--open"); } quickAddItem(event) { const btn = event.target; const variantId = btn.dataset.quickAdd; console.log("button", btn, variantId); this.sidecart.addToCart(variantId); } }); } class CardBubbles extends QuickaddDrawer { constructor() { super(); this.productCard = this.closest('product-card'); this.bubbles = this.querySelectorAll('li>a'); this.quickaddListings = this.productCard.querySelector('.quickadd-btn__listing'); this.slideAnchors = this.productCard.querySelectorAll('.product-card__wrapper .swiper-slide a'); this.initBubbles(); } initBubbles() { this.bubbles.forEach(item=> item.addEventListener('click', this.handleClick.bind(this))); } handleClick(event) { event.preventDefault(); this.updateImageLink(event); // update available size buttons this.checkForData(event); // update add to cart button // update featured images // update circled swatch } updateImageLink(event) { const variantLink = new URL(event.target.href); this.slideAnchors.forEach(el=>{ el.href = el.href.replace(/\/products\/(.*)/, variantLink.pathname); }); } checkForData(event) { // update with available sizes let targetVariantJSON = document.querySelector(`product-card script[data-product-id="${event.target.dataset.productId}"]`); if (targetVariantJSON) { const data = JSON.parse(targetVariantJSON.textContent); this.updateQuickaddBtns(data); this.updateImages(data); } else { console.log('fetching JSON'); fetch(`${event.target.href}.js`) .then( res => res.json()) .then( data => this.updateQuickaddBtns(data)); } // bind to quickadd functions } updateQuickaddBtns(data) { console.log(data); console.log(data.available); let availableSizes=[]; this.quickaddListings.innerHTML = ''; data.variants.forEach(item=>{ console.log(`Variant: ${item.id}, size ${item.option1} is available: ${item.available}`); const newButton = document.createElement('a'); newButton.classList.add('quickadd-btn'); newButton.dataset.quickAdd = item.id; newButton.innerText = item.option1; if (item.available == false) { console.log('is false, will attempt to add disabled attribute now'); newButton.setAttribute("disabled", ""); } this.quickaddListings.append(newButton); }); console.log(availableSizes); } updateImages(data) { //update images with data } } customElements.define('card-bubbles', CardBubbles);
修复方案
以下三种方式均可解决问题,可根据项目实际情况选择:
方案1:将QuickaddDrawer提升到全局作用域
把类定义移出if块,先声明全局类再注册自定义元素,确保外部子类能访问到:
// 全局声明QuickaddDrawer类 class QuickaddDrawer extends HTMLElement { constructor() { super(); this.sidecart = document.querySelector("side-cart"); } connectedCallback() { this.atcBtn = this.querySelector(".atc-btn"); this.atcBtn.addEventListener("click", this.toggleDrawer.bind(this)); this.quickaddBtns = this.querySelectorAll(".quickadd-btn:not([disabled])"); this.quickaddBtns.forEach(btn => btn.addEventListener("click", this.quickAddItem.bind(this))); } toggleDrawer() { this.atcBtn.classList.toggle("drawer--open"); } quickAddItem(event) { const btn = event.target; const variantId = btn.dataset.quickAdd; console.log("button", btn, variantId); this.sidecart.addToCart(variantId); } } // 仅当元素未注册时执行注册 if(!customElements.get("quickadd-drawer")) { customElements.define("quickadd-drawer", QuickaddDrawer); } // 现在可正常继承 class CardBubbles extends QuickaddDrawer { // ... 你的子类实现 } customElements.define('card-bubbles', CardBubbles);
方案2:通过customElements.get获取已注册的类
自定义元素注册后,可通过customElements.get("标签名")获取对应的类,直接用于继承:
if(!customElements.get("quickadd-drawer")) { customElements.define("quickadd-drawer", class QuickaddDrawer extends HTMLElement { // ... 类实现 }); } // 从自定义元素注册表中获取类 const QuickaddDrawer = customElements.get("quickadd-drawer"); class CardBubbles extends QuickaddDrawer { // ... 你的子类实现 } customElements.define('card-bubbles', CardBubbles);
方案3:将CardBubbles移到if块内部(若无需单独暴露子类)
如果CardBubbles仅需依赖QuickaddDrawer存在时才定义,可将子类定义放入if块内:
if(!customElements.get("quickadd-drawer")) { class QuickaddDrawer extends HTMLElement { // ... 类实现 } customElements.define("quickadd-drawer", QuickaddDrawer); // 在块内定义子类 class CardBubbles extends QuickaddDrawer { // ... 你的子类实现 } customElements.define('card-bubbles', CardBubbles); }
附加问题:QuickaddDrawer包裹在条件语句中的原因
这个条件判断if(!customElements.get("quickadd-drawer"))的核心作用是避免重复注册自定义元素报错。
根据Web Components规范,重复调用customElements.define()注册同一标签名的元素会抛出DOMException。该判断逻辑确保只有当quickadd-drawer未被注册时,才执行定义操作,防止脚本重复加载(比如页面多次引入同一段代码)时出现错误。
其他类未做此处理,可能是因为这些元素的注册逻辑已被确保只会执行一次,或者不会出现重复加载的场景。
内容的提问来源于stack exchange,提问作者Kirkwood
相关产品推荐
相关产品推荐

