环境:vue-admin-template   vue 2.6.10 element-ui 2.7.0

1、自定义组件,文件位置:src/components/mentContext

<template>
<!-- @mousedown.stop 阻止冒泡事件-->
<!-- @contextmenu.prevent 阻止右键的默认事件 -->
<div id="dropMenu"
:style="style"
style="display: block;"
v-show="show"
@mousedown.stop
@contextmenu.prevent>
<slot></slot>
</div>
</template>
<script>
export default {
name:"menuContext",
data() {
return {
triggerShowFn: () => {
},
triggerHideFn: () => {
},
x: null,
y: null,
style: {},
binded: false
}
},
props: {
target: null,
show: Boolean
},
mounted() {
this.bindEvents()
},
watch: {
show(show) {
if (show) {
this.bindHideEvents()
} else {
this.unbindHideEvents()
}
},
target(target) {
this.bindEvents()
}
},
methods: {
// 初始化事件
bindEvents() {
this.$nextTick(() => {
var that = this
if (!this.target || this.binded) return
this.triggerShowFn = this.contextMenuHandler.bind(this)
this.target.addEventListener('contextmenu', this.triggerShowFn)
//this.binded = true
})
},
// 取消绑定事件
unbindEvents() {
if (!this.target) return
this.target.removeEventListener('contextmenu', this.triggerShowFn)
},
// 绑定隐藏菜单事件
bindHideEvents() {
this.triggerHideFn = this.clickDocumentHandler.bind(this)
document.addEventListener('mousedown', this.triggerHideFn)
document.addEventListener('mousewheel', this.triggerHideFn)
},
// 取消绑定隐藏菜单事件
unbindHideEvents() {
document.removeEventListener('mousedown', this.triggerHideFn)
document.removeEventListener('mousewheel', this.triggerHideFn)
},
// 鼠标按压事件处理器
clickDocumentHandler(e) {
this.$emit('update:show', false) //隐藏
},
// 右键事件事件处理
contextMenuHandler(e) {
e.target.click()//这个是因为我需要获取tree节点的数据,所以我通过点击事件去获取数据
this.x = e.clientX - 240
this.y = e.clientY - 110
this.layout()
this.$emit('update:show', true) //显示
e.preventDefault()
e.stopPropagation() this.$emit('targetElement', e.target) //我还要获取右键的DOM元素进行操作
},
// 布局
layout() {
this.style = {
left: this.x + 'px',
top: this.y + 'px'
}
}
}
}
</script>
<style lang="scss">
#dropMenu {
position: absolute;
margin: 0;
padding: 0;
width: 80px;
height: auto;
border: 1px solid #ccc;
border-radius: 4px; ul {
list-style: none;
margin: 0;
padding: 0; li {
width: 100%;
text-align: center;
height: 30px;
line-height: 30px;
background: #eee;
margin-bottom: 1px;
cursor: pointer;
}
}
}
</style>

2、调用,src/views 自己的项目目录里

