Demo:支持点击节点内的图标显示一个图标快捷替换和删除悬浮面板
This commit is contained in:
parent
20eba7b29b
commit
78f5d4ec88
@ -65,7 +65,7 @@ function createIconNode() {
|
|||||||
}
|
}
|
||||||
node.size(iconSize, iconSize)
|
node.size(iconSize, iconSize)
|
||||||
node.on('click', e => {
|
node.on('click', e => {
|
||||||
this.mindMap.emit('node_icon_click', this, e)
|
this.mindMap.emit('node_icon_click', this, item, e)
|
||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
node,
|
node,
|
||||||
|
|||||||
@ -19,7 +19,8 @@
|
|||||||
<NodeImgPreview v-if="mindMap" :mindMap="mindMap"></NodeImgPreview>
|
<NodeImgPreview v-if="mindMap" :mindMap="mindMap"></NodeImgPreview>
|
||||||
<SidebarTrigger v-if="!isZenMode"></SidebarTrigger>
|
<SidebarTrigger v-if="!isZenMode"></SidebarTrigger>
|
||||||
<Search v-if="mindMap" :mindMap="mindMap"></Search>
|
<Search v-if="mindMap" :mindMap="mindMap"></Search>
|
||||||
<NodeIconSidebar></NodeIconSidebar>
|
<NodeIconSidebar v-if="mindMap" :mindMap="mindMap"></NodeIconSidebar>
|
||||||
|
<NodeIconToolbar v-if="mindMap" :mindMap="mindMap"></NodeIconToolbar>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -64,6 +65,7 @@ import store from '../../../store'
|
|||||||
import i18n from '../../../i18n'
|
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'
|
||||||
|
|
||||||
// 注册插件
|
// 注册插件
|
||||||
MindMap
|
MindMap
|
||||||
@ -108,7 +110,8 @@ export default {
|
|||||||
NodeImgPreview,
|
NodeImgPreview,
|
||||||
SidebarTrigger,
|
SidebarTrigger,
|
||||||
Search,
|
Search,
|
||||||
NodeIconSidebar
|
NodeIconSidebar,
|
||||||
|
NodeIconToolbar
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -37,14 +37,13 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Sidebar from './Sidebar'
|
import Sidebar from './Sidebar'
|
||||||
import { shortcutKeyList } from '@/config'
|
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'vuex'
|
||||||
import { nodeIconList } from 'simple-mind-map/src/svg/icons'
|
import { nodeIconList } from 'simple-mind-map/src/svg/icons'
|
||||||
import icon from '@/config/icon'
|
import icon from '@/config/icon'
|
||||||
import image from '@/config/image'
|
import image from '@/config/image'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ShortcutKey',
|
name: 'NodeIconSidebar',
|
||||||
components: {
|
components: {
|
||||||
Sidebar
|
Sidebar
|
||||||
},
|
},
|
||||||
|
|||||||
212
web/src/pages/Edit/components/NodeIconToolbar.vue
Normal file
212
web/src/pages/Edit/components/NodeIconToolbar.vue
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
<template>
|
||||||
|
<div class="nodeIconToolbar" ref="nodeIconToolbar" :style="style" @click.stop.passive v-show="showNodeIconToolbar">
|
||||||
|
<div class="iconListBox">
|
||||||
|
<div class="icon" v-for="icon in iconList" :key="icon.name" v-html="getHtml(icon.icon)" :class="{
|
||||||
|
selected: nodeIconList.includes(iconType + '_' + icon.name)
|
||||||
|
}" @click="setIcon(icon.name)"></div>
|
||||||
|
</div>
|
||||||
|
<div class="btnBox">
|
||||||
|
<span class="btn iconfont iconshanchu" @click="deleteIcon"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { nodeIconList as _nodeIconList } from 'simple-mind-map/src/svg/icons'
|
||||||
|
import icon from '@/config/icon'
|
||||||
|
import { mapState, mapMutations } from 'vuex'
|
||||||
|
|
||||||
|
const allIconList = [..._nodeIconList, ...icon]
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'NodeIconToolbar',
|
||||||
|
components: {
|
||||||
|
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
mindMap: {
|
||||||
|
type: Object
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showNodeIconToolbar: false,
|
||||||
|
style: {
|
||||||
|
left: 0,
|
||||||
|
top: 0
|
||||||
|
},
|
||||||
|
node: null,
|
||||||
|
iconType: '',
|
||||||
|
iconName: '',
|
||||||
|
nodeIconList: [],
|
||||||
|
iconList: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(['activeSidebar']),
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.mindMap.on('node_icon_click', this.show)
|
||||||
|
this.mindMap.on('draw_click', this.close)
|
||||||
|
this.mindMap.on('svg_mousedown', this.close)
|
||||||
|
this.mindMap.on('node_dblclick', this.close)
|
||||||
|
this.mindMap.on('node_active', this.onNodeActive)
|
||||||
|
this.$bus.$on('close_node_icon_toolbar', this.close)
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
document.body.append(this.$refs.nodeIconToolbar)
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
this.mindMap.off('node_icon_click', this.show)
|
||||||
|
this.mindMap.off('draw_click', this.close)
|
||||||
|
this.mindMap.off('svg_mousedown', this.close)
|
||||||
|
this.mindMap.off('node_dblclick', this.close)
|
||||||
|
this.mindMap.off('node_active', this.onNodeActive)
|
||||||
|
this.$bus.$off('close_node_icon_toolbar', this.close)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapMutations(['setActiveSidebar']),
|
||||||
|
|
||||||
|
show(node, icon) {
|
||||||
|
this.node = node
|
||||||
|
this.iconType = icon.split('_')[0]
|
||||||
|
this.iconName = icon.split('_')[1]
|
||||||
|
this.nodeIconList = node.getData('icon') || []
|
||||||
|
this.iconList = [...allIconList.find((item) => {
|
||||||
|
return item.type === this.iconType
|
||||||
|
}).list]
|
||||||
|
let rect = node.group.rbox()
|
||||||
|
this.style.left = rect.x + 'px'
|
||||||
|
this.style.top = rect.y + rect.height + 'px'
|
||||||
|
this.showNodeIconToolbar = true
|
||||||
|
if (this.activeSidebar === 'nodeIconSidebar') {
|
||||||
|
this.setActiveSidebar('')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.showNodeIconToolbar = false
|
||||||
|
this.node = null
|
||||||
|
this.iconType = ''
|
||||||
|
this.iconName = ''
|
||||||
|
this.nodeIconList = []
|
||||||
|
this.iconList = []
|
||||||
|
this.style.left = 0
|
||||||
|
this.style.top = 0
|
||||||
|
},
|
||||||
|
|
||||||
|
onNodeActive(node) {
|
||||||
|
if (node === this.node) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.close()
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteIcon() {
|
||||||
|
this.setIcon(this.iconName)
|
||||||
|
this.close()
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取图标渲染方式
|
||||||
|
getHtml(icon) {
|
||||||
|
return /^<svg/.test(icon) ? icon : `<img src="${icon}" />`
|
||||||
|
},
|
||||||
|
|
||||||
|
// 设置icon
|
||||||
|
setIcon(name) {
|
||||||
|
let key = this.iconType + '_' + name
|
||||||
|
let index = this.nodeIconList.findIndex(item => {
|
||||||
|
return item === key
|
||||||
|
})
|
||||||
|
// 删除icon
|
||||||
|
if (index !== -1) {
|
||||||
|
this.nodeIconList.splice(index, 1)
|
||||||
|
} else {
|
||||||
|
let typeIndex = this.nodeIconList.findIndex(item => {
|
||||||
|
return item.split('_')[0] === this.iconType
|
||||||
|
})
|
||||||
|
// 替换icon
|
||||||
|
if (typeIndex !== -1) {
|
||||||
|
this.nodeIconList.splice(typeIndex, 1, key)
|
||||||
|
this.iconName = name
|
||||||
|
} else {
|
||||||
|
// 增加icon
|
||||||
|
this.nodeIconList.push(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.node.setIcon([...this.nodeIconList])
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.nodeIconToolbar {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 2000;
|
||||||
|
width: 210px;
|
||||||
|
max-height: 170px;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.06);
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 16px 0 rgba(0, 0, 0, 0.06);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.iconListBox {
|
||||||
|
width: 100%;
|
||||||
|
height: 180px;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 10px;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
margin: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
float: left;
|
||||||
|
|
||||||
|
/deep/ img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ svg {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: -4px;
|
||||||
|
top: -4px;
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 2px solid #409eff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btnBox {
|
||||||
|
width: 100%;
|
||||||
|
height: 30px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
cursor: pointer;
|
||||||
|
color: rgba(26, 26, 26, 0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
@ -239,6 +239,7 @@ export default {
|
|||||||
|
|
||||||
showNodeIcon() {
|
showNodeIcon() {
|
||||||
// this.$bus.$emit('showNodeIcon')
|
// this.$bus.$emit('showNodeIcon')
|
||||||
|
this.$bus.$emit('close_node_icon_toolbar')
|
||||||
this.setActiveSidebar('nodeIconSidebar')
|
this.setActiveSidebar('nodeIconSidebar')
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user