Demo:支持全屏编辑大纲
This commit is contained in:
parent
27885aabe7
commit
6bdcec0fca
@ -4,7 +4,7 @@
|
|||||||
<Count v-if="!isZenMode"></Count>
|
<Count v-if="!isZenMode"></Count>
|
||||||
<Navigator :mindMap="mindMap"></Navigator>
|
<Navigator :mindMap="mindMap"></Navigator>
|
||||||
<NavigatorToolbar :mindMap="mindMap" v-if="!isZenMode"></NavigatorToolbar>
|
<NavigatorToolbar :mindMap="mindMap" v-if="!isZenMode"></NavigatorToolbar>
|
||||||
<Outline :mindMap="mindMap"></Outline>
|
<OutlineSidebar :mindMap="mindMap"></OutlineSidebar>
|
||||||
<Style v-if="!isZenMode"></Style>
|
<Style v-if="!isZenMode"></Style>
|
||||||
<BaseStyle :data="mindMapData" :mindMap="mindMap"></BaseStyle>
|
<BaseStyle :data="mindMapData" :mindMap="mindMap"></BaseStyle>
|
||||||
<Theme v-if="mindMap" :mindMap="mindMap"></Theme>
|
<Theme v-if="mindMap" :mindMap="mindMap"></Theme>
|
||||||
@ -21,6 +21,7 @@
|
|||||||
<Search v-if="mindMap" :mindMap="mindMap"></Search>
|
<Search v-if="mindMap" :mindMap="mindMap"></Search>
|
||||||
<NodeIconSidebar v-if="mindMap" :mindMap="mindMap"></NodeIconSidebar>
|
<NodeIconSidebar v-if="mindMap" :mindMap="mindMap"></NodeIconSidebar>
|
||||||
<NodeIconToolbar v-if="mindMap" :mindMap="mindMap"></NodeIconToolbar>
|
<NodeIconToolbar v-if="mindMap" :mindMap="mindMap"></NodeIconToolbar>
|
||||||
|
<OutlineEdit v-if="mindMap" :mindMap="mindMap"></OutlineEdit>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -40,7 +41,7 @@ import TouchEvent from 'simple-mind-map/src/plugins/TouchEvent.js'
|
|||||||
import NodeImgAdjust from 'simple-mind-map/src/plugins/NodeImgAdjust.js'
|
import NodeImgAdjust from 'simple-mind-map/src/plugins/NodeImgAdjust.js'
|
||||||
import SearchPlugin from 'simple-mind-map/src/plugins/Search.js'
|
import SearchPlugin from 'simple-mind-map/src/plugins/Search.js'
|
||||||
import Painter from 'simple-mind-map/src/plugins/Painter.js'
|
import Painter from 'simple-mind-map/src/plugins/Painter.js'
|
||||||
import Outline from './Outline'
|
import OutlineSidebar from './OutlineSidebar'
|
||||||
import Style from './Style'
|
import Style from './Style'
|
||||||
import BaseStyle from './BaseStyle'
|
import BaseStyle from './BaseStyle'
|
||||||
import Theme from './Theme'
|
import Theme from './Theme'
|
||||||
@ -67,6 +68,7 @@ import i18n from '../../../i18n'
|
|||||||
import Search from './Search.vue'
|
import Search from './Search.vue'
|
||||||
import NodeIconSidebar from './NodeIconSidebar.vue'
|
import NodeIconSidebar from './NodeIconSidebar.vue'
|
||||||
import NodeIconToolbar from './NodeIconToolbar.vue'
|
import NodeIconToolbar from './NodeIconToolbar.vue'
|
||||||
|
import OutlineEdit from './OutlineEdit.vue'
|
||||||
|
|
||||||
// 注册插件
|
// 注册插件
|
||||||
MindMap
|
MindMap
|
||||||
@ -97,7 +99,7 @@ customThemeList.forEach((item) => {
|
|||||||
export default {
|
export default {
|
||||||
name: 'Edit',
|
name: 'Edit',
|
||||||
components: {
|
components: {
|
||||||
Outline,
|
OutlineSidebar,
|
||||||
Style,
|
Style,
|
||||||
BaseStyle,
|
BaseStyle,
|
||||||
Theme,
|
Theme,
|
||||||
@ -113,7 +115,8 @@ export default {
|
|||||||
SidebarTrigger,
|
SidebarTrigger,
|
||||||
Search,
|
Search,
|
||||||
NodeIconSidebar,
|
NodeIconSidebar,
|
||||||
NodeIconToolbar
|
NodeIconToolbar,
|
||||||
|
OutlineEdit
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -1,35 +1,32 @@
|
|||||||
<template>
|
<template>
|
||||||
<Sidebar ref="sidebar" :title="$t('outline.title')">
|
<el-tree
|
||||||
<el-tree
|
class="outlineTree"
|
||||||
class="outlineTree"
|
:class="{ isDark: isDark }"
|
||||||
:class="{ isDark: isDark }"
|
:data="data"
|
||||||
:data="data"
|
:props="defaultProps"
|
||||||
:props="defaultProps"
|
:expand-on-click-node="false"
|
||||||
:expand-on-click-node="false"
|
default-expand-all
|
||||||
default-expand-all
|
>
|
||||||
|
<span
|
||||||
|
class="customNode"
|
||||||
|
slot-scope="{ node, data }"
|
||||||
|
@click="onClick($event, node)"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="customNode"
|
class="nodeEdit"
|
||||||
slot-scope="{ node, data }"
|
:key="getKey()"
|
||||||
@click="onClick($event, node)"
|
contenteditable="true"
|
||||||
>
|
@keydown.stop="onKeydown($event, node)"
|
||||||
<span
|
@keyup.stop
|
||||||
class="nodeEdit"
|
@blur="onBlur($event, node)"
|
||||||
:key="getKey()"
|
@paste="onPaste($event, node)"
|
||||||
contenteditable="true"
|
v-html="node.label"
|
||||||
@keydown.stop="onKeydown($event, node)"
|
></span>
|
||||||
@keyup.stop
|
</span>
|
||||||
@blur="onBlur($event, node)"
|
</el-tree>
|
||||||
@paste="onPaste($event, node)"
|
|
||||||
v-html="node.label"
|
|
||||||
></span>
|
|
||||||
</span>
|
|
||||||
</el-tree>
|
|
||||||
</Sidebar>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Sidebar from './Sidebar'
|
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'vuex'
|
||||||
import {
|
import {
|
||||||
nodeRichTextToTextWithWrap,
|
nodeRichTextToTextWithWrap,
|
||||||
@ -37,16 +34,9 @@ import {
|
|||||||
getTextFromHtml
|
getTextFromHtml
|
||||||
} from 'simple-mind-map/src/utils'
|
} from 'simple-mind-map/src/utils'
|
||||||
|
|
||||||
/**
|
// 大纲树
|
||||||
* @Author: 王林
|
|
||||||
* @Date: 2021-06-24 22:54:14
|
|
||||||
* @Desc: 大纲内容
|
|
||||||
*/
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Outline',
|
name: 'Outline',
|
||||||
components: {
|
|
||||||
Sidebar
|
|
||||||
},
|
|
||||||
props: {
|
props: {
|
||||||
mindMap: {
|
mindMap: {
|
||||||
type: Object
|
type: Object
|
||||||
@ -69,16 +59,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['activeSidebar', 'isDark'])
|
...mapState(['isDark','isOutlineEdit'])
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
activeSidebar(val) {
|
|
||||||
if (val === 'outline') {
|
|
||||||
this.$refs.sidebar.show = true
|
|
||||||
} else {
|
|
||||||
this.$refs.sidebar.show = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.$bus.$on('data_change', data => {
|
this.$bus.$on('data_change', data => {
|
||||||
@ -91,6 +72,10 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
refresh() {
|
||||||
|
this.data = [this.mindMap.renderer.renderTree]
|
||||||
|
},
|
||||||
|
|
||||||
onBlur(e, node) {
|
onBlur(e, node) {
|
||||||
if (node.data.data.textCache === e.target.innerHTML) {
|
if (node.data.data.textCache === e.target.innerHTML) {
|
||||||
return
|
return
|
||||||
@ -187,6 +172,7 @@ export default {
|
|||||||
|
|
||||||
.nodeEdit {
|
.nodeEdit {
|
||||||
outline: none;
|
outline: none;
|
||||||
|
white-space: normal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
91
web/src/pages/Edit/components/OutlineEdit.vue
Normal file
91
web/src/pages/Edit/components/OutlineEdit.vue
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="outlineEditContainer"
|
||||||
|
ref="outlineEditContainer"
|
||||||
|
v-if="isOutlineEdit"
|
||||||
|
>
|
||||||
|
<div class="closeBtn" @click="onClose">
|
||||||
|
<span class="icon iconfont iconguanbi"></span>
|
||||||
|
</div>
|
||||||
|
<div class="outlineEdit">
|
||||||
|
<Outline :mindMap="mindMap" ref="outline"></Outline>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapState, mapMutations } from 'vuex'
|
||||||
|
import Outline from './Outline.vue'
|
||||||
|
|
||||||
|
// 大纲侧边栏
|
||||||
|
export default {
|
||||||
|
name: 'OutlineEdit',
|
||||||
|
components: {
|
||||||
|
Outline
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
mindMap: {
|
||||||
|
type: Object
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(['isOutlineEdit'])
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
isOutlineEdit(val) {
|
||||||
|
if (val) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.outline.refresh()
|
||||||
|
document.body.appendChild(this.$refs.outlineEditContainer)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapMutations(['setIsOutlineEdit']),
|
||||||
|
|
||||||
|
onClose() {
|
||||||
|
this.setIsOutlineEdit(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.outlineEditContainer {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 9999;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #fff;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 50px 0;
|
||||||
|
|
||||||
|
.closeBtn {
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
top: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.outlineEdit {
|
||||||
|
width: 1000px;
|
||||||
|
height: max-content;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
/deep/ .customNode {
|
||||||
|
.nodeEdit {
|
||||||
|
max-width: 800px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
56
web/src/pages/Edit/components/OutlineSidebar.vue
Normal file
56
web/src/pages/Edit/components/OutlineSidebar.vue
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<template>
|
||||||
|
<Sidebar ref="sidebar" :title="$t('outline.title')">
|
||||||
|
<div class="changeBtn" @click="onChangeToOutlineEdit">
|
||||||
|
<span class="icon iconfont iconquanping1"></span>
|
||||||
|
</div>
|
||||||
|
<Outline :mindMap="mindMap"></Outline>
|
||||||
|
</Sidebar>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Sidebar from './Sidebar'
|
||||||
|
import { mapState, mapMutations } from 'vuex'
|
||||||
|
import Outline from './Outline.vue'
|
||||||
|
|
||||||
|
// 大纲侧边栏
|
||||||
|
export default {
|
||||||
|
name: 'OutlineSidebar',
|
||||||
|
components: {
|
||||||
|
Sidebar,
|
||||||
|
Outline
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
mindMap: {
|
||||||
|
type: Object
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(['activeSidebar', 'isOutlineEdit'])
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
activeSidebar(val) {
|
||||||
|
if (val === 'outline') {
|
||||||
|
this.$refs.sidebar.show = true
|
||||||
|
} else {
|
||||||
|
this.$refs.sidebar.show = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapMutations(['setIsOutlineEdit']),
|
||||||
|
|
||||||
|
onChangeToOutlineEdit() {
|
||||||
|
this.setIsOutlineEdit(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.changeBtn {
|
||||||
|
position: absolute;
|
||||||
|
right: 50px;
|
||||||
|
top: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -19,6 +19,7 @@ const store = new Vuex.Store({
|
|||||||
},
|
},
|
||||||
activeSidebar: '', // 当前显示的侧边栏
|
activeSidebar: '', // 当前显示的侧边栏
|
||||||
isDark: false,// 是否是暗黑模式
|
isDark: false,// 是否是暗黑模式
|
||||||
|
isOutlineEdit: false// 是否是大纲编辑模式
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
/**
|
/**
|
||||||
@ -67,6 +68,11 @@ const store = new Vuex.Store({
|
|||||||
// 设置暗黑模式
|
// 设置暗黑模式
|
||||||
setIsDark(state, data) {
|
setIsDark(state, data) {
|
||||||
state.isDark = data
|
state.isDark = data
|
||||||
|
},
|
||||||
|
|
||||||
|
// 设置大纲编辑模式
|
||||||
|
setIsOutlineEdit(state, data) {
|
||||||
|
state.isOutlineEdit = data
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user