<template>
<div class="app-container">
<h2>当前目录:</h2>
<h4>{{ current_path }}</h4> <el-input
placeholder="输入关键字进行过滤"
v-model="filterText">
</el-input> <!-- 树形结构 -->
<el-tree
id="modelTree"
ref="tree"
:data="treedata"
:props="defaultProps"
class="filter-tree"
accordion
node-key="id"
:filter-node-method="filterNode"
>
</el-tree> <!-- 右键菜单 -->
<menu-context
:target="contextMenuTarget"
:show="isShowDrop"
@update:show="(show) => isShowDrop = show"
@targetElement="getTargetElement">
<ul>        <!--按需展示按钮-->
<li v-show="isShowDelete" @click="deleteOne">删除</li>
<li v-show="isShowAdd" @click="add">添加</li>
<li v-show="isShowEdit" @click="editNode">编辑</li>
<li v-show="isShowLink" @click="linkModels">关联</li>
<li v-show="isShowMove" @click="move">转移</li>
</ul>
</menu-context> <el-dialog
:title="textMap[dialogStatus]"
:visible.sync="dialogFormVisible"
:close-on-click-modal="false"
width="70%"
top="5vh"
@open="resetForm('dataForm')"
>
<el-form ref="dataForm" :rules="rules" :model="temp" label-position="left" label-width="100px">
<el-form-item v-if="false" label="ID" prop="id">
<el-input v-model="temp.id"/>
</el-form-item>
<el-form-item label="脚本路径" prop="path">
<p>{{ temp.path }}</p>
</el-form-item>
<el-form-item label="脚本名称" prop="name">
<el-input v-model="temp.name" placeholder="请输入具有辨识性的名称"/>
</el-form-item>
<el-form-item label="脚本内容" prop="filebody">
<codemirror v-model="temp.filebody" :options="cmOptions"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer"> <el-button @click="dialogFormVisible = false">
取消
</el-button>
<el-button type="primary" @click="dialogStatus==='create'?createData():updateData()">
提交
</el-button>
</div>
</el-dialog>
</div>
</template> <script>
import {Message} from 'element-ui'
import * as LocalScriptsApi from '@/api/hostmanage'
// 在线代码编辑器
import {codemirror} from 'vue-codemirror'
import 'codemirror/lib/codemirror.css'
import 'codemirror/mode/yaml/yaml.js'
import 'codemirror/theme/monokai.css'
import request from "@/utils/request";
import store from "@/store";
import menuContext from '@/components/menuContext' let id = 1000;
export default {
components: {
menuContext,
codemirror
},
data() {
return {
// 树形节点参数
filterText: '', // 过滤内容
treedata: [], // 属性节点内容
current_path: '',
defaultProps: { //节点内容的key
children: 'children',
label: 'label'
},
// 右键菜单参数
isShowDrop: false, //右键菜单的是否显示
contextMenuTarget: null, //右键菜单的DOM对象
thisformdata: {}, //右键菜单的点击的节点对象
targetElement: {}, //右键点击的目标对象
isShowDelete: true, //是否显示菜单中的删除按钮
isShowEdit: true, //是否显示菜单中的 编辑按钮
isShowAdd: true, //是否显示菜单中的 添加按钮
isShowMove: true, //是否显示菜单中的 转移按钮
isShowLink: true, //是否显示菜单中的 关联按钮 // 以下为模态框的参数
temp: {
id: undefined,
name: '',
filebody: '',
path:''
},
cmOptions: { // codemirror options
tabSize: 2,
mode: 'text/x-yaml',
theme: 'monokai',
lineNumbers: true,
line: true
},
dialogFormVisible: false,
dialogStatus: '',
textMap: {
update: '修改脚本',
create: '新增脚本'
},
rules: {
name: [{required: true, message: '请输入脚本名称', trigger: 'blur'}],
filebody: [{required: true, message: '请输入脚本内容', trigger: 'blur'}],
},
};
},
created() {
this.fetchTreeData()
},
mounted() {
this.isShowDrop = false;
//dom加载完,进行目标dom的设置,直接在data中赋值,会找不到dom
this.contextMenuTarget = document.querySelector('#modelTree')
},
watch: {
filterText(val) {
this.$refs.tree.filter(val);
},
},
methods: {
filterNode(value, data) { // 节点过滤
if (!value) return true;
return data.label.indexOf(value) !== -1;
},
fetchTreeData() { // 空间树数据
LocalScriptsApi.queryscripts().then(resp => {
if (resp.status === false) {
Message({
message: response.message || '后端无返回说明信息',
type: 'error',
duration: 5 * 1000
})
} else {
this.treedata = resp.data.info
this.current_path = resp.data.current_path
} })
},
getTargetElement(v) {
this.targetElement = v
},
deleteOne() {
var that = this
var nodeIds = [this.thisformdata.nodeId]
this.$confirm('此操作将删除该节点及其子节点, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
center: true
})
.then(() => {
deleteTreeNode(that.spaceTreeId, nodeIds).then(function (res) {
console.log('deleteTreeNode', res)
if (res.success) {
that.$message('删除成功!')
that.refreshSpaceTree()
}
})
})
.catch(() => {
})
},
add() {
this.append(this.thisformdata)
this.isShowDrop = false
},
editNode() {
var data = this.thisformdata
var str = "<input type='text' name='label' value='" + data.name + "'>"
var e = window.event
var text = this.targetElement
text.innerHTML = str
this.isShowDrop = false
text.lastChild.onblur = function () {
data.name = text.lastChild.value
text.innerHTML = text.lastChild.value
var that = this
var space = {
nodeId: data.nodeId,
orgnazitionalTreeID: data.orgnazitionalTreeID,
parentNodeId: data.parentNodeId,
name: data.name,
nodeType: data.nodeType
}
//发送请求修改内容=>?有问题明天要修改
modifyTreeNode(data.orgnazitionalTreeID, space).then(function (res) {
console.log('modifyTreeNode', res)
})
}
},
move() {
if (this.thisformdata.nodeType == 0) {
this.$refs.modelLinkSpace.Open([this.thisformdata])
}
this.isShowDrop = false
},
linkModels() {
this.linkModel({}, this.thisformdata)
},
handleNodeClick(data) {
console.log('handleNodeClick', data)
// !核心 : 节点数据被获得
this.thisformdata = data
//按需展示不同的按钮
if (data.nodeType == 1 && !data.children) {
this.isShowAdd = true
this.isShowLink = true
this.isShowMove = true
} else if (data.nodeType == 0) {
this.isShowAdd = false
this.isShowLink = false
this.isShowMove = true
} else if (data.nodeType == 1 && data.children && data.children[0].nodeType == 0) {
this.isShowAdd = false
this.isShowLink = true
this.isShowMove = true
} else if (data.nodeType == 1 && data.children && data.children[0].nodeType == 1) {
this.isShowAdd = true
this.isShowLink = false
this.isShowMove = false
}
},
// 清空表单数据
resetForm(formName) {
this.$nextTick(() => {
this.$refs[formName].resetFields()
})
},
append(data) {
console.log(data)
this.dialogStatus = 'create'
this.dialogFormVisible = true
// 自己定义逻辑
},
}
}; </script> <style lang="scss"> </style>

参考资料:https://www.cnblogs.com/xuqp/p/11117636.html

vue+element树形结构右键菜单的更多相关文章

  1. 递归、嵌套for循环、map集合方式实现树形结构菜单列表查询

    有时候, 我们需要用到菜单列表,但是怎么样去实现一个菜单列表的编写呢,这是一重要的问题. 比如我们需要编写一个树形结构的菜单,那么我们可以使用JQuery的zTree插件:http://www.tre ...

  2. VUE实现Studio管理后台(七):树形结构,文件树,节点树共用一套代码NodeTree

    本次介绍的内容,稍稍复杂了一点,用VUE实现树形结构.目前这个属性结构还没有编辑功能,仅仅是展示.明天再开一篇文章,介绍如何增加编辑功能,标题都想好了.先看今天的展示效果: 构建树必须用到递归,使用s ...

  3. vue.js与element-ui实现菜单树形结构

    由于业务需要,要求实现树形菜单,且菜单数据由后台返回,在网上找了几篇文章,看下来总算有了解决办法.借鉴文章链接在最底部. 场景:根据业务要求,需要实现活动的树形菜单,菜单数据由后台返回,最后的效果图如 ...

  4. 基于electron+vue+element构建项目模板之【自定义标题栏&右键菜单项篇】

    1.概述 开发平台OS:windows 开发平台IDE:vs code 本篇章将介绍自定义标题栏和右键菜单项,基于electron现有版本安全性的建议,此次的改造中主进程和渲染进程彼此语境隔离,通过预 ...

  5. 验证实现element-ui树形控件的自定义图标及右键菜单

    许久不用,element-ui已经更新至2.4.1版本.直接进入今天的正题,前提是node.js的环境还有vue及elment-ui都已经安装.由于element-ui的官方文档中介绍比较粗略,试了许 ...

  6. Vue + Element UI 实现权限管理系统 前端篇(十四):菜单功能实现

    菜单功能实现 菜单接口封装 菜单管理是一个对菜单树结构的增删改查操作. 提供一个菜单查询接口,查询整颗菜单树形结构. http/modules/menu.js 添加 findMenuTree 接口. ...

  7. 循序渐进VUE+Element 前端应用开发(17)--- 菜单资源管理

    在权限管理系统中,菜单也属于权限控制的一个资源,应该直接应用于角色,和权限功能点一样,属于角色控制的一环.不同角色用户,登录系统后,出现的系统菜单是不同的.在VUE+Element 前端中,我们菜单结 ...

  8. Bootstrap 树形列表与右键菜单

    Bootstrap 树形列表与右键菜单 介绍两个Bootstrap的扩展 Bootstrap Tree View 树形列表 jQuery contextMenu 右键菜单 Demo采用CDN分发,直接 ...

  9. jQuery+zTree加载树形结构菜单

    jQuery+zTree加载树形结构菜单 由于项目中需要设计树形菜单功能,经过一番捣腾之后,终于给弄出来了,所以便记下来,也算是学习zTree的一个总结吧. zTree的介绍: 1.zTree 是利用 ...

