Vue2开发:使用vuedraggable实现菜单栏拖拽
一阶:简单拖拽+点击效果
<template><div><div><draggable v-model="mainMenu" @start="dragStart" @end="dragEnd" class="menu-list"><div v-for="(item, index) in mainMenu" :key="item.id" class="menu-item"><div class="main-item" @click="toggleMainMenu(item)" :class="{ active: activeMainMenuId === item.id }"><span>{{ item.name }}</span><button @click="toggleSubMenu(item)" class="openBtn">展开</button></div><div v-if="item.isOpen" class="sub-menu"><divv-for="(subItem, subIndex) in item.subMenu":key="subItem.id"class="sub-item":class="{ active: activeSubMenuId === subItem.id }"@click="toggleSubMenuActive(subItem)">{{ subItem.name }}</div></div></div></draggable></div></div></template><script>import draggable from 'vuedraggable'export default {components: {draggable},data() {return {activeMainMenuId: null, // 当前选中的大目录的IDactiveSubMenuId: null, // 当前选中的小目录的IDmainMenu: [{id: 1,name: '大目录1',isActive: false,isOpen: false,subMenu: [{ id: 1.1, name: '小目录1.1', isActive: false },{ id: 1.2, name: '小目录1.2', isActive: false }]},{id: 2,name: '大目录2',isActive: false,isOpen: false,subMenu: [{ id: 2.1, name: '小目录2.1', isActive: false },{ id: 2.2, name: '小目录2.2', isActive: false }]},{id: 3,name: '大目录3',isActive: false,isOpen: false,subMenu: [{ id: 3.1, name: '小目录3.1', isActive: false },{ id: 3.2, name: '小目录3.2', isActive: false }]}]}},methods: {//点击大目录(传入被点击的目录信息)toggleMainMenu(item) {this.activeMainMenuId =item.id //只存在一个大目录有选中状态this.activeSubMenuId = null //取消小目录的选中状态},//点击大目录的展开按钮toggleSubMenu(item) {item.isOpen = !item.isOpen // 是否展开},//点击小目录(传入被点击的目录信息)toggleSubMenuActive(subItem) {this.activeSubMenuId = subItem.id //只存在一个小目录有选中状态this.activeMainMenuId = null //取消大目录的选中状态},dragStart() {console.log('拖拽开始')},dragEnd() {console.log('拖拽结束')}}}</script><style scoped>.menu-list {list-style: none;padding: 0;margin: 0;}.menu-item {border: 1px solid #ccc;padding: 10px;margin: 5px 0;border-radius: 5px;background-color: #fff;cursor: pointer;}.menu-item.active {background-color: blue;color: white;}.main-item.active {background-color: blue;color: white;border-radius: 4px;padding: 4px;}.sub-menu {padding-left: 20px;}.sub-item {padding: 5px;margin: 5px 0;border: 1px solid #ccc;border-radius: 5px;background-color: #f0f0f0;}.sub-item.active {background-color: #4c8bf5;color: white;}.main-item {display: flex;justify-content: space-between;align-items: center;}.openBtn{background-color: white;color: black;border-radius: 4px;}</style>
点击:
拖拽:
二阶:简单拖拽+保存编辑新增+点击效果
<template><div><div><!-- 添加新大目录按钮 --><button @click="showAddMainMenu" class="openBtn">新增</button><!-- 新增大目录的输入框和保存/取消按钮 --><div v-if="isAddingMainMenu" class="add-main-menu"><input v-model="newMainMenuName" type="text" placeholder="请输入名称" /><button @click="saveMainMenu" class="openBtn">保存</button><button @click="cancelAddMainMenu" class="openBtn">取消</button></div><draggable v-model="mainMenu" @start="dragStart" @end="dragEnd" class="menu-list" :disabled="isEditing"><div v-for="(item, index) in mainMenu" :key="item.id" class="menu-item"><div class="main-item" @click="toggleMainMenu(item)" :class="{ active: activeMainMenuId === item.id }"><span>{{ item.name }}</span><button @click="toggleSubMenu(item)" class="openBtn">展开</button></div><div v-if="item.isOpen" class="sub-menu"><divv-for="(subItem, subIndex) in item.subMenu":key="subItem.id"class="sub-item":class="{ active: activeSubMenuId === subItem.id }"@click="toggleSubMenuActive(subItem)"><div v-if="subItem.isEditing" class="editzoom"><input v-model="subItem.name" type="text" style="color: black" /><div class="button-group"><button @click="saveEdit(subItem)" class="openBtn">保存</button></div></div><div v-else class="editzoom">{{ subItem.name }}<div class="button-group"><button @click="editSubMenu(subItem)" class="openBtn">编辑</button><button @click="deleteSubMenu(subItem)" class="openBtn">删除</button></div></div></div><!-- Add a button to add a new sub-item --><div class="add-submenu"><button @click="addSubMenu(item)" class="openBtn">新增小目录</button></div></div></div></draggable></div></div>
</template><script>
import draggable from 'vuedraggable'export default {components: {draggable},data() {return {activeMainMenuId: null, // 当前选中的大目录的IDactiveSubMenuId: null, // 当前选中的小目录的IDmainMenu: [{id: 1,name: '大目录1',isActive: false,isOpen: false,subMenu: [{ id: 1.1, name: '小目录1.1', isActive: false, isEditing: false },{ id: 1.2, name: '小目录1.2', isActive: false, isEditing: false }]},{id: 2,name: '大目录2',isActive: false,isOpen: false,subMenu: [{ id: 2.1, name: '小目录2.1', isActive: false, isEditing: false },{ id: 2.2, name: '小目录2.2', isActive: false, isEditing: false }]},{id: 3,name: '大目录3',isActive: false,isOpen: false,subMenu: [{ id: 3.1, name: '小目录3.1', isActive: false, isEditing: false },{ id: 3.2, name: '小目录3.2', isActive: false, isEditing: false }]}],isAddingMainMenu: false, // 控制是否显示新增大目录的输入框newMainMenuName: '' // 新增大目录的名称}},methods: {//点击大目录(传入被点击的目录信息)toggleMainMenu(item) {this.activeMainMenuId = item.id //只存在一个大目录有选中状态this.activeSubMenuId = null //取消小目录的选中状态},//点击大目录的展开按钮toggleSubMenu(item) {item.isOpen = !item.isOpen // 是否展开},//点击小目录(传入被点击的目录信息)toggleSubMenuActive(subItem) {this.activeSubMenuId = subItem.id //只存在一个小目录有选中状态this.activeMainMenuId = null //取消大目录的选中状态},//编辑小目录editSubMenu(subItem) {subItem.isEditing = true // 进入编辑状态},//保存编辑saveEdit(subItem) {subItem.isEditing = false // 退出编辑状态// 保存编辑内容,这里可以做更多操作,比如发送请求到服务器},//删除小目录deleteSubMenu(subItem) {const index = this.mainMenu.findIndex((menu) => menu.subMenu.includes(subItem))if (index !== -1) {const subMenuIndex = this.mainMenu[index].subMenu.indexOf(subItem)this.mainMenu[index].subMenu.splice(subMenuIndex, 1) // 从大目录的子目录中删除}},// 新增小目录addSubMenu(item) {const newId = (Math.random() * 1000).toFixed(1) // 简单的生成新的IDconst newSubItem = { id: newId, name: '', isEditing: true } // 默认进入编辑状态item.subMenu.push(newSubItem) // 将新小目录添加到大目录的子目录列表},dragStart() {console.log('拖拽开始')},dragEnd() {console.log('拖拽结束')},// 控制新增大目录showAddMainMenu() {this.isAddingMainMenu = true},saveMainMenu() {if (this.newMainMenuName.trim() !== '') {const newId = (Math.random() * 1000).toFixed(1)this.mainMenu.unshift({id: newId,name: this.newMainMenuName,isOpen: false,subMenu: []})this.newMainMenuName = ''this.isAddingMainMenu = false} else {alert('请输入名称!')}},cancelAddMainMenu() {this.isAddingMainMenu = falsethis.newMainMenuName = ''}},computed: {isEditing() {//存在编辑状态时,不要拖拽功能return this.mainMenu.some((menu) => menu.subMenu.some((subItem) => subItem.isEditing))}}
}
</script><style scoped>
.menu-list {list-style: none;padding: 0;margin: 0;
}.menu-item {border: 1px solid #ccc;padding: 10px;margin: 5px 0;border-radius: 5px;background-color: #fff;cursor: pointer;
}.menu-item.active {background-color: blue;color: white;
}
.main-item.active {background-color: blue;color: white;border-radius: 4px;padding: 4px;
}.sub-menu {padding-left: 20px;
}.sub-item {padding: 5px;margin: 5px 0;border: 1px solid #ccc;border-radius: 5px;background-color: #f0f0f0;
}.sub-item.active {background-color: #4c8bf5;color: white;
}.main-item {display: flex;justify-content: space-between;align-items: center;
}button {margin-left: 5px;
}input[type='text'] {padding: 5px;margin-right: 10px;width: 150px;
}.button-group {display: flex;justify-content: flex-end;margin-top: 5px;margin-left: auto;
}.button-group button {margin-left: 10px;
}.openBtn {background-color: white;color: black;border-radius: 4px;margin-top: 4px;
}.editzoom {display: flex;align-items: center;justify-content: flex-start;
}.add-submenu {margin-top: 10px;margin: 0 auto;width: 100px;
}.add-submenu button {padding: 5px 10px;background-color: #4283e4;color: white;border: none;border-radius: 5px;
}.add-main-menu {display: flex;margin: 10px 0;align-items: center;
}.add-main-menu input {margin-right: 10px;
}.add-main-menu button {margin-left: 10px;
}
</style>
点击: