修改文本编辑器;文件树添加右键菜单

This commit is contained in:
jmal 2020-06-21 20:07:45 +08:00
parent b1a6d7e175
commit c7774cf867
8 changed files with 513 additions and 37 deletions

View File

@ -26,6 +26,7 @@
"highlightjs-line-numbers.js": "^2.7.0",
"htmlhint": "^0.13.0",
"jquery": "^1.12.4",
"jquery-contextmenu": "^2.9.1",
"jquery.fancytree": "^2.35.0",
"js-cookie": "2.2.0",
"jshint": "^2.11.1",
@ -43,6 +44,7 @@
"scriptjs": "^2.5.9",
"sortablejs": "^1.10.2",
"spark-md5": "^3.0.0",
"v-contextmenu": "^2.9.0",
"v-viewer": "^1.5.1",
"vant": "2.5.0",
"viewerjs": "^1.5.0",
@ -52,6 +54,7 @@
"vue-codemirror-lite": "^1.0.4",
"vue-grid-layout": "^2.3.7",
"vue-router": "3.0.6",
"vue-runtime-helpers": "^1.1.2",
"vue-simple-uploader": "^0.7.4",
"vue-touch": "^2.0.0-beta.4",
"vue-video-player": "^5.0.2",

View File

@ -107,6 +107,14 @@ export default {
params
})
},
// 查找上级目录
upperLevelList: function(params) {
return request({
url: 'upper-level-list',
method: 'get',
params
})
},
// 查找下级目录
listfiles: function(params) {
return request({

View File

@ -1,13 +1,19 @@
<template>
<div id="dir-tree">
<div id="dir-tree" >
<v-contextmenu ref="contextmenu" :theme="lightTheme?'default':'dark'" @contextmenu="contextmenu">
<v-contextmenu-item v-for="item of menus" :key="item.operation" @click="contextmenuClick(item.operation)">
<svg-icon :icon-class="item.iconClass"></svg-icon>
{{item.label}}
</v-contextmenu-item>
</v-contextmenu>
</div>
</template>
<script>
import 'v-contextmenu/dist/index.css'
import { iconClass,suffix } from '@/utils/file-type'
import 'jquery.fancytree/dist/skin-win8/ui.fancytree.less';
import {createTree} from 'jquery.fancytree';
import {createTree,getNode} from 'jquery.fancytree';
import api from '@/api/file-api'
export default {
name: "FancyTree",
@ -16,14 +22,29 @@
type: Array,
default: () => []
},
lightTheme: {
type: Boolean,
default: true,
}
},
data(){
return {
tree:{}
tree:{},
contextData: {},
rightClicking: false,
menus: [],
folderMenus: [
{ iconClass: 'open-folder', label: '进入该目录', operation: 'openFolder'},
{ iconClass: 'menu-remove', label: '删除', operation: 'remove' }
],
fileMenus: [
{ iconClass: 'menu-remove', label: '删除', operation: 'remove' }
]
}
},
watch: {
directoryTreeData(newVal,oldVal) {
this.directoryTreeData = newVal
this.loadTreeData(newVal,true)
}
},
@ -33,6 +54,86 @@
computed: {
},
methods: {
contextmenu(vnode){
this.rightClicking = true
const that = this
setTimeout(function () {
that.rightClicking = false
},200)
this.contextData = getNode(vnode).data
// 触发节点的点击事件
let evObj = document.createEvent('MouseEvents');
evObj.initMouseEvent('click',true,true,window,1,12,345,7,220,false,false,true,false,0,null);
vnode.dispatchEvent(evObj);
if(this.contextData.isFolder){
this.menus = this.folderMenus
}else{
this.menus = this.fileMenus
}
},
// 菜单点击事件
contextmenuClick(operation){
switch (operation) {
case 'openFolder':
console.log('openFolder',this.contextData)
this.enterDir(this.contextData)
break
case 'remove':
console.log('remove',this.contextData)
break
default:
console.log('default',this.contextData)
break
}
},
//上级目录
upperLeve(){
let path = this.tree.rootNode.children[0].key
let title = this.tree.rootNode.children[0].title
if(path.endsWith(title)){
path = path.substring(0,path.length-title.length)
}
if(path.length === 0){
return
}
api.upperLevelList({
username: this.$store.state.user.name,
path: path,
}).then(res => {
this.tree.reload(this.convert(res.data))
})
},
// 刷新当前目录
refresh(){
api.upperLevelList({
username: this.$store.state.user.name,
path: this.tree.rootNode.children[0].key,
}).then(res => {
this.tree.reload(this.convert(res.data))
})
},
//进入目录
enterDir(node){
let loading = this.$message({
iconClass: 'el-icon-loading',
type: 'info',
duration: 0,
dangerouslyUseHTMLString: true,
offset: document.body.clientHeight/3,
message: '<span>&nbsp;&nbsp;正在加载数据...</span>'
})
api.listfiles({
userId: this.$store.state.user.userId,
username: this.$store.state.user.name,
path: node.path,
}).then(res => {
loading.close()
this.tree.reload(this.convert(res.data))
}).catch(()=>{
loading.close()
})
},
loadTreeData(treeData,reLoad) {
api.listfiles({
userId: this.$store.state.user.userId,
@ -69,16 +170,18 @@
source: this.convert(treeData),
lazyLoad: (event,data)=> this.lazyLoad(event,data),
click: (event,data)=> this.click(event,data),
dblclick: (event,data)=> this.dblclick(event,data),
activate: (event,data)=> this.activate(event,data),
loadChildren: function(event, data) {
// console.log('loadChildren',data)
},
createNode: (event,data)=> this.createNode(event,data),
});
},
icon(event,data) {
return { html: this.loadSvg(this.findIconClass(data.node.data)) }
},
findIconClass(file){
if(!file || !file.contentType){
return
}
if(file.isFolder){
return 'folder'
}
@ -101,8 +204,10 @@
return 'file'
},
loadSvg(svgName){
let src = require(`@/icons/svg/${svgName}.svg`)
return `<svg class="tree-icon">${src.default.render()}<use xlink:href="#icon-${svgName}"/></svg>`
if(svgName){
let src = require(`@/icons/svg/${svgName}.svg`)
return `<svg class="tree-icon">${src.default.render()}<use xlink:href="#icon-${svgName}"/></svg>`
}
},
lazyLoad(event, data){
let nodeData = data.node.data
@ -120,10 +225,20 @@
})
},
click(event, data){
this.$emit('treeNodeClick',data.node.data)
if(!this.rightClicking){
this.$emit('treeNodeClick',data.node.data)
}
},
dblclick(event, data){
},
activate(event, data){
},
createNode(event, data){
if(data.node.key !== '_1'){
this.$refs.contextmenu.addRef({el:data.node.span,vnode: data.node.span})
}else{
data.node.span.querySelector('.fancytree-title').innerText = '无数据'
}
},
convert(data){
return data.map(doc => {

View File

@ -0,0 +1,256 @@
// jQuery Context Menu Plugin
//
// Version 1.01 customized version (see comment below)
//
// Cory S.N. LaViska
// A Beautiful Site (http://abeautifulsite.net/)
//
// More info: http://abeautifulsite.net/2008/09/jquery-context-menu-plugin/
//
// Terms of Use
//
// This plugin is dual-licensed under the GNU General Public License
// and the MIT License and is copyright A Beautiful Site, LLC.
//
// 2011-02-17 Martin Wendt:
// Changed stopPropagation() to preventDefault() in order to make it
// work with Dynatree drag'n'drop.
// See http://code.google.com/p/dynatree/issues/detail?id=174
// 2012-09-27 Martin Wendt:
// fixed position in a fancy layout
// 2013-05-09 Martin Wendt:
// Added polyfil for $.browser (fixes compatibility with jQuery 1.9)
//
if(jQuery)( function() {
/* Check browser version, since $.browser was removed in jQuery 1.9 */
function _checkBrowser(){
var matched, browser;
function uaMatch( ua ) {
ua = ua.toLowerCase();
var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
/(webkit)[ \/]([\w.]+)/.exec( ua ) ||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
/(msie) ([\w.]+)/.exec( ua ) ||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
[];
return {
browser: match[ 1 ] || "",
version: match[ 2 ] || "0"
};
}
matched = uaMatch( navigator.userAgent );
browser = {};
if ( matched.browser ) {
browser[ matched.browser ] = true;
browser.version = matched.version;
}
if ( browser.chrome ) {
browser.webkit = true;
} else if ( browser.webkit ) {
browser.safari = true;
}
return browser;
}
var BROWSER = jQuery.browser || _checkBrowser();
$.extend($.fn, {
contextMenu: function(o, callback) {
// Defaults
if( o.menu == undefined ) return false;
if( o.inSpeed == undefined ) o.inSpeed = 150;
if( o.outSpeed == undefined ) o.outSpeed = 75;
// 0 needs to be -1 for expected results (no fade)
if( o.inSpeed == 0 ) o.inSpeed = -1;
if( o.outSpeed == 0 ) o.outSpeed = -1;
// Loop each context menu
$(this).each( function() {
var el = $(this);
var offset = $(el).offset();
// Add contextMenu class
$('#' + o.menu).addClass('contextMenu');
// Simulate a true right click
$(this).mousedown( function(e) {
var evt = e;
// evt.stopPropagation();
evt.preventDefault();
$(this).mouseup( function(e) {
// e.stopPropagation();
e.preventDefault();
var srcElement = $(this);
$(this).unbind('mouseup');
if( evt.button == 2 ) {
// Hide context menus that may be showing
$(".contextMenu").hide();
// Get this context menu
var menu = $('#' + o.menu);
if( $(el).hasClass('disabled') ) return false;
// Detect mouse position
var d = {}, x, y;
if( self.innerHeight ) {
d.pageYOffset = self.pageYOffset;
d.pageXOffset = self.pageXOffset;
d.innerHeight = self.innerHeight;
d.innerWidth = self.innerWidth;
} else if( document.documentElement &&
document.documentElement.clientHeight ) {
d.pageYOffset = document.documentElement.scrollTop;
d.pageXOffset = document.documentElement.scrollLeft;
d.innerHeight = document.documentElement.clientHeight;
d.innerWidth = document.documentElement.clientWidth;
} else if( document.body ) {
d.pageYOffset = document.body.scrollTop;
d.pageXOffset = document.body.scrollLeft;
d.innerHeight = document.body.clientHeight;
d.innerWidth = document.body.clientWidth;
}
(e.pageX) ? x = e.pageX : x = e.clientX + d.scrollLeft;
(e.pageY) ? y = e.pageY : y = e.clientY + d.scrollTop;
// Show the menu
$(document).unbind('click');
// MW: fixed position in a fancy layout
// $(menu).css({ top: y, left: x }).fadeIn(o.inSpeed);
$(menu).fadeIn(o.inSpeed).offset({ top: y, left: x }); // must be visible, before calling offset()
// Hover events
$(menu).find('A').mouseover( function() {
$(menu).find('LI.hover').removeClass('hover');
$(this).parent().addClass('hover');
}).mouseout( function() {
$(menu).find('LI.hover').removeClass('hover');
});
// Keyboard
$(document).keypress( function(e) {
switch( e.keyCode ) {
case 38: // up
if( $(menu).find('LI.hover').size() == 0 ) {
$(menu).find('LI:last').addClass('hover');
} else {
$(menu).find('LI.hover').removeClass('hover').prevAll('LI:not(.disabled)').eq(0).addClass('hover');
if( $(menu).find('LI.hover').size() == 0 ) $(menu).find('LI:last').addClass('hover');
}
break;
case 40: // down
if( $(menu).find('LI.hover').size() == 0 ) {
$(menu).find('LI:first').addClass('hover');
} else {
$(menu).find('LI.hover').removeClass('hover').nextAll('LI:not(.disabled)').eq(0).addClass('hover');
if( $(menu).find('LI.hover').size() == 0 ) $(menu).find('LI:first').addClass('hover');
}
break;
case 13: // enter
$(menu).find('LI.hover A').trigger('click');
break;
case 27: // esc
$(document).trigger('click');
break
}
});
// When items are selected
$('#' + o.menu).find('A').unbind('click');
$('#' + o.menu).find('LI:not(.disabled) A').click( function() {
$(document).unbind('click').unbind('keypress');
$(".contextMenu").hide();
// Callback
if( callback ) callback( $(this).attr('href').substr(1), $(srcElement), {x: x - offset.left, y: y - offset.top, docX: x, docY: y} );
return false;
});
// Hide bindings
setTimeout( function() { // Delay for Mozilla
$(document).click( function() {
$(document).unbind('click').unbind('keypress');
$(menu).fadeOut(o.outSpeed);
return false;
});
}, 0);
}
});
});
// Disable text selection
if( BROWSER.mozilla ) {
$('#' + o.menu).each( function() { $(this).css({ 'MozUserSelect' : 'none' }); });
} else if( BROWSER.msie ) {
$('#' + o.menu).each( function() { $(this).bind('selectstart.disableTextSelect', function() { return false; }); });
} else {
$('#' + o.menu).each(function() { $(this).bind('mousedown.disableTextSelect', function() { return false; }); });
}
// Disable browser context menu (requires both selectors to work in IE/Safari + FF/Chrome)
$(el).add($('UL.contextMenu')).bind('contextmenu', function() { return false; });
});
return $(this);
},
// Disable context menu items on the fly
disableContextMenuItems: function(o) {
if( o == undefined ) {
// Disable all
$(this).find('LI').addClass('disabled');
return( $(this) );
}
$(this).each( function() {
if( o != undefined ) {
var d = o.split(',');
for( var i = 0; i < d.length; i++ ) {
$(this).find('A[href="' + d[i] + '"]').parent().addClass('disabled');
}
}
});
return( $(this) );
},
// Enable context menu items on the fly
enableContextMenuItems: function(o) {
if( o == undefined ) {
// Enable all
$(this).find('LI.disabled').removeClass('disabled');
return( $(this) );
}
$(this).each( function() {
if( o != undefined ) {
var d = o.split(',');
for( var i = 0; i < d.length; i++ ) {
$(this).find('A[href="' + d[i] + '"]').parent().removeClass('disabled');
}
}
});
return( $(this) );
},
// Disable context menu(s)
disableContextMenu: function() {
$(this).each( function() {
$(this).addClass('disabled');
});
return( $(this) );
},
// Enable context menu(s)
enableContextMenu: function() {
$(this).each( function() {
$(this).removeClass('disabled');
});
return( $(this) );
},
// Destroy context menu(s)
destroyContextMenu: function() {
// Destroy specified context menus
$(this).each( function() {
// Disable action
$(this).unbind('mousedown').unbind('mouseup');
});
return( $(this) );
}
});
})(jQuery);

View File

@ -0,0 +1,62 @@
/* Generic context menu styles */
.contextMenu {
position: absolute;
width: 120px;
z-index: 99999;
border: solid 1px #CCC;
background: #EEE;
padding: 0px;
margin: 0px;
display: none;
}
.contextMenu LI {
list-style: none;
padding: 0px;
margin: 0px;
}
.contextMenu A {
color: #333;
text-decoration: none;
display: block;
line-height: 20px;
height: 20px;
background-position: 6px center;
background-repeat: no-repeat;
outline: none;
padding: 1px 5px;
padding-left: 28px;
}
.contextMenu LI.hover A {
color: #FFF;
background-color: #3399FF;
}
.contextMenu LI.disabled A {
color: #AAA;
cursor: default;
}
.contextMenu LI.hover.disabled A {
background-color: transparent;
}
.contextMenu LI.separator {
border-top: solid 1px #CCC;
}
/*
Adding Icons
You can add icons to the context menu by adding
classes to the respective LI element(s)
*/
.contextMenu LI.edit A { background-image: url(images/page_white_edit.png); }
.contextMenu LI.cut A { background-image: url(images/cut.png); }
.contextMenu LI.copy A { background-image: url(images/page_white_copy.png); }
.contextMenu LI.paste A { background-image: url(images/page_white_paste.png); }
.contextMenu LI.delete A { background-image: url(images/page_white_delete.png); }
.contextMenu LI.quit A { background-image: url(images/door.png); }

View File

@ -17,7 +17,7 @@
<div class="title-extension">
<el-button v-if="isShowUpdateBtn" @click="update" :class="lightTheme?'':'dark-button'" :loading="updating">Ctrl-S 保存</el-button>
<!-- <el-button @click="changePreviewMode">{{previewMode?'预览模式':'源码模式'}}</el-button> -->
<el-button @click="skinning" :class="lightTheme?'':'dark-button'">{{lightTheme?'暗色':'亮色'}}</el-button>
<el-button @click="skinning" :class="lightTheme?'':'dark-button'" :icon="lightTheme?'el-icon-moon':'el-icon-sunny'" circle></el-button>
<button class="title-extension-button" @click="fullScreen">
<svg-icon :icon-class="fullscreen?'normalscreen':'fullscreen'"></svg-icon>
</button>
@ -26,8 +26,15 @@
<div class="content" @keydown="onKeyDown">
<div class="editor_main_storey"></div>
<div class="file-contents" :style="{width: contentsWidth+'px',height: editorHieght+'px'}">
<!--<file-tree :directoryTreeData="directoryTreeData" :localFileMode="true" @treeNodeClick="treeNodeClick"></file-tree>-->
<fancy-tree v-if="directoryTreeData.length > 0" :directoryTreeData="directoryTreeData" @treeNodeClick="treeNodeClick"></fancy-tree>
<div class="dir-tools" :style="{width: contentsWidth+5+'px'}">
<el-button-group>
<el-button :class="lightTheme?'':'dark-button'" size="mini" icon="el-icon-arrow-left" @click="upperLeve">上一级</el-button>
<el-button :class="lightTheme?'':'dark-button'" size="mini" icon="el-icon-refresh" @click="refresh">刷新</el-button>
<el-button :class="lightTheme?'':'dark-button'" size="mini" icon="el-icon-plus">新建</el-button>
<el-button :class="lightTheme?'':'dark-button'" size="mini" icon="el-icon-search">搜索</el-button>
</el-button-group>
</div>
<fancy-tree ref="fancTree" v-if="directoryTreeData.length > 0" :lightTheme="lightTheme" :directoryTreeData="directoryTreeData" @treeNodeClick="treeNodeClick"></fancy-tree>
</div>
<div class="editor-resize" style="width: 5px;cursor: col-resize;"></div>
<div class="editor">
@ -109,7 +116,7 @@
fullscreen: false,
dialogWidth: 0.7,
lastTransform: undefined,
contentsWidth: 300,
contentsWidth: 273,
editorWidth: 1035,
editorHieght: 640,
content: '',
@ -157,6 +164,7 @@
type: 'info',
duration: 0,
dangerouslyUseHTMLString: true,
offset: 100,
message: '<span>&nbsp;&nbsp;正在加载数据...</span>'
})
let languages = monaco.languages.getLanguages();
@ -209,6 +217,12 @@
}
},
methods:{
upperLeve(){
this.$refs.fancTree.upperLeve()
},
refresh(){
this.$refs.fancTree.refresh()
},
dragControllerDiv() {
let resize = document.querySelector('.el-dialog__body .content .editor-resize');
let left = document.querySelector('.file-contents');
@ -249,6 +263,7 @@
type: 'info',
duration: 0,
dangerouslyUseHTMLString: true,
offset: document.body.clientHeight/3,
message: '<span>&nbsp;&nbsp;正在加载数据...</span>'
})
let languages = monaco.languages.getLanguages();
@ -435,29 +450,29 @@
margin: 0 !important;
overflow: hidden;
.dark-button {
background: #565656;
border: 1px solid #565656;
color: #ffffff;
}
.el-button:focus{
background: #FFF;
border: 1px solid #DCDFE6;
color: #606266;
}
.dark-button:focus{
background: #565656;
border: 1px solid #565656;
color: #ffffff;
}
.dark-button:hover {
color: #409EFF;
background-color: $bg-color;
}
.el-dialog__header {
padding: 5px 20px 5px;
.dark-button {
background: #565656;
border: 1px solid #565656;
color: #ffffff;
}
.el-button:focus{
background: #FFF;
border: 1px solid #DCDFE6;
color: #606266;
}
.dark-button:focus{
background: #565656;
border: 1px solid #565656;
color: #ffffff;
}
.dark-button:hover {
color: #409EFF;
background-color: $bg-color;
}
.el-dialog__headerbtn {
top: 12px;
right: 16px;
@ -545,9 +560,22 @@
border-color: #ffffff;
}
}
.dir-tools {
.el-button--mini, .el-button--mini.is-round {
padding: 7px 10px;
}
}
}
&[data-theme=dark] {
.editor-resize {
background: $bg-color;
}
.file-contents{
@include scrollBarDarkStyle;
background: $bg-color;

View File

@ -1 +1 @@
<svg t="1580454842221" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4508" width="32" height="32"><path d="M873.11 123.11H703.64C690.73 59.8 634.62 12 567.56 12H456.44c-67.07 0-123.17 47.8-136.08 111.11H150.89C74.31 123.11 12 185.42 12 262a27.76 27.76 0 0 0 27.78 27.78h111.11v611.11A111.22 111.22 0 0 0 262 1012h500a111.22 111.22 0 0 0 111.11-111.11V289.78h111.11A27.76 27.76 0 0 0 1012 262c0-76.58-62.31-138.89-138.89-138.89zM456.44 67.56h111.12a83.51 83.51 0 0 1 78.59 55.56H377.86a83.51 83.51 0 0 1 78.58-55.56z m361.12 833.33A55.63 55.63 0 0 1 762 956.44H262a55.63 55.63 0 0 1-55.56-55.56v-611.1h611.12z m55.56-666.67H72.3a83.51 83.51 0 0 1 78.59-55.56h722.22a83.51 83.51 0 0 1 78.59 55.56z" p-id="4509"></path><path d="M512 845.33a27.76 27.76 0 0 0 27.78-27.78V428.67a27.78 27.78 0 1 0-55.56 0v388.89A27.76 27.76 0 0 0 512 845.33zM345.33 845.33a27.76 27.76 0 0 0 27.78-27.78V428.67a27.78 27.78 0 1 0-55.56 0v388.89a27.76 27.76 0 0 0 27.78 27.77zM678.67 845.33a27.76 27.76 0 0 0 27.78-27.78V428.67a27.78 27.78 0 1 0-55.56 0v388.89a27.76 27.76 0 0 0 27.78 27.77z" p-id="4510"></path></svg>
<svg t="1580454842221" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4508" width="32" height="32"><path d="M873.11 123.11H703.64C690.73 59.8 634.62 12 567.56 12H456.44c-67.07 0-123.17 47.8-136.08 111.11H150.89C74.31 123.11 12 185.42 12 262a27.76 27.76 0 0 0 27.78 27.78h111.11v611.11A111.22 111.22 0 0 0 262 1012h500a111.22 111.22 0 0 0 111.11-111.11V289.78h111.11A27.76 27.76 0 0 0 1012 262c0-76.58-62.31-138.89-138.89-138.89zM456.44 67.56h111.12a83.51 83.51 0 0 1 78.59 55.56H377.86a83.51 83.51 0 0 1 78.58-55.56z m361.12 833.33A55.63 55.63 0 0 1 762 956.44H262a55.63 55.63 0 0 1-55.56-55.56v-611.1h611.12z m55.56-666.67H72.3a83.51 83.51 0 0 1 78.59-55.56h722.22a83.51 83.51 0 0 1 78.59 55.56z" p-id="4509" fill="#F74649"></path><path d="M512 845.33a27.76 27.76 0 0 0 27.78-27.78V428.67a27.78 27.78 0 1 0-55.56 0v388.89A27.76 27.76 0 0 0 512 845.33zM345.33 845.33a27.76 27.76 0 0 0 27.78-27.78V428.67a27.78 27.78 0 1 0-55.56 0v388.89a27.76 27.76 0 0 0 27.78 27.77zM678.67 845.33a27.76 27.76 0 0 0 27.78-27.78V428.67a27.78 27.78 0 1 0-55.56 0v388.89a27.76 27.76 0 0 0 27.78 27.77z" p-id="4510" fill="#F74649"></path></svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -22,6 +22,10 @@ import { Popup,Search, Button, Cell, CellGroup, Image, List, PullRefresh, SwipeC
// import { Tree } from 'ant-design-vue';
// Vue.use(Tree)
import contentmenu from 'v-contextmenu'
import 'v-contextmenu/dist/index.css'
Vue.use(contentmenu)
// mavonEditor
import mavonEditor from 'mavon-editor'
import 'mavon-editor/dist/css/index.css'