diff --git a/README.md b/README.md index 6416d38..d1890a0 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ export default { | tabs | tabs configuration. Details are mentioned below. | Array | [] | | value / v-model | binding value | String | - | | props | configuration options, Details are mentioned below. | +| insert-to-after | Insert to tag's after | Boolean | false | ## Tabs Attributes | Attributes | Description | Type | Default | @@ -66,5 +67,19 @@ export default { | label | specify which key of tab object is used as the tab's label | String | 'label' | | key | specify which key of tab object is used as the tab's key | String | 'key' | +## Methods +| Method | Description | Parameters | +| - | - | - | +| addTab | add tab | (tab1, [, ...tab, ...tabN]) | +| removeTab | remove tab | (tabKey | index) | +| getTabs | get tabs | - | + +## Events +| Event Name | Description | Parameters | +| - | - | - | +| swap | swap tab | (tab, targetTab) | +| remove | remove tab | (tab, index) | +| contextmenu | contextmenu event | (event, tab, index) | + ## License MIT diff --git a/examples/App.vue b/examples/App.vue index 0e49e44..fcc0ab7 100644 --- a/examples/App.vue +++ b/examples/App.vue @@ -3,11 +3,24 @@

vue-tabs-chrome

A Vue component for Chrome-like tabs.

Default

+

+ code +

Theme Dark

+

+ code +

Theme Custom

+

+ code +

+

Insert to tag's after

+ +

Save to Localstorage

+ @@ -15,10 +28,12 @@ import Example from './example/example' import ExampleDark from './example/example-dark' import ExampleCustom from './example/example-custom' +import ExampleInsert from './example/example-insert' +import ExampleSave from './example/example-save' export default { name: 'app', - components: { Example, ExampleDark, ExampleCustom } + components: { Example, ExampleDark, ExampleCustom, ExampleInsert, ExampleSave } } diff --git a/examples/example/example-insert.vue b/examples/example/example-insert.vue new file mode 100644 index 0000000..4ecc9e0 --- /dev/null +++ b/examples/example/example-insert.vue @@ -0,0 +1,43 @@ + + + diff --git a/examples/example/example-save.vue b/examples/example/example-save.vue new file mode 100644 index 0000000..6e7e867 --- /dev/null +++ b/examples/example/example-save.vue @@ -0,0 +1,72 @@ + + + diff --git a/examples/example/example.vue b/examples/example/example.vue index 38fe3b2..422daa2 100644 --- a/examples/example/example.vue +++ b/examples/example/example.vue @@ -3,6 +3,7 @@
+
@@ -37,6 +38,9 @@ export default { ] this.$refs.tab.addTab(...newTabs) this.tab = item + }, + removeTab () { + this.$refs.tab.removeTab(this.tab) } } } diff --git a/packages/vue-tabs-chrome.vue b/packages/vue-tabs-chrome.vue index 2bafba5..4f58b43 100644 --- a/packages/vue-tabs-chrome.vue +++ b/packages/vue-tabs-chrome.vue @@ -11,6 +11,7 @@ :class="[{ active: tab[tabKey] === value }, `tab-${tab[tabKey]}`]" :key="tab[tabKey]" :style="{ width: tabWidth + 'px' }" + @contextmenu="e => handleMenu(e, tab, i)" ) .tabs-background .tabs-background-content @@ -113,6 +114,10 @@ export default { type: Number, default: 7 }, + insertToAfter: { + type: Boolean, + default: false + }, theme: { type: String, default: '' @@ -174,12 +179,37 @@ export default { tab._instance.on('dragEnd', (e, pointer) => this.handleDraEnd(e, tab, i)) }, addTab (...tabs) { - this.tabs.push(...tabs) + let { insertToAfter, value, tabKey } = this + if (insertToAfter) { + let i = this.tabs.findIndex(tab => tab[tabKey] === value) + this.tabs.splice(i + 1, 0, ...tabs) + } else { + this.tabs.push(...tabs) + } this.$nextTick(() => { this.setup() this.doLayout() }) }, + removeTab (key) { + let { tabKey, tabs } = this + let index = -1 + let targetTab = null + if (typeof tab === 'number') { + index = key + targetTab = this.tabs[index] + } else { + tabs.forEach((tab, i) => { + if (tab[tabKey] === key) { + index = i + targetTab = tab + } + }) + } + if (index >= 0 && targetTab) { + this.handleDelete(targetTab, index) + } + }, doLayout () { this.calcTabWidth() let { tabWidth, tabs, gap } = this @@ -193,11 +223,20 @@ export default { handleDelete (tab, i) { let { tabKey, tabs, value } = this let index = tabs.findIndex(item => item[tabKey] === value) + let after, before if (i === index) { - let before = tabs[i - 1] - this.$emit('input', before ? before[tabKey] : null) + after = tabs[i + 1] + before = tabs[i - 1] + } + if (after) { + this.$emit('input', after[tabKey]) + } else if (before) { + this.$emit('input', before[tabKey]) + } else if (tabs.length <= 1) { + this.$emit('input', null) } tabs.splice(i, 1) + this.$emit('remove', tab, i) this.$nextTick(() => { this.doLayout() }) @@ -230,6 +269,9 @@ export default { _instance.element.classList.remove('move') }, 200) }, + handleMenu (e, tab, index) { + this.$emit('contextmenu', e, tab, index) + }, swapTab (tab, targetTab) { let { tabKey, tabs } = this let index, targetIndex @@ -257,7 +299,18 @@ export default { }, 50) setTimeout(() => { _instance.element.classList.remove('move') + this.$emit('swap', tab, targetTab) }, 200) + }, + getTabs () { + return this.tabs.map(tab => { + let item = { + ...tab + } + delete item._instance + delete item._x + return item + }) } } } @@ -406,7 +459,7 @@ export default { } .tabs-background-before, .tabs-background-after { - bottom: 0; + bottom: -1px; position: absolute; fill: transparent; transition: background @speed;