-
新建文件夹 -
新建子文件夹 -
新建文档 -
重命名 -
删除
vue3、pinia、view-ui-plus
传入一个菜单数组数据,自动生成一个左侧菜单栏。菜单栏可以添加、删除、展开、重命名,拖动插入位置等。
c-menu-wrap.vue
c-menu.vue
menu.ts
import { defineStore } from 'pinia'
import { ref, nextTick } from 'vue'
import { randomString } from '@/utils/index.js'
export const useMenuStore = defineStore('menu', () => {
const menuList = ref([
{
id: 1,
val: '标题1',
type: 'folder'
},
{
id: 2,
val: '标题1',
type: 'folder',
children: [{
id: 21,
val: '标题2',
type: 'folder',
children: [
{
id: 211,
val: '标题3',
type: 'file',
content: '123'
},
{
id: 212,
val: '标题3',
type: 'file',
content: '345'
}
]
}]
}
])
const preMenuList = ref([])
const currentMenuId = ref('')
const isShowPopper = ref(false)
const modal = ref(null)
const modalX = ref(0)
const modalY = ref(0)
const editItem = ref(null) // 当前标题编辑对象(文件夹或文件)
const editInput = ref(null)
const selectItem = ref(null) // 当前选中的文件对象
const preSelectItem = ref(null)
const isEdit = ref(false) // 文档是否开启编辑状态
const isNew = ref(false) // 是否新建
const isEditRename = ref(false) // 是否重命名
const dragItem = ref(null) // 当前拖动元素
const dropPosition = ref(0) // 拖动元素插入的位置:0 中,1 上,2 下
// 点击菜单
function doMenuAction(e:any, item: any) {
hidePopper()
if(item.type === 'folder') {
item.showSub = !item.showSub
}
// 选中的文档
else if(item.type === 'file') {
if(item.id !== currentMenuId.value) {
isEdit.value = false
currentMenuId.value = item.id.toString()
selectItem.value = JSON.parse(JSON.stringify(item))
preSelectItem.value = JSON.parse(JSON.stringify(selectItem.value))
}
}
}
// 显示更多菜单
function showPopper(param: any) {
hidePopper()
isShowPopper.value = true
let e = param.e
let item = param.item
editItem.value = item
nextTick(() => {
let _w = modal.value?.offsetWidth || 0
let _h = modal.value?.offsetHeight || 0
modalX.value = e.clientX + _w > window.innerWidth ? window.innerWidth - _w : e.clientX+2
modalY.value = e.clientY + _h > window.innerHeight ? window.innerHeight - _h : e.clientY+2
})
}
// 隐藏更多菜单
function hidePopper() {
console.log('隐藏更多菜单')
if(isNew.value || (!isNew.value && isEditRename.value)) {
menuList.value = JSON.parse(JSON.stringify(preMenuList.value))
}
isNew.value = false
isEditRename.value = false
editItem.value = null
isShowPopper.value = false
}
// 确定修改文档标题
function editTitle() {
// 新建
if(isNew.value) {
console.log('确定新建标题', editItem.value)
if(editItem.value && editItem.value.type === 'file') {
currentMenuId.value = editItem.value.id
isEdit.value = true
selectItem.value = JSON.parse(JSON.stringify(editItem.value))
preSelectItem.value = JSON.parse(JSON.stringify(selectItem.value ))
}
}
// 修改
else {
console.log('确定修改标题', editItem.value)
if(editItem.value && editItem.value.type === 'file' && currentMenuId.value === editItem.value.id) {
selectItem.value = JSON.parse(JSON.stringify(editItem.value))
preSelectItem.value = JSON.parse(JSON.stringify(selectItem.value ))
}
}
isNew.value = false
isEditRename.value = false
editItem.value = null
}
function callBack(name: string) {
console.log('callBack: ', name)
}
// 开启重命名
function openRename() {
preMenuList.value = JSON.parse(JSON.stringify(menuList.value))
isShowPopper.value = false
isEditRename.value = true
nextTick(() => {
editInput.value && editInput.value[0] && editInput.value[0].focus()
})
}
// 全部展开
function expandAll(_list: Array = []) {
if(!_list || _list.length <= 0 || !(_list instanceof Array)) {
_list = menuList.value
}
for(let i = 0; i < _list.length; i++) {
if(_list[i].children && _list[i].children.length > 0) {
_list[i].showSub = true
expandAll(_list[i].children)
}
}
}
// 创建文件夹或文档
function createNew(type: number) {
isNew.value = true
isShowPopper.value = false
isEditRename.value = true
preMenuList.value = JSON.parse(JSON.stringify(menuList.value))
// 文件夹
if(type === 1) {
// 新建文件夹
if(!editItem.value) {
console.log('新建文件夹')
editItem.value = JSON.parse(JSON.stringify({
id: randomString(32),
val: '',
type: 'folder',
}))
menuList.value.push(editItem.value)
}
// 新建子文件夹
else {
console.log('新建子文件夹')
findParentMenu(menuList.value, type)
}
}
// 文档
else if(type === 2) {
// 新建文档
if(!editItem.value) {
console.log('新建文档')
editItem.value = JSON.parse(JSON.stringify({
id: randomString(32),
val: '',
type: 'file',
}))
menuList.value.push(editItem.value)
}
// 新建子文档
else {
console.log('新建子文档')
findParentMenu(menuList.value, type)
}
}
nextTick(() => {
editInput.value && editInput.value[0] && editInput.value[0].focus()
})
}
function findParentMenu(list: Array, type: number) {
console.log(type)
for(let i = 0; i < list.length; i++) {
if(list[i].id === editItem.value.id) {
list[i].showSub = true
editItem.value = JSON.parse(JSON.stringify({
id: randomString(32),
val: '',
type: type === 1 ? 'folder' : 'file',
}))
if(!list[i].children) {
list[i].children = []
}
list[i].children.push(editItem.value)
break
} else {
if(list[i].children && list[i].children.length > 0) {
findParentMenu(list[i].children, type)
}
}
}
}
return {
editInput,
isEdit,
isNew,
isEditRename,
isShowPopper,
modal,
modalX,
modalY,
currentMenuId,
editItem,
menuList,
preMenuList,
selectItem,
preSelectItem,
dragItem,
dropPosition,
doMenuAction,
expandAll,
createNew,
openRename,
editTitle,
showPopper,
hidePopper,
callBack
}
})
使用
import cMenuWrap from '@/components/menu/c-menu-wrap.vue'