1.前言
项目需求:后端发送ftp目录tree需要前端展示出来,可以搜索文件,并且可以对文件进行操作(创建文件夹,删除文件,重命名等一些操作),这里用用的是element-ui tree控件!技术上没有什么难度!
2. 思路
展示目录结构应该很简单,需要对文件做一些操作,这里可以想象下window系统是怎么操作文件,鼠标右键,弹框显示,我们也可以模拟下,鼠标右键可以获取到tree得当前坐标,然后可以根据坐标显示弹框,当前点击其他地方弹框也要消失!先看下效果图!
这里作了一些判断,如果是文件夹都显示新建文件夹,删除文件夹,文件夹重命名,如果是文件就显示,删除文件,文件重命名
下面是后端传过来的数据,这个是我自己定义的,你需要什么数据可以和后端商量
let data = [
{
id: 1,
fileName: "文件夹1",
path: "c:/文件夹1",
type: "folder",
children: [
{
id: 4,
fileName: "文件夹2",
path: "c:/文件夹1/文件夹2",
type: "folder",
children: [
{
id: 9,
fileName: "1.js",
path: "c:/文件夹1/文件夹2/1.js",
type: "file"
},
{
id: 10,
fileName: "文件夹3",
path: "c:/文件夹1/文件夹2",
type: "folder"
}
]
}
]
},
{
id: 2,
fileName: "文件夹4",
path: "c:/文件夹1/文件夹4",
type: "folder",
children: [
{
id: 5,
fileName: "2.js",
path: "c:/文件夹1/文件夹4/2.js",
type: "file"
},
{
id: 6,
fileName: "3.js",
path: "c:/文件夹1/文件夹4/3.js",
type: "file"
}
]
},
{
id: 3,
fileName: "文件夹5",
path: "c:/文件夹1/文件夹4",
type: "folder",
children: [
{
id: 7,
fileName: "4.js",
path: "c:/文件夹1/文件夹5/4.js",
type: "file"
},
{
id: 8,
fileName: "5.js",
path: "c:/文件夹1/文件夹5/5.js",
type: "file"
}
]
}
]
html部分
<div class="tab-container">
<el-tabs v-model="activeName">
<el-tab-pane label="视频管理" name="first">视频管理</el-tab-pane>
<el-tab-pane label="图片管理" name="second">图片管理</el-tab-pane>
<el-tab-pane label="文件列表" name="third">
<div class="custom-tree-container">
<el-input placeholder="输入关键字进行过滤" v-model="filterText">
</el-input>
<!-- show-checkbox -->
<div class="block">
<el-tree
:data="data"
node-key="id"
default-expand-all
:filter-node-method="filterNode"
ref="tree"
@node-contextmenu="operationFile"
@node-click="operationClose"
>
<span class="custom-tree-node" slot-scope="{ node, data }">
<i
:class="[
data.type == 'folder'
? 'el-icon-folder'
: 'el-icon-notebook-2'
]"
style="color: #FFE791; margin-right: 5px;"
></i>
<span style="font-size: 15px;">{{ data.fileName }}</span>
</span>
</el-tree>
</div>
</div></el-tab-pane
>
<el-tab-pane label="文件位置" name="fourth">文件位置</el-tab-pane>
</el-tabs>
<div
:style="{
left: btnX + 'px',
top: btnY + 'px'
}"
v-show="dialogVisible"
id="operation-list"
>
<el-button
v-if="isFolder"
@click="append"
class="operation-btn"
size="small"
>新建文件夹
</el-button>
<el-button
v-if="isFolder"
@click="remove"
class="operation-btn"
size="small"
>删除文件夹
</el-button>
<el-button v-else @click="remove" class="operation-btn" size="small"
>删除文件
</el-button>
<el-button
v-if="isFolder"
@click="rename"
class="operation-btn"
size="small"
>文件夹重命名
</el-button>
<el-button v-else @click="rename" class="operation-btn" size="small"
>文件重命名
</el-button>
</div>
</div>
js部分:
let id = 100,
data = [
{
id: 1,
fileName: "文件夹1",
path: "c:/文件夹1",
type: "folder",
children: [
{
id: 4,
fileName: "文件夹2",
path: "c:/文件夹1/文件夹2",
type: "folder",
children: [
{
id: 9,
fileName: "1.js",
path: "c:/文件夹1/文件夹2/1.js",
type: "file"
},
{
id: 10,
fileName: "文件夹3",
path: "c:/文件夹1/文件夹2",
type: "folder"
}
]
}
]
},
{
id: 2,
fileName: "文件夹4",
path: "c:/文件夹1/文件夹4",
type: "folder",
children: [
{
id: 5,
fileName: "2.js",
path: "c:/文件夹1/文件夹4/2.js",
type: "file"
},
{
id: 6,
fileName: "3.js",
path: "c:/文件夹1/文件夹4/3.js",
type: "file"
}
]
},
{
id: 3,
fileName: "文件夹5",
path: "c:/文件夹1/文件夹4",
type: "folder",
children: [
{
id: 7,
fileName: "4.js",
path: "c:/文件夹1/文件夹5/4.js",
type: "file"
},
{
id: 8,
fileName: "5.js",
path: "c:/文件夹1/文件夹5/5.js",
type: "file"
}
]
}
];
export default {
name: "tree",
data() {
return {
activeName: "second", //tab栏被选中的模块
filterText: "", //搜索过滤
dialogVisible: false, //弹框是否显示
btnX: "", //显示框x坐标
btnY: "", //显示框y坐标
operationFileData: "", //右键选中节点属性
node: "", //右键选中节点所有信息
isFolder: false, //是否是文件夹
data: JSON.parse(JSON.stringify(data)) //拷贝一份tree数据,不影响之前的
};
},
mounted() {
let that = this;
$(document).on("click", function(event) {
if (event.target != document.getElementById("operation-list")) {
that.dialogVisible = false;
}
});
},
watch: {
filterText(val) {
this.$refs.tree.filter(val);
}
},
methods: {
filterNode(value, data) {
if (!value) return true;
return data.fileName.indexOf(value) !== -1;
},
//关闭操作
operationClose(evt, data, node) {
this.dialogVisible = false;
},
// 操作tree列表鼠标右键触发
operationFile(event, data, node, context) {
this.btnX = event.x;
this.btnY = event.y;
this.operationFileData = data; //当前节点数据
this.node = node; // 将当前节点所有信息
this.isFolder = data.type == "folder"; //是否是文件夹
this.dialogVisible = true; // 展示右键菜单
console.log(event, data, node, context == this);
},
//添加文件夹
append() {
this.dialogVisible = false;
this.$prompt("请输入文件名", "提示", {
// 弹出框用于输入文件名
confirmButtonText: "确定",
cancelButtonText: "取消",
inputPattern: /^[^/\\\:\*\?\"\<\>\|\\]{1,255}$/,
inputErrorMessage: "文件名格式不对"
})
.then(({ value }) => {
//添加新节点
let child = {
id: id++,
fileName: value,
type: "folder",
children: []
};
if (!this.operationFileData.children) {
this.$set(this.operationFileData, "children", []);
}
this.operationFileData.children.push(child);
//展开节点
if (!this.node.expanded) {
this.node.expanded = true;
}
this.$message({
type: "success",
message: "文件夹新建成功!"
});
})
.catch(() => {
this.$message({
type: "info",
message: "取消输入"
});
});
},
//删除文件夹/文件
remove() {
this.dialogVisible = false;
this.$confirm("此操作将永久删除该文件夹/文件, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
const parent = this.node.parent;
const children = parent.data.children || parent.data;
const index = children.findIndex(
d => d.id === this.operationFileData.id
);
children.splice(index, 1);
this.$message({
type: "success",
message: "删除成功!"
});
})
.catch(() => {
this.$message({
type: "info",
message: "已取消删除"
});
});
},
//给文件/文件夹重新命名
rename() {
this.dialogVisible = false;
this.$prompt("请输入文件名", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
inputPlaceholder: this.node.data.fileName,
inputPattern: /^[^/\\\:\*\?\"\<\>\|\\]{1,255}$/,
inputErrorMessage: "文件名格式不对"
})
.then(({ value }) => {
this.node.data.fileName = value;
this.$message({
type: "success",
message: "重命名成功!"
});
})
.catch(() => {
this.$message({
type: "info",
message: "取消重命名"
});
});
}
}
};
style部分:
.tab-container {
width: 400px;
height: 500px;
margin: 100px auto;
border: 1px solid #eee;
padding: 20px;
}
.el-tabs.el-tabs--top {
height: 100%;
}
.el-tabs__content {
height: calc(100% - 55px);
border: 1px solid #eee;
padding: 10px;
}
.operation-btn {
width: 100%;
margin-left: 0 !important;
font-size: 10px;
border-radius: 0;
border-top: none;
}
#operation-list {
z-index: 999999;
position: absolute;
width: 100px;
background: white;
box-shadow: 1px 1px 5px #aaa;
}
源码已经奉上,效果图如下: