mirror of
https://github.com/wanglin2/mind-map.git
synced 2026-02-17 14:04:47 +08:00
Demo:新增源码编辑模式
This commit is contained in:
11
web/package-lock.json
generated
11
web/package-lock.json
generated
@@ -9,6 +9,7 @@
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@toast-ui/editor": "^3.1.5",
|
||||
"codemirror": "^5.65.16",
|
||||
"core-js": "^3.6.5",
|
||||
"element-ui": "^2.15.1",
|
||||
"highlight.js": "^10.7.3",
|
||||
@@ -5009,6 +5010,11 @@
|
||||
"node": ">= 4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/codemirror": {
|
||||
"version": "5.65.16",
|
||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.16.tgz",
|
||||
"integrity": "sha512-br21LjYmSlVL0vFCPWPfhzUCT34FM/pAdK7rRIZwa0rrtrIdotvP4Oh4GUHsu2E3IrQMCfRkL/fN3ytMNxVQvg=="
|
||||
},
|
||||
"node_modules/codepage": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz",
|
||||
@@ -21021,6 +21027,11 @@
|
||||
"q": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"codemirror": {
|
||||
"version": "5.65.16",
|
||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.16.tgz",
|
||||
"integrity": "sha512-br21LjYmSlVL0vFCPWPfhzUCT34FM/pAdK7rRIZwa0rrtrIdotvP4Oh4GUHsu2E3IrQMCfRkL/fN3ytMNxVQvg=="
|
||||
},
|
||||
"codepage": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz",
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@toast-ui/editor": "^3.1.5",
|
||||
"codemirror": "^5.65.16",
|
||||
"core-js": "^3.6.5",
|
||||
"element-ui": "^2.15.1",
|
||||
"highlight.js": "^10.7.3",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 2479351 */
|
||||
src: url('iconfont.woff2?t=1711432586441') format('woff2'),
|
||||
url('iconfont.woff?t=1711432586441') format('woff'),
|
||||
url('iconfont.ttf?t=1711432586441') format('truetype');
|
||||
src: url('iconfont.woff2?t=1711536835850') format('woff2'),
|
||||
url('iconfont.woff?t=1711536835850') format('woff'),
|
||||
url('iconfont.ttf?t=1711536835850') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@@ -13,6 +13,14 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icongeshihua:before {
|
||||
content: "\e7a3";
|
||||
}
|
||||
|
||||
.iconyuanma:before {
|
||||
content: "\e658";
|
||||
}
|
||||
|
||||
.icongundongtiao:before {
|
||||
content: "\e670";
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -152,7 +152,8 @@ export default {
|
||||
closeMiniMap: 'Close mini map',
|
||||
readonly: 'Change to eadonly',
|
||||
edit: 'Change to edit',
|
||||
backToRoot: 'Back to root node'
|
||||
backToRoot: 'Back to root node',
|
||||
changeSourceCodeEdit: 'Switch to source code editing mode'
|
||||
},
|
||||
nodeHyperlink: {
|
||||
title: 'Link',
|
||||
@@ -317,5 +318,15 @@ export default {
|
||||
},
|
||||
other: {
|
||||
loading: 'Loading, please wait...'
|
||||
},
|
||||
sourceCodeEdit: {
|
||||
sourceCodeTip: 'It is not recommended to modify the style in rich text mode because it requires synchronous modification of data and HTML structure.',
|
||||
format: 'Format',
|
||||
copy: 'Copy',
|
||||
confirm: 'Complete',
|
||||
close: 'Close',
|
||||
formatErrorTip: 'The JSON format is incorrect. Please check and try again',
|
||||
copyTip: 'Copied to clipboard',
|
||||
formatTip: 'Format complete'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +150,8 @@ export default {
|
||||
closeMiniMap: '关闭小地图',
|
||||
readonly: '切换为只读模式',
|
||||
edit: '切换为编辑模式',
|
||||
backToRoot: '回到根节点'
|
||||
backToRoot: '回到根节点',
|
||||
changeSourceCodeEdit: '切换为源码编辑模式'
|
||||
},
|
||||
nodeHyperlink: {
|
||||
title: '超链接',
|
||||
@@ -311,5 +312,15 @@ export default {
|
||||
},
|
||||
other: {
|
||||
loading: '正在加载,请稍后...'
|
||||
},
|
||||
sourceCodeEdit: {
|
||||
sourceCodeTip: '富文本模式下不建议修改样式,因为需要同步修改数据及html结构。',
|
||||
format: '格式化',
|
||||
copy: '复制',
|
||||
confirm: '完成',
|
||||
close: '关闭',
|
||||
formatErrorTip: 'JSON格式有误,请检查后再试',
|
||||
copyTip: '已复制到剪贴板',
|
||||
formatTip: '格式化完成'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
<OutlineEdit v-if="mindMap" :mindMap="mindMap"></OutlineEdit>
|
||||
<Scrollbar v-if="isShowScrollbar && mindMap" :mindMap="mindMap"></Scrollbar>
|
||||
<FormulaSidebar v-if="mindMap" :mindMap="mindMap"></FormulaSidebar>
|
||||
<SourceCodeEdit v-if="mindMap" :mindMap="mindMap"></SourceCodeEdit>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -83,6 +84,7 @@ import handleClipboardText from '@/utils/handleClipboardText'
|
||||
import Scrollbar from './Scrollbar.vue'
|
||||
import exampleData from 'simple-mind-map/example/exampleData'
|
||||
import FormulaSidebar from './FormulaSidebar.vue'
|
||||
import SourceCodeEdit from './SourceCodeEdit.vue'
|
||||
|
||||
// 注册插件
|
||||
MindMap.usePlugin(MiniMap)
|
||||
@@ -134,7 +136,8 @@ export default {
|
||||
NodeIconToolbar,
|
||||
OutlineEdit,
|
||||
Scrollbar,
|
||||
FormulaSidebar
|
||||
FormulaSidebar,
|
||||
SourceCodeEdit
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
@@ -80,6 +80,15 @@
|
||||
@click="toggleDark"
|
||||
></div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="$t('navigatorToolbar.changeSourceCodeEdit')"
|
||||
placement="top"
|
||||
>
|
||||
<div class="btn iconfont iconyuanma" @click="openSourceCodeEdit"></div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div class="item">
|
||||
<el-dropdown @command="handleCommand">
|
||||
<div class="btn iconfont iconbangzhu"></div>
|
||||
@@ -141,7 +150,7 @@ export default {
|
||||
this.lang = getLang()
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['setLocalConfig', 'setIsReadonly']),
|
||||
...mapMutations(['setLocalConfig', 'setIsReadonly', 'setIsOutlineEdit']),
|
||||
|
||||
readonlyChange() {
|
||||
this.setIsReadonly(!this.isReadonly)
|
||||
@@ -198,6 +207,10 @@ export default {
|
||||
|
||||
backToRoot() {
|
||||
this.mindMap.renderer.setRootNodeCenter()
|
||||
},
|
||||
|
||||
openSourceCodeEdit() {
|
||||
this.setIsOutlineEdit(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ export default {
|
||||
computed: {
|
||||
...mapState({
|
||||
isDark: state => state.localConfig.isDark,
|
||||
isOutlineEdit: state => state.isOutlineEdit,
|
||||
activeSidebar: state => state.activeSidebar
|
||||
})
|
||||
},
|
||||
|
||||
216
web/src/pages/Edit/components/SourceCodeEdit.vue
Normal file
216
web/src/pages/Edit/components/SourceCodeEdit.vue
Normal file
@@ -0,0 +1,216 @@
|
||||
<template>
|
||||
<div
|
||||
class="sourceCodeEditContainer"
|
||||
:class="{ isDark: isDark }"
|
||||
ref="sourceCodeEditContainer"
|
||||
v-if="isSourceCodeEdit"
|
||||
>
|
||||
<div class="closeBtn">
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="$t('sourceCodeEdit.copy')"
|
||||
placement="top"
|
||||
>
|
||||
<span
|
||||
class="icon iconfont iconfuzhi"
|
||||
style="font-size: 26px"
|
||||
@click="copy"
|
||||
></span>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="$t('sourceCodeEdit.format')"
|
||||
placement="top"
|
||||
>
|
||||
<span
|
||||
class="icon iconfont icongeshihua"
|
||||
style="font-size: 24px"
|
||||
@click="format"
|
||||
></span>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="$t('sourceCodeEdit.sourceCodeTip')"
|
||||
placement="top"
|
||||
>
|
||||
<span class="icon el-icon-info"></span>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="$t('sourceCodeEdit.confirm')"
|
||||
placement="top"
|
||||
>
|
||||
<span class="icon el-icon-circle-check" @click="onConfirm"></span>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="$t('sourceCodeEdit.close')"
|
||||
placement="top"
|
||||
>
|
||||
<span class="icon iconfont iconguanbi" @click="onClose"></span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div class="sourceCodeEditBox">
|
||||
<div class="outlineEdit" ref="outlineEditRef" @keydown.stop></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations } from 'vuex'
|
||||
import { storeData } from '@/api'
|
||||
import CodeMirror from 'codemirror'
|
||||
import 'codemirror/mode/javascript/javascript'
|
||||
import 'codemirror/lib/codemirror.css'
|
||||
import { copy } from '@/utils/index'
|
||||
|
||||
let editor = null
|
||||
|
||||
// 源码编辑
|
||||
export default {
|
||||
name: 'SourceCodeEdit',
|
||||
props: {
|
||||
mindMap: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
isReadonly: state => state.isReadonly,
|
||||
isDark: state => state.localConfig.isDark,
|
||||
isSourceCodeEdit: state => state.isSourceCodeEdit
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
isSourceCodeEdit(val) {
|
||||
if (val) {
|
||||
this.$nextTick(() => {
|
||||
document.body.appendChild(this.$refs.sourceCodeEditContainer)
|
||||
this.initEditor()
|
||||
this.initData()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['setIsOutlineEdit']),
|
||||
|
||||
// 初始化编辑器
|
||||
initEditor() {
|
||||
editor = CodeMirror(this.$refs.outlineEditRef, {
|
||||
mode: { name: 'javascript', json: true },
|
||||
lineWrapping: true,
|
||||
lineNumbers: true
|
||||
})
|
||||
},
|
||||
|
||||
// 初始化数据
|
||||
initData() {
|
||||
editor.setValue(JSON.stringify(this.mindMap.getData(), null, 2))
|
||||
},
|
||||
|
||||
// 完成
|
||||
onConfirm() {
|
||||
try {
|
||||
const content = editor.getValue()
|
||||
const data = JSON.parse(content)
|
||||
this.setIsOutlineEdit(false)
|
||||
this.$bus.$emit('setData', data)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
this.$message.error(this.$t('sourceCodeEdit.formatErrorTip'))
|
||||
}
|
||||
},
|
||||
|
||||
// 关闭
|
||||
onClose() {
|
||||
this.setIsOutlineEdit(false)
|
||||
},
|
||||
|
||||
// 复制
|
||||
copy() {
|
||||
const content = editor.getValue()
|
||||
copy(content)
|
||||
this.$message.success(this.$t('sourceCodeEdit.copyTip'))
|
||||
},
|
||||
|
||||
// 格式化
|
||||
format() {
|
||||
try {
|
||||
const content = editor.getValue()
|
||||
const data = JSON.parse(content)
|
||||
editor.setValue(JSON.stringify(data, null, 2))
|
||||
this.$message.success(this.$t('sourceCodeEdit.formatTip'))
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
this.$message.error(this.$t('sourceCodeEdit.formatErrorTip'))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.sourceCodeEditContainer {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1999;
|
||||
background-color: #f5f5f5;
|
||||
overflow: hidden;
|
||||
|
||||
&.isDark {
|
||||
background-color: #262a2e;
|
||||
|
||||
.closeBtn {
|
||||
.icon {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.closeBtn {
|
||||
position: absolute;
|
||||
right: 40px;
|
||||
top: 20px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.icon {
|
||||
font-size: 28px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.sourceCodeEditBox {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
padding: 50px 0;
|
||||
|
||||
.outlineEdit {
|
||||
width: 1000px;
|
||||
height: 100%;
|
||||
margin: 0 auto;
|
||||
font-size: 17px;
|
||||
background-color: #fff;
|
||||
font-family: Menlo, Monaco, Consolas, Andale Mono, Ubuntu Mono,
|
||||
Courier New, monospace;
|
||||
padding: 12px;
|
||||
border-radius: 5px;
|
||||
|
||||
/deep/ .CodeMirror {
|
||||
height: 100%;
|
||||
font-family: Menlo, Monaco, Consolas, Andale Mono, Ubuntu Mono,
|
||||
Courier New, monospace;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -25,7 +25,8 @@ const store = new Vuex.Store({
|
||||
},
|
||||
activeSidebar: '', // 当前显示的侧边栏
|
||||
isOutlineEdit: false, // 是否是大纲编辑模式
|
||||
isReadonly: false // 是否只读
|
||||
isReadonly: false, // 是否只读
|
||||
isSourceCodeEdit: false// 是否是源码编辑模式
|
||||
},
|
||||
mutations: {
|
||||
// 设置思维导图数据
|
||||
@@ -60,7 +61,12 @@ const store = new Vuex.Store({
|
||||
// 设置是否只读
|
||||
setIsReadonly(state, data) {
|
||||
state.isReadonly = data
|
||||
}
|
||||
},
|
||||
|
||||
// 设置源码编辑模式
|
||||
setIsOutlineEdit(state, data) {
|
||||
state.isSourceCodeEdit = data
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
// 设置初始思维导图数据
|
||||
|
||||
@@ -47,3 +47,13 @@ export const fileToBuffer = file => {
|
||||
reader.readAsArrayBuffer(file)
|
||||
})
|
||||
}
|
||||
|
||||
// 复制文本到剪贴板
|
||||
export const copy = (text) => {
|
||||
const input = document.createElement('input')
|
||||
input.setAttribute('value', text)
|
||||
document.body.appendChild(input)
|
||||
input.select()
|
||||
document.execCommand('copy')
|
||||
document.body.removeChild(input)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user