vue版本:2.5.21,element版本:2.15.6
tab组件使用方式:
源码实现思路:通过this.$slots.default获取插槽列表,根据插槽列表生成tab-nav,给绑定tab-nav绑定事件,设置当前的currentName。tab-pane使用name与currentName作对比是否显示。
获取插槽列表
<script>
calcPaneInstances(isForceUpdate = false) {
if (this.$slots.default) {
const paneSlots = this.$slots.default.filter(vnode => vnode.tag &&
vnode.componentOptions && vnode.componentOptions.Ctor.options.name === 'ElTabPane');
// update indeed
const panes = paneSlots.map(({ componentInstance }) => componentInstance);
const panesChanged = !(panes.length === this.panes.length && panes.every((pane, index) => pane === this.panes[index]));
if (isForceUpdate || panesChanged) {
this.panes = panes;
}
} else if (this.panes.length !== 0) {
this.panes = [];
}
},
</script>
根据插槽列表生成tab-nav
<script>
const tabs = this._l(panes, (pane, index) => {
let tabName = pane.name || pane.index || index;
const closable = pane.isClosable || editable;
pane.index = `${index}`;
const btnClose = closable
? <span class="el-icon-close" on-click={(ev) => { onTabRemove(pane, ev); }}></span>
: null;
const tabLabelContent = pane.$slots.label || pane.label;
const tabindex = pane.active ? 0 : -1;
return (
<div
class={{
'el-tabs__item': true,
[`is-${ this.rootTabs.tabPosition }`]: true,
'is-active': pane.active,
'is-disabled': pane.disabled,
'is-closable': closable,
'is-focus': this.isFocus
}}
id={`tab-${tabName}`}
key={`tab-${tabName}`}
aria-controls={`pane-${tabName}`}
role="tab"
aria-selected={ pane.active }
ref="tabs"
tabindex={tabindex}
refInFor
on-focus={ ()=> { setFocus(); }}
on-blur ={ ()=> { removeFocus(); }}
on-click={(ev) => { removeFocus(); onTabClick(pane, tabName, ev); }}
on-keydown={(ev) => { if (closable && (ev.keyCode === 46 || ev.keyCode === 8)) { onTabRemove(pane, ev);} }}
>
{tabLabelContent}
{btnClose}
</div>
);
});
</script>
设置当前的currentName
<script>
handleTabClick(tab, tabName, event) {
if (tab.disabled) return;
this.setCurrentName(tabName);
this.$emit('tab-click', tab, event);
},
</script>
name与currentName作对比是否显示
<div
class="el-tab-pane"
v-if="(!lazy || loaded) || active"
v-show="active"
role="tabpanel"
:aria-hidden="!active"
:id="`pane-${paneName}`"
:aria-labelledby="`tab-${paneName}`"
>
<slot></slot>
</div>
<script>
computed: {
active() {
const active = this.$parent.currentName === (this.name || this.index);
if (active) {
this.loaded = true;
}
return active;
},
},
</script>