随机推荐

  1. Python Ethical Hacking - BACKDOORS(2)

    Refactoring - Creating a Listener Class #!/usr/bin/env python import socket class Listener: def __in ...

  2. 五大高效的PDF文件搜索引擎

    当你花了半个多小时在线搜索PDF文档,却发现您找到的文档都不是您需要的PDF格式.如前说述,您可以先打开PDF文档查看是不是PDF格式的,然后再到web浏览器中下载该文档.那么,为了确保您获得的文档是 ...

  3. 不藏了,摊牌了,一张知识图谱整理完整Java并发体系,就问全不全

    推荐阅读: 2020年马士兵Java多线程高并发讲解——百万年薪架构师告诉你Java多线程与高并发 目录 这是我关于整个Java并发体系的整理,结合的主要是现在市面上对于Java并发在面试的过程中经常 ...

  4. Hadoop之HDFS常用文件操作命令

    命令基本格式:hadoop fs -cmd < args > 1. ls 列出hdfs文件系统根目录下的目录和文件hadoop fs -ls /dirhadoop fs -ls -R /d ...

  5. 题解 洛谷 P2046 【[NOI2010]海拔】

    首先进行贪心,发现海拔有梯度时一定是不优的,最优的情况是海拔像断崖一样上升,也就是左上角有一片海拔高度为\(0\),右下角有一片海拔高度为\(1\). 发现这样的性质后,不难想到用最小割来解决问题,但 ...

  6. DJANGO-天天生鲜项目从0到1-011-订单-订单提交和创建

    本项目基于B站UP主‘神奇的老黄’的教学视频‘天天生鲜Django项目’,视频讲的非常好,推荐新手观看学习 https://www.bilibili.com/video/BV1vt41147K8?p= ...

  7. 线程_multiprocessing实现文件夹copy器

    import multiprocessing import os import time import random def copy_file(queue,file_name,source_fold ...

  8. PHP sizeof() 函数

    实例 返回数组中元素的数目: <?php$cars=array("Volvo","BMW","Toyota");echo sizeof ...

  9. PHP date_timezone_get() 函数

    ------------恢复内容开始------------ 实例 返回给定 DateTime 对象的时区: <?php$date=date_create(null,timezone_open( ...

  10. PHP serialize() 函数

    serialize() 函数用于序列化对象或数组,并返回一个字符串.高佣联盟 www.cgewang.com serialize() 函数序列化对象后,可以很方便的将它传递给其他需要它的地方,且其类型 ...