Home
avatar

.Wang

属性排序需求

属性排序需求 demo

国庆结束了第一波需求它来了,需求大致是这样的:

  1. 是一个拖拽排序的功能
  2. 同级子集是可以拖拽排序的, 现在是同一目标内,例如:A 容器不能退拽到 B 容器,只能在 A 容器内排序或者 B 容器内排序

如下图:

属性排序需求.png

注:规格配置不能退拽到行业属性容器,只能在当前容器内排序,行业属性也是如此。

如何做

我的想法就很简单,将其封装成一个小组件,同时支持标题,描述,排序功能。

<!-- 父组件 -->

<script setup lang="ts">
import { ref } from "vue";
import attrDragItem from "./attrDragItem.vue";
const test = ref(
	Array.from({ length: 7 }, (_, i) => ({
		id: i + 1,
		name: `C00${i + 1}${
			["白色", "黑色", "红色", "绿色", "蓝色", "黄色", "紫色"][i]
		}`,
		elements: [],
	}))
);
const test2 = ref([
	{
		id: 1,
		name: "电机型号",
		elements: [
			{
				id: 1,
				name: "M2/V2",
			},
			{
				id: 2,
				name: "米家",
			},
		],
	},
]);
</script>

<template>
	<h3>颜色配置</h3>
	<attrDragItem
		:data="test"
		:is-tree="false"
		@update:data="newData => (test = newData)"
	/>

	<h3>规格配置</h3>
	<attrDragItem
		:data="test2"
		:is-tree="true"
		@update:data="newData => (test2 = newData)"
	/>
	<!-- .... 其他属性配置 -->
</template>

attrDragItem就是封装的这个组件,它的 props 是:

  • data: 数据,数组格式
  • is-tree: 是否是树状结构,默认 false
  • @update:data: 数据更新事件,返回新的数组
<!-- 子组件 attrDragItem.vue -->

<script setup lang="ts">
defineOptions({
	name: "AttrDragItem",
});
import VabDraggable from "vuedraggable";

const props = defineProps<{
	// 数据
	data: TAny[];
	// 是否是树结构
	isTree: boolean;
}>();

const emit = defineEmits<{
	"update:data": [value: any[]];
}>();

const dataList = computed({
	get: () => props.data,
	set: value => emit("update:data", value),
});

const dragOptions = computed(() => {
	return {
		animation: 600,
		disabled: false,
		ghostClass: "ghost",
	};
});

// 处理子集元素的更新
const handleElementsUpdate = (item: TAny, newElements: TAny[]) => {
	const index = dataList.value.findIndex(i => i.id === item.id);
	if (index !== -1) {
		const newData = [...dataList.value];
		newData[index] = { ...item, elements: newElements };
		emit("update:data", newData);
	}
};
</script>

<template>
	<vab-draggable
		v-model="dataList"
		v-bind="dragOptions"
		item-key="id"
		style="display: flex; flex-wrap: wrap; justify-content: flex-start"
		:style="{ flexDirection: props.isTree ? 'column' : 'row' }"
	>
		<template #item="{ element: item }">
			<div>
				<div :class="['drag-item-container', props.isTree ? 'mb' : '']">
					<vab-icon v-if="props.isTree" icon="draggable" />
					<div :class="[props.isTree ? 'tree-item' : 'drag-item']">
						{{ item.name }}
					</div>
				</div>
				<template v-if="props.isTree">
					<!-- 递归调用子组件 -->
					<attrDragItem
						:data="item.elements"
						:is-tree="false"
						@update:data="
							newElements => handleElementsUpdate(item, newElements)
						"
					/>
				</template>
			</div>
		</template>
	</vab-draggable>
</template>

<style lang="scss" scoped>
.drag-item-container {
	display: flex;
	align-items: center;
	color: #333;

	&.mb {
		margin-bottom: 12px;
	}
	.drag-item {
		padding: 6px 12px;
		background-color: rgba(238, 238, 238, 1);
		border-radius: 50px;
		margin-bottom: 8px;
		margin-right: 8px;
		cursor: move;
	}
}
</style>
工作总结

喜欢这篇文章嘛,觉得文章不错的话,奖励奖励我!

支付宝打赏支付宝微信打赏 微信