Uncaught TypeError: __WEBPACK_IMPORTED_MODULE_7__vanilla_tabs__ is not a constructor
Uncaught TypeError: __WEBPACK_IMPORTED_MODULE_7__vanilla_tabs__ is not a constructor
我正在尝试导入 ES6 模块并遇到错误。模块是一个纯 Javascript 选项卡,可以变成响应式手风琴。您应该在下面找到 link 到 Javascript、My main-js 和模块的 Javascript。
https://github.com/ADTC/vanilla-tabs
我的 main.js 文件:
import VanillaTabs from './vanilla-tabs';
document.addEventListener('DOMContentLoaded', () => {
new VanillaTabs({
'selector': '.tabs', // default is ".tabs"
'type': 'horizontal', // can be horizontal / vertical / accordion
'responsiveBreak': 840, // tabs become accordion on this device width
'activeIndex' : 0 // active tab index (starts from 0 ). Can be -1 for accordions.
});
});
模块的外观如下:
class VanillaTabs {
constructor( opts ) {
const DEFAULTS = {
'selector': '.tabs',
'type': 'horizontal',
'responsiveBreak': 840,
'activeIndex' : 0
}
this.options = Object.assign( DEFAULTS, opts );
this.elems = document.querySelectorAll( this.options.selector );
// skip building tabs if they were already initialized
this.skipIfInitialized = ( tabsElem ) => {
// skip element if already initialized
if( tabsElem.classList.contains('tabs__initialized') ) {
return;
}
}
this.buildUI();
this.handleNavigation();
this.handleResponsive();
}
// initialize the UI Elements
buildUI(){
let tabs = this.elems;
// walk on all tabs on the page
tabs.forEach( ( el, i ) => {
let tabsElem = el,
childNodes = tabsElem.childNodes,
tabsTitles = [],
tabsStyle = this.options.type;
this.skipIfInitialized( tabsElem );
tabsElem.classList.add( 'style__' + this.options.type );
tabsElem.classList.add( 'tabs__initialized' );
for( let i = 0; i < childNodes.length; i++ ) {
let tabItem = childNodes[i];
if ( tabItem.nodeType != Node.TEXT_NODE ) {
// add tab__content CSS class
tabItem.classList.add( 'tabs__content');
// grab tab title from data attribute
let tabTitle = tabItem.dataset.title ? tabItem.dataset.title : '';
tabsTitles.push( tabTitle );
// wrap tab content
let tabContent = tabItem.innerHTML;
tabItem.innerHTML = '<div class="tabs__content_wrapper">' + tabContent + '</div>';
// insert nav link for accordion navigation
tabItem.insertAdjacentHTML( 'afterbegin', '<a class="tabs__nav_link">' + tabTitle + '</a>');
}
}
// create horizontal / vertical tabs navigation elements
let navElemsHTML = '';
tabsTitles.forEach( ( title ) => {
navElemsHTML = navElemsHTML + '<a class="tabs__nav_link">' + title + '</a>';
});
tabsElem.insertAdjacentHTML( 'afterbegin', '<li class="tabs__nav">' + navElemsHTML + '</li>');
// set initial active tab
let activeTabIndex = Number( this.options.activeIndex );
// validate active tab index. but, you can specify -1 for accordion tabs to make all of them closed by defaults
if( tabsStyle != 'accordion' && activeTabIndex != -1 ) {
if( activeTabIndex > (tabsTitles.length - 1) ) {
console.warn( 'VANILLA TABS: Active tab number from settings is bigger than tabs count. Please remember, that index starts from Zero! To avoid crashes, activeIndex option was reverted to 0.');
activeTabIndex = 0;
}
tabsElem.querySelectorAll( '.tabs__nav > .tabs__nav_link')[ activeTabIndex ].classList.add( 'is__active' );
tabsElem.querySelectorAll( '.tabs__content')[ activeTabIndex ].classList.add( 'is__active' );
tabsElem.querySelectorAll( '.tabs__content > .tabs__nav_link')[ activeTabIndex ].classList.add( 'is__active' );
}
});
}
// navigation: assign click events
handleNavigation() {
let tabs = this.elems,
tabsStyle = this.options.type;
// walk on all tabs on the page
tabs.forEach( ( el, i ) => {
let tabsElem = el;
this.skipIfInitialized( tabsElem );
tabsElem.addEventListener( 'click', function( e ){
if( e.target && e.target.classList.contains( 'tabs__nav_link') ) {
e.preventDefault();
let activeTabIndex;
// if we click on main navigation link
if( e.target.parentElement.classList == 'tabs__nav' ) {
activeTabIndex = Array.prototype.slice.call( e.target.parentElement.children ).indexOf( e.target );
// if we click on accordion nav link
} else {
activeTabIndex = Array.prototype.slice.call( e.target.parentElement.parentElement.children ).indexOf( e.target.parentElement ) - 1;
}
let tabsContent = tabsElem.getElementsByClassName( 'tabs__content'),
mainNavLinks = tabsElem.querySelectorAll( '.tabs__nav > .tabs__nav_link'),
accordionNavLinks = tabsElem.querySelectorAll( '.tabs__content > .tabs__nav_link');
// toggle accordion panel
if( ( tabsStyle == 'accordion' || tabsElem.classList.contains( 'is__responsive') ) && e.target.classList.contains( 'is__active') ) {
tabsContent[ activeTabIndex ].classList.remove( 'is__active');
mainNavLinks[ activeTabIndex ].classList.remove( 'is__active');
accordionNavLinks[ activeTabIndex ].classList.remove( 'is__active');
return;
}
// remove active class for inactive tabs
for( let i = 0; i < tabsContent.length; i++ ) {
tabsContent[ i ].classList.remove( 'is__active');
}
// add active class for a current (active) tab
tabsContent[ activeTabIndex ].classList.add( 'is__active');
// add active classes and remove inactive for main nav links
mainNavLinks.forEach( ( el ) => {
el.classList.remove( 'is__active');
});
mainNavLinks[ activeTabIndex ].classList.add( 'is__active');
// add active classes and remove inactive for accordion nav links
accordionNavLinks.forEach( ( el ) => {
el.classList.remove( 'is__active');
});
accordionNavLinks[ activeTabIndex ].classList.add( 'is__active');
}
});
});
}
// responsive: tabs to accordion
handleResponsive() {
let tabs = this.elems,
responsiveClassName = 'is__responsive',
tabsStyle = this.options.type;
window.addEventListener( 'resize', () => {
// walk on all tabs on the page
tabs.forEach( ( el, i ) => {
let tabsElem = el,
tabsContent = tabsElem.getElementsByClassName( 'tabs__content'),
mainNavLinks = tabsElem.querySelectorAll( '.tabs__nav > .tabs__nav_link'),
accordionNavLinks = tabsElem.querySelectorAll( '.tabs__content > .tabs__nav_link');
this.skipIfInitialized( tabsElem );
if( window.innerWidth > Number( this.options.responsiveBreak ) ) {
tabsElem.classList.remove( responsiveClassName );
if( tabsStyle != 'accordion' ) {
// set first active tab if all of tabs were closed in accordion mode
let openTabs = tabsElem.querySelectorAll( '.tabs__nav_link.is__active');
if( openTabs.length == 0 ) {
tabsContent[0].classList.add('is__active');
mainNavLinks[0].classList.add('is__active');
accordionNavLinks[0].classList.add('is__active');
}
}
} else {
tabsElem.classList.add( responsiveClassName );
}
});
});
// manually fire resize event
window.dispatchEvent( new Event( 'resize' ));
}
}
您的 vanilla-tabs
模块实际上并未导出 class。为了能够将其作为默认值导入,就像您在主文件中所做的那样,将模块的第一行更改为:
export default class VanillaTabs {
(Webpack 在这里过多地掩盖了错误消息。我从你的代码中直接使用未编译的 ES6 模块和 Node.js 得到的错误更清楚:)
SyntaxError: The requested module './vanilla-tabs.mjs' does not provide an export named 'default'
我正在尝试导入 ES6 模块并遇到错误。模块是一个纯 Javascript 选项卡,可以变成响应式手风琴。您应该在下面找到 link 到 Javascript、My main-js 和模块的 Javascript。
https://github.com/ADTC/vanilla-tabs
我的 main.js 文件:
import VanillaTabs from './vanilla-tabs';
document.addEventListener('DOMContentLoaded', () => {
new VanillaTabs({
'selector': '.tabs', // default is ".tabs"
'type': 'horizontal', // can be horizontal / vertical / accordion
'responsiveBreak': 840, // tabs become accordion on this device width
'activeIndex' : 0 // active tab index (starts from 0 ). Can be -1 for accordions.
});
});
模块的外观如下:
class VanillaTabs {
constructor( opts ) {
const DEFAULTS = {
'selector': '.tabs',
'type': 'horizontal',
'responsiveBreak': 840,
'activeIndex' : 0
}
this.options = Object.assign( DEFAULTS, opts );
this.elems = document.querySelectorAll( this.options.selector );
// skip building tabs if they were already initialized
this.skipIfInitialized = ( tabsElem ) => {
// skip element if already initialized
if( tabsElem.classList.contains('tabs__initialized') ) {
return;
}
}
this.buildUI();
this.handleNavigation();
this.handleResponsive();
}
// initialize the UI Elements
buildUI(){
let tabs = this.elems;
// walk on all tabs on the page
tabs.forEach( ( el, i ) => {
let tabsElem = el,
childNodes = tabsElem.childNodes,
tabsTitles = [],
tabsStyle = this.options.type;
this.skipIfInitialized( tabsElem );
tabsElem.classList.add( 'style__' + this.options.type );
tabsElem.classList.add( 'tabs__initialized' );
for( let i = 0; i < childNodes.length; i++ ) {
let tabItem = childNodes[i];
if ( tabItem.nodeType != Node.TEXT_NODE ) {
// add tab__content CSS class
tabItem.classList.add( 'tabs__content');
// grab tab title from data attribute
let tabTitle = tabItem.dataset.title ? tabItem.dataset.title : '';
tabsTitles.push( tabTitle );
// wrap tab content
let tabContent = tabItem.innerHTML;
tabItem.innerHTML = '<div class="tabs__content_wrapper">' + tabContent + '</div>';
// insert nav link for accordion navigation
tabItem.insertAdjacentHTML( 'afterbegin', '<a class="tabs__nav_link">' + tabTitle + '</a>');
}
}
// create horizontal / vertical tabs navigation elements
let navElemsHTML = '';
tabsTitles.forEach( ( title ) => {
navElemsHTML = navElemsHTML + '<a class="tabs__nav_link">' + title + '</a>';
});
tabsElem.insertAdjacentHTML( 'afterbegin', '<li class="tabs__nav">' + navElemsHTML + '</li>');
// set initial active tab
let activeTabIndex = Number( this.options.activeIndex );
// validate active tab index. but, you can specify -1 for accordion tabs to make all of them closed by defaults
if( tabsStyle != 'accordion' && activeTabIndex != -1 ) {
if( activeTabIndex > (tabsTitles.length - 1) ) {
console.warn( 'VANILLA TABS: Active tab number from settings is bigger than tabs count. Please remember, that index starts from Zero! To avoid crashes, activeIndex option was reverted to 0.');
activeTabIndex = 0;
}
tabsElem.querySelectorAll( '.tabs__nav > .tabs__nav_link')[ activeTabIndex ].classList.add( 'is__active' );
tabsElem.querySelectorAll( '.tabs__content')[ activeTabIndex ].classList.add( 'is__active' );
tabsElem.querySelectorAll( '.tabs__content > .tabs__nav_link')[ activeTabIndex ].classList.add( 'is__active' );
}
});
}
// navigation: assign click events
handleNavigation() {
let tabs = this.elems,
tabsStyle = this.options.type;
// walk on all tabs on the page
tabs.forEach( ( el, i ) => {
let tabsElem = el;
this.skipIfInitialized( tabsElem );
tabsElem.addEventListener( 'click', function( e ){
if( e.target && e.target.classList.contains( 'tabs__nav_link') ) {
e.preventDefault();
let activeTabIndex;
// if we click on main navigation link
if( e.target.parentElement.classList == 'tabs__nav' ) {
activeTabIndex = Array.prototype.slice.call( e.target.parentElement.children ).indexOf( e.target );
// if we click on accordion nav link
} else {
activeTabIndex = Array.prototype.slice.call( e.target.parentElement.parentElement.children ).indexOf( e.target.parentElement ) - 1;
}
let tabsContent = tabsElem.getElementsByClassName( 'tabs__content'),
mainNavLinks = tabsElem.querySelectorAll( '.tabs__nav > .tabs__nav_link'),
accordionNavLinks = tabsElem.querySelectorAll( '.tabs__content > .tabs__nav_link');
// toggle accordion panel
if( ( tabsStyle == 'accordion' || tabsElem.classList.contains( 'is__responsive') ) && e.target.classList.contains( 'is__active') ) {
tabsContent[ activeTabIndex ].classList.remove( 'is__active');
mainNavLinks[ activeTabIndex ].classList.remove( 'is__active');
accordionNavLinks[ activeTabIndex ].classList.remove( 'is__active');
return;
}
// remove active class for inactive tabs
for( let i = 0; i < tabsContent.length; i++ ) {
tabsContent[ i ].classList.remove( 'is__active');
}
// add active class for a current (active) tab
tabsContent[ activeTabIndex ].classList.add( 'is__active');
// add active classes and remove inactive for main nav links
mainNavLinks.forEach( ( el ) => {
el.classList.remove( 'is__active');
});
mainNavLinks[ activeTabIndex ].classList.add( 'is__active');
// add active classes and remove inactive for accordion nav links
accordionNavLinks.forEach( ( el ) => {
el.classList.remove( 'is__active');
});
accordionNavLinks[ activeTabIndex ].classList.add( 'is__active');
}
});
});
}
// responsive: tabs to accordion
handleResponsive() {
let tabs = this.elems,
responsiveClassName = 'is__responsive',
tabsStyle = this.options.type;
window.addEventListener( 'resize', () => {
// walk on all tabs on the page
tabs.forEach( ( el, i ) => {
let tabsElem = el,
tabsContent = tabsElem.getElementsByClassName( 'tabs__content'),
mainNavLinks = tabsElem.querySelectorAll( '.tabs__nav > .tabs__nav_link'),
accordionNavLinks = tabsElem.querySelectorAll( '.tabs__content > .tabs__nav_link');
this.skipIfInitialized( tabsElem );
if( window.innerWidth > Number( this.options.responsiveBreak ) ) {
tabsElem.classList.remove( responsiveClassName );
if( tabsStyle != 'accordion' ) {
// set first active tab if all of tabs were closed in accordion mode
let openTabs = tabsElem.querySelectorAll( '.tabs__nav_link.is__active');
if( openTabs.length == 0 ) {
tabsContent[0].classList.add('is__active');
mainNavLinks[0].classList.add('is__active');
accordionNavLinks[0].classList.add('is__active');
}
}
} else {
tabsElem.classList.add( responsiveClassName );
}
});
});
// manually fire resize event
window.dispatchEvent( new Event( 'resize' ));
}
}
您的 vanilla-tabs
模块实际上并未导出 class。为了能够将其作为默认值导入,就像您在主文件中所做的那样,将模块的第一行更改为:
export default class VanillaTabs {
(Webpack 在这里过多地掩盖了错误消息。我从你的代码中直接使用未编译的 ES6 模块和 Node.js 得到的错误更清楚:)
SyntaxError: The requested module './vanilla-tabs.mjs' does not provide an export named 'default'