vue3
<template>
<div :model="active" class="ui-tabs">
<template v-for="item in data">
<div v-if="'item.visible'" :key="item.name" class="ui-tab" :class="active == item.name ? 'active' : ''" :name="item.name" :label="item.label" :draggable="item.draggable" @dragstart="handleDragStart($event, item)" @dragenter="handleDragEnter($event, item)" @dragover.prevent="handleDragOver($event, item)" @dragend="handleDragEnd($event, item)" @click="handleClick($event, item)">
{{ item.label }}
</div>
</template>
</div>
</template>
<script setup>
import { ref, watch } from 'vue';
const props = defineProps({
model: {
type: String,
},
data: {
type: Array,
},
});
const emit = defineEmits(['update:model', 'update:data', 'tabClick']);
watch(
() => props.data,
(val) => {
if (!val) return;
if (!this.active) this.active = val[0].name;
},
{ immediate: true, deep: true },
);
const active = ref('');
const drag = ref(null);
function handleDragStart(e, item) {
drag.value = item.name;
}
function handleDragEnter(e, item) {
e.dataTransfer.effectAllowed = 'move';
if (item.name === drag.value) return;
const arr = [...props.data];
const x = arr.findIndex((i) => i.name === item.name);
const y = arr.findIndex((i) => i.name === drag.value);
arr.splice(y, 1, ...arr.splice(x, 1, arr[y]));
emit('update:data', arr);
}
function handleDragOver(e, item) {
e.dataTransfer.dropEffect = 'move';
}
function handleDragEnd(e, item) {
drag.value = null;
}
function handleClick(e, item) {
active.value = item.name;
emit('update:model', item.name);
emit('tabClick', item.name);
}
</script>
<style scoped>
.ui-tabs {
display: flex;
align-items: center;
user-select: none;
}
.ui-tab {
margin-left: 2px;
padding: 4px 8px;
color: #eee;
font-size: 12px;
border-radius: 4px 4px 0 0;
white-space: no-wrap;
overflow: hidden;
text-overflow: ellipsis;
text-align: center;
background-color: #333;
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.4);
cursor: pointer;
}
.ui-tab.active {
color: #fff;
background: #555;
}
</style>
vue2
<script>
export default{
props:{
model: {
type: String,
},
data: {
type: Array,
},
},
watch:{
data:{
handler(val){
if (!val) return;
if (!this.active) this.active = val[0].name;
},
immediate: true,
deep: true
}
},
data(){
return{
active:'',
drag:null
}
},
methods:{
handleDragStart(e, item) {
this.drag = item.name;
},
handleDragEnter(e, item) {
e.dataTransfer.effectAllowed = 'move';
if (item.name === drag.value) return;
const arr = [...props.data];
const x = arr.findIndex((i) => i.name === item.name);
const y = arr.findIndex((i) => i.name === drag.value);
arr.splice(y, 1, ...arr.splice(x, 1, arr[y]));
this.$emit('update:data', arr);
},
handleDragOver(e, item) {
e.dataTransfer.dropEffect = 'move';
},
handleDragEnd(e, item) {
this.drag = null;
},
handleClick(e, item) {
this.active = item.name;
this.$emit('update:model', item.name);
this.$emit('tabClick', item.name);
}
}
}
</script>