子组件``
<div id="box" :style="boxStyle">
<div v-for="item in modelValue" :key="item.id">
<slot :msg="item"></slot>
</div>
</div>
</template>
<script setup lang="ts">
import Sortable from "sortablejs";
import {
defineEmits,
defineProps,
nextTick,
onMounted,
defineExpose,
withDefaults,
computed,
} from "vue";
//内部interface type类型定义
interface IModelValue {
id: string;
index: number;
name: string;
}
type ILayout = "x" | "y" | "X" | "Y";
interface IProps {
modelValue: IModelValue[];
layout?: ILayout;
}
// props 定义:对外选项
const props = withDefaults(defineProps<IProps>(), {
layout: "x",
});
// emit 定义:自定义事件
const emits = defineEmits(["update:modelValue"]);
//computed定义:计算属性
const boxStyle = computed(() => {
if (props.layout == "y" || props.layout == "Y") {
return "flex-direction:column;height:100%;width:fit-content";
} else {
return "flex-direction:row;width:100%;height:fit-content";
}
});
//生命周期函数
onMounted(() => {
initDragAble();
});
//自定义函数
//初始化拖拽元素
function initDragAble() {
nextTick(() => {
const el = document.querySelector("#box");
const sortable = Sortable.create(el as HTMLElement, {
// 在拖拽过程中会有动画产生
animation: 150,
easing: "cubic-bezier(1, 0, 0, 1)",
// 是否可以进行拖拽排序,为 true 时,不能进行排序,函数不会被触发,为 false 时, 可以进行排序
disabled: false,
// 为拖拽时产生的副本添加一个class
ghostClass: "newclass",
// 为选中的元素添加一个class
chosenClass: "addclass",
// 禁用html5原有的样式
forceFallback: true,
// 排序发生变化时调用的函数
onUpdate: function (event) {
const newVal = props.modelValue;
const oldItem = newVal[event.oldIndex as number];
newVal[event.oldIndex as number] = newVal[event.newIndex as number];
newVal[event.newIndex as number] = oldItem;
//将数据传给父组件
emits("update:modelValue", newVal);
},
});
});
}
defineExpose({
boxStyle,
});
</script>
<style scoped>
#box {
display: flex;
/* width: 100%; */
/* height: 100%; */
overflow: scroll;
overflow-y: none;
}
</style>
父组件
```javascript
在这里插入代码片
<template>
<div class="container">
<TableComponent v-model="data.tabList" layout="x">
<template v-slot="scope">
<div class="items">{{ scope.msg.name }}</div>
</template>
</TableComponent>
</div>
</template>
<script setup lang="ts">
import TableComponent from "@/components/TabComponent.vue";
import { reactive, watch } from "vue";
interface ITabItem {
id: string;
index: number;
name: string;
}
interface IData {
tabList: ITabItem[];
}
const data = reactive<IData>({
tabList: [
{
id: "ie",
index: 4,
name: "e",
},
{
id: "id",
index: 3,
name: "d",
},
{
id: "ic",
index: 2,
name: "c",
},
{
id: "ib",
index: 1,
name: "b",
},
{
id: "ia",
index: 0,
name: "a",
},
],
});
watch(
() => data.tabList,
(val) => {
console.log("更新了", val);
},
{
deep: true,
}
);
defineExpose({
data,
});
</script>
<style scoped>
.container {
width: 300px;
height: 300px;
background-color: green;
}
.items {
width: 100px;
height: 100px;
background-color: red;
border: 1px solid black;
}
</style>
注意点:引入第三方库的时候需要自定义生命类型 可以安装类型声明文件, npm i @types/第三方库包名 --save-dev