支持新建、打开、
This commit is contained in:
parent
0d81f9ff9c
commit
d1ab67cd4c
24
README.md
24
README.md
@ -30,7 +30,17 @@
|
|||||||
|
|
||||||
2.`web`
|
2.`web`
|
||||||
|
|
||||||
使用`simple-mind-map`工具库,基于`vue2.x`、`ElementUI`搭建的在线思维导图。
|
使用`simple-mind-map`工具库,基于`vue2.x`、`ElementUI`搭建的在线思维导图。特性:
|
||||||
|
|
||||||
|
- [x] 工具栏,支持插入节点、删除节点;编辑节点图片、图标、超链接、备注、标签、概要
|
||||||
|
|
||||||
|
- [x] 侧边栏,基础样式设置面板、节点样式设置面板、大纲面板、主题选择面板、结构选择面板
|
||||||
|
|
||||||
|
- [x] 导入导出功能;数据默认保存在浏览器本地存储,也支持直接创建、打开、编辑电脑本地文件
|
||||||
|
|
||||||
|
- [x] 右键菜单,支持展开、收起、整理布局等操作
|
||||||
|
|
||||||
|
- [x] 底部栏,支持节点数量、字数统计;支持切换编辑和只读模式;支持放大缩小;支持全屏切换
|
||||||
|
|
||||||
3.`dist`
|
3.`dist`
|
||||||
|
|
||||||
@ -91,7 +101,7 @@ npm run build
|
|||||||
|
|
||||||
# 安装
|
# 安装
|
||||||
|
|
||||||
> 当然仓库版本:0.2.8,当前npm版本:0.2.8
|
> 当然仓库版本:0.2.9,当前npm版本:0.2.9
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm i simple-mind-map
|
npm i simple-mind-map
|
||||||
@ -303,8 +313,6 @@ v0.1.7+。切换模式为只读或编辑。
|
|||||||
| RESET_LAYOUT(v0.2.0+) | 一键整理布局 | |
|
| RESET_LAYOUT(v0.2.0+) | 一键整理布局 | |
|
||||||
| SET_NODE_SHAPE(v0.2.4+) | 设置节点形状 | node(要设置的节点)、shape(形状,全部形状:https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/Shape.js) |
|
| SET_NODE_SHAPE(v0.2.4+) | 设置节点形状 | node(要设置的节点)、shape(形状,全部形状:https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/Shape.js) |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### setData(data)
|
#### setData(data)
|
||||||
|
|
||||||
动态设置思维导图数据,纯节点数据
|
动态设置思维导图数据,纯节点数据
|
||||||
@ -319,6 +327,14 @@ v0.2.7+
|
|||||||
|
|
||||||
`data`:完整数据,结构可参考[exportFullData](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exportFullData.json)
|
`data`:完整数据,结构可参考[exportFullData](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exportFullData.json)
|
||||||
|
|
||||||
|
#### getData(withConfig)
|
||||||
|
|
||||||
|
v0.2.9+
|
||||||
|
|
||||||
|
获取思维导图数据
|
||||||
|
|
||||||
|
`withConfig`:`Boolean`,默认为`false`,即获取的数据只包括节点树,如果传`true`则会包含主题、布局、视图等数据
|
||||||
|
|
||||||
#### export(type, isDownload, fileName)
|
#### export(type, isDownload, fileName)
|
||||||
|
|
||||||
导出
|
导出
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import {
|
|||||||
SVG
|
SVG
|
||||||
} from '@svgdotjs/svg.js'
|
} from '@svgdotjs/svg.js'
|
||||||
import xmind from './src/parse/xmind'
|
import xmind from './src/parse/xmind'
|
||||||
|
import { simpleDeepClone } from './src/utils';
|
||||||
|
|
||||||
// 默认选项配置
|
// 默认选项配置
|
||||||
const defaultOpt = {
|
const defaultOpt = {
|
||||||
@ -355,6 +356,31 @@ class MindMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2022-09-24 14:42:07
|
||||||
|
* @Desc: 获取思维导图数据,节点树、主题、布局等
|
||||||
|
*/
|
||||||
|
getData(withConfig) {
|
||||||
|
let nodeData = this.command.getCopyData()
|
||||||
|
let data = {}
|
||||||
|
if (withConfig) {
|
||||||
|
data = {
|
||||||
|
layout: this.getLayout(),
|
||||||
|
root: nodeData,
|
||||||
|
theme: {
|
||||||
|
template: this.getTheme(),
|
||||||
|
config: this.getCustomThemeConfig()
|
||||||
|
},
|
||||||
|
view: this.view.getTransformData()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data = nodeData
|
||||||
|
}
|
||||||
|
return simpleDeepClone(data)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: 王林
|
* @Author: 王林
|
||||||
* @Date: 2021-07-01 22:06:38
|
* @Date: 2021-07-01 22:06:38
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "simple-mind-map",
|
"name": "simple-mind-map",
|
||||||
"version": "0.2.8",
|
"version": "0.2.9",
|
||||||
"description": "一个简单的web在线思维导图",
|
"description": "一个简单的web在线思维导图",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -249,21 +249,7 @@ class Export {
|
|||||||
* @Desc: 导出为json
|
* @Desc: 导出为json
|
||||||
*/
|
*/
|
||||||
json (name, withConfig = true) {
|
json (name, withConfig = true) {
|
||||||
let nodeData = this.mindMap.command.getCopyData()
|
let data = this.mindMap.getData(withConfig)
|
||||||
let data = {}
|
|
||||||
if (withConfig) {
|
|
||||||
data = {
|
|
||||||
layout: this.mindMap.getLayout(),
|
|
||||||
root: nodeData,
|
|
||||||
theme: {
|
|
||||||
template: this.mindMap.getTheme(),
|
|
||||||
config: this.mindMap.getCustomThemeConfig()
|
|
||||||
},
|
|
||||||
view: this.mindMap.view.getTransformData()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
data = nodeData
|
|
||||||
}
|
|
||||||
let str = JSON.stringify(data)
|
let str = JSON.stringify(data)
|
||||||
let blob = new Blob([str])
|
let blob = new Blob([str])
|
||||||
return URL.createObjectURL(blob)
|
return URL.createObjectURL(blob)
|
||||||
|
|||||||
BIN
web/src/.DS_Store
vendored
BIN
web/src/.DS_Store
vendored
Binary file not shown.
@ -1,5 +1,6 @@
|
|||||||
import exampleData from "simple-mind-map/example/exampleData"
|
import exampleData from "simple-mind-map/example/exampleData"
|
||||||
import { simpleDeepClone } from 'simple-mind-map/src/utils/index'
|
import { simpleDeepClone } from 'simple-mind-map/src/utils/index'
|
||||||
|
import Vue from 'vue'
|
||||||
|
|
||||||
const SIMPLE_MIND_MAP_DATA = 'SIMPLE_MIND_MAP_DATA'
|
const SIMPLE_MIND_MAP_DATA = 'SIMPLE_MIND_MAP_DATA'
|
||||||
|
|
||||||
@ -47,6 +48,7 @@ export const storeData = (data) => {
|
|||||||
try {
|
try {
|
||||||
let originData = getData()
|
let originData = getData()
|
||||||
originData.root = copyMindMapTreeData({}, data)
|
originData.root = copyMindMapTreeData({}, data)
|
||||||
|
Vue.prototype.$bus.$emit('write_local_file', originData)
|
||||||
let dataStr = JSON.stringify(originData)
|
let dataStr = JSON.stringify(originData)
|
||||||
localStorage.setItem(SIMPLE_MIND_MAP_DATA, dataStr)
|
localStorage.setItem(SIMPLE_MIND_MAP_DATA, dataStr)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -66,6 +68,7 @@ export const storeConfig = (config) => {
|
|||||||
...originData,
|
...originData,
|
||||||
...config
|
...config
|
||||||
}
|
}
|
||||||
|
Vue.prototype.$bus.$emit('write_local_file', originData)
|
||||||
let dataStr = JSON.stringify(originData)
|
let dataStr = JSON.stringify(originData)
|
||||||
localStorage.setItem(SIMPLE_MIND_MAP_DATA, dataStr)
|
localStorage.setItem(SIMPLE_MIND_MAP_DATA, dataStr)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
BIN
web/src/assets/.DS_Store
vendored
BIN
web/src/assets/.DS_Store
vendored
Binary file not shown.
BIN
web/src/assets/icon-font/.DS_Store
vendored
BIN
web/src/assets/icon-font/.DS_Store
vendored
Binary file not shown.
@ -3,8 +3,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<title>iconfont Demo</title>
|
<title>iconfont Demo</title>
|
||||||
<link rel="shortcut icon" href="//img.alicdn.com/imgextra/i2/O1CN01ZyAlrn1MwaMhqz36G_!!6000000001499-73-tps-64-64.ico" type="image/x-icon"/>
|
<link rel="shortcut icon" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg" type="image/x-icon"/>
|
||||||
<link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01EYTRnJ297D6vehehJ_!!6000000008020-55-tps-64-64.svg"/>
|
<link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg"/>
|
||||||
<link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
|
<link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
|
||||||
<link rel="stylesheet" href="demo.css">
|
<link rel="stylesheet" href="demo.css">
|
||||||
<link rel="stylesheet" href="iconfont.css">
|
<link rel="stylesheet" href="iconfont.css">
|
||||||
@ -54,6 +54,36 @@
|
|||||||
<div class="content unicode" style="display: block;">
|
<div class="content unicode" style="display: block;">
|
||||||
<ul class="icon_lists dib-box">
|
<ul class="icon_lists dib-box">
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont"></span>
|
||||||
|
<div class="name">导出</div>
|
||||||
|
<div class="code-name">&#xe63e;</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont"></span>
|
||||||
|
<div class="name">另存为</div>
|
||||||
|
<div class="code-name">&#xe657;</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont"></span>
|
||||||
|
<div class="name">export</div>
|
||||||
|
<div class="code-name">&#xe642;</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont"></span>
|
||||||
|
<div class="name">打开</div>
|
||||||
|
<div class="code-name">&#xebdf;</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont"></span>
|
||||||
|
<div class="name">新建</div>
|
||||||
|
<div class="code-name">&#xe64e;</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li class="dib">
|
<li class="dib">
|
||||||
<span class="icon iconfont"></span>
|
<span class="icon iconfont"></span>
|
||||||
<div class="name">剪切</div>
|
<div class="name">剪切</div>
|
||||||
@ -300,9 +330,9 @@
|
|||||||
<pre><code class="language-css"
|
<pre><code class="language-css"
|
||||||
>@font-face {
|
>@font-face {
|
||||||
font-family: 'iconfont';
|
font-family: 'iconfont';
|
||||||
src: url('iconfont.woff2?t=1659615576455') format('woff2'),
|
src: url('iconfont.woff2?t=1664005697217') format('woff2'),
|
||||||
url('iconfont.woff?t=1659615576455') format('woff'),
|
url('iconfont.woff?t=1664005697217') format('woff'),
|
||||||
url('iconfont.ttf?t=1659615576455') format('truetype');
|
url('iconfont.ttf?t=1664005697217') format('truetype');
|
||||||
}
|
}
|
||||||
</code></pre>
|
</code></pre>
|
||||||
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
|
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
|
||||||
@ -328,6 +358,51 @@
|
|||||||
<div class="content font-class">
|
<div class="content font-class">
|
||||||
<ul class="icon_lists dib-box">
|
<ul class="icon_lists dib-box">
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont icondaochu1"></span>
|
||||||
|
<div class="name">
|
||||||
|
导出
|
||||||
|
</div>
|
||||||
|
<div class="code-name">.icondaochu1
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont iconlingcunwei"></span>
|
||||||
|
<div class="name">
|
||||||
|
另存为
|
||||||
|
</div>
|
||||||
|
<div class="code-name">.iconlingcunwei
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont iconexport"></span>
|
||||||
|
<div class="name">
|
||||||
|
export
|
||||||
|
</div>
|
||||||
|
<div class="code-name">.iconexport
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont icondakai"></span>
|
||||||
|
<div class="name">
|
||||||
|
打开
|
||||||
|
</div>
|
||||||
|
<div class="code-name">.icondakai
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont iconxinjian"></span>
|
||||||
|
<div class="name">
|
||||||
|
新建
|
||||||
|
</div>
|
||||||
|
<div class="code-name">.iconxinjian
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li class="dib">
|
<li class="dib">
|
||||||
<span class="icon iconfont iconjianqie"></span>
|
<span class="icon iconfont iconjianqie"></span>
|
||||||
<div class="name">
|
<div class="name">
|
||||||
@ -697,6 +772,46 @@
|
|||||||
<div class="content symbol">
|
<div class="content symbol">
|
||||||
<ul class="icon_lists dib-box">
|
<ul class="icon_lists dib-box">
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<svg class="icon svg-icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icondaochu1"></use>
|
||||||
|
</svg>
|
||||||
|
<div class="name">导出</div>
|
||||||
|
<div class="code-name">#icondaochu1</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<svg class="icon svg-icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#iconlingcunwei"></use>
|
||||||
|
</svg>
|
||||||
|
<div class="name">另存为</div>
|
||||||
|
<div class="code-name">#iconlingcunwei</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<svg class="icon svg-icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#iconexport"></use>
|
||||||
|
</svg>
|
||||||
|
<div class="name">export</div>
|
||||||
|
<div class="code-name">#iconexport</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<svg class="icon svg-icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icondakai"></use>
|
||||||
|
</svg>
|
||||||
|
<div class="name">打开</div>
|
||||||
|
<div class="code-name">#icondakai</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<svg class="icon svg-icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#iconxinjian"></use>
|
||||||
|
</svg>
|
||||||
|
<div class="name">新建</div>
|
||||||
|
<div class="code-name">#iconxinjian</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li class="dib">
|
<li class="dib">
|
||||||
<svg class="icon svg-icon" aria-hidden="true">
|
<svg class="icon svg-icon" aria-hidden="true">
|
||||||
<use xlink:href="#iconjianqie"></use>
|
<use xlink:href="#iconjianqie"></use>
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: "iconfont"; /* Project id 2479351 */
|
font-family: "iconfont"; /* Project id 2479351 */
|
||||||
src: url('iconfont.woff2?t=1659615576455') format('woff2'),
|
src: url('iconfont.woff2?t=1664005697217') format('woff2'),
|
||||||
url('iconfont.woff?t=1659615576455') format('woff'),
|
url('iconfont.woff?t=1664005697217') format('woff'),
|
||||||
url('iconfont.ttf?t=1659615576455') format('truetype');
|
url('iconfont.ttf?t=1664005697217') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
.iconfont {
|
||||||
@ -13,6 +13,26 @@
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icondaochu1:before {
|
||||||
|
content: "\e63e";
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconlingcunwei:before {
|
||||||
|
content: "\e657";
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconexport:before {
|
||||||
|
content: "\e642";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icondakai:before {
|
||||||
|
content: "\ebdf";
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconxinjian:before {
|
||||||
|
content: "\e64e";
|
||||||
|
}
|
||||||
|
|
||||||
.iconjianqie:before {
|
.iconjianqie:before {
|
||||||
content: "\e601";
|
content: "\e601";
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -5,6 +5,41 @@
|
|||||||
"css_prefix_text": "icon",
|
"css_prefix_text": "icon",
|
||||||
"description": "思维导图",
|
"description": "思维导图",
|
||||||
"glyphs": [
|
"glyphs": [
|
||||||
|
{
|
||||||
|
"icon_id": "1305460",
|
||||||
|
"name": "导出",
|
||||||
|
"font_class": "daochu1",
|
||||||
|
"unicode": "e63e",
|
||||||
|
"unicode_decimal": 58942
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "4784101",
|
||||||
|
"name": "另存为",
|
||||||
|
"font_class": "lingcunwei",
|
||||||
|
"unicode": "e657",
|
||||||
|
"unicode_decimal": 58967
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "9929033",
|
||||||
|
"name": "export",
|
||||||
|
"font_class": "export",
|
||||||
|
"unicode": "e642",
|
||||||
|
"unicode_decimal": 58946
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "4570294",
|
||||||
|
"name": "打开",
|
||||||
|
"font_class": "dakai",
|
||||||
|
"unicode": "ebdf",
|
||||||
|
"unicode_decimal": 60383
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "5086088",
|
||||||
|
"name": "新建",
|
||||||
|
"font_class": "xinjian",
|
||||||
|
"unicode": "e64e",
|
||||||
|
"unicode_decimal": 58958
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"icon_id": "1117",
|
"icon_id": "1117",
|
||||||
"name": "剪切",
|
"name": "剪切",
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -154,12 +154,8 @@ export default {
|
|||||||
if (this.openTest) {
|
if (this.openTest) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let data = this.mindMap.command.getCopyData()
|
let data = this.mindMap.getData(true)
|
||||||
storeData(data)
|
storeConfig(data)
|
||||||
let viewData = this.mindMap.view.getTransformData()
|
|
||||||
storeConfig({
|
|
||||||
view: viewData,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -82,6 +82,7 @@ export default {
|
|||||||
if (this.fileList.length <= 0) {
|
if (this.fileList.length <= 0) {
|
||||||
return this.$message.error("请选择要导入的文件");
|
return this.$message.error("请选择要导入的文件");
|
||||||
}
|
}
|
||||||
|
this.$store.commit('setIsHandleLocalFile', false);
|
||||||
let file = this.fileList[0];
|
let file = this.fileList[0];
|
||||||
if (/\.(smm|json)$/.test(file.name)) {
|
if (/\.(smm|json)$/.test(file.name)) {
|
||||||
this.handleSmm(file)
|
this.handleSmm(file)
|
||||||
|
|||||||
@ -135,12 +135,24 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- 导出 -->
|
<!-- 导出 -->
|
||||||
<div class="toolbarBlock">
|
<div class="toolbarBlock">
|
||||||
|
<div class="toolbarBtn" @click="createNewLocalFile">
|
||||||
|
<span class="icon iconfont iconxinjian"></span>
|
||||||
|
<span class="text">新建</span>
|
||||||
|
</div>
|
||||||
|
<div class="toolbarBtn" @click="openLocalFile">
|
||||||
|
<span class="icon iconfont icondakai"></span>
|
||||||
|
<span class="text">打开</span>
|
||||||
|
</div>
|
||||||
|
<div class="toolbarBtn" @click="saveLocalFile">
|
||||||
|
<span class="icon iconfont iconlingcunwei"></span>
|
||||||
|
<span class="text">另存为</span>
|
||||||
|
</div>
|
||||||
<div class="toolbarBtn" @click="$bus.$emit('showImport')">
|
<div class="toolbarBtn" @click="$bus.$emit('showImport')">
|
||||||
<span class="icon iconfont icondaoru"></span>
|
<span class="icon iconfont icondaoru"></span>
|
||||||
<span class="text">导入</span>
|
<span class="text">导入</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="toolbarBtn" @click="$bus.$emit('showExport')">
|
<div class="toolbarBtn" @click="$bus.$emit('showExport')">
|
||||||
<span class="icon iconfont icondaochu"></span>
|
<span class="icon iconfont iconexport"></span>
|
||||||
<span class="text">导出</span>
|
<span class="text">导出</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="toolbarBtn" @click="$bus.$emit('showShortcutKey')">
|
<div class="toolbarBtn" @click="$bus.$emit('showShortcutKey')">
|
||||||
@ -167,12 +179,17 @@ import NodeNote from "./NodeNote";
|
|||||||
import NodeTag from "./NodeTag";
|
import NodeTag from "./NodeTag";
|
||||||
import Export from "./Export";
|
import Export from "./Export";
|
||||||
import Import from './Import';
|
import Import from './Import';
|
||||||
|
import { mapState } from 'vuex';
|
||||||
|
import { Notification } from 'element-ui';
|
||||||
|
import exampleData from 'simple-mind-map/example/exampleData';
|
||||||
|
import { getData } from '../../../api';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: 王林
|
* @Author: 王林
|
||||||
* @Date: 2021-06-24 22:54:58
|
* @Date: 2021-06-24 22:54:58
|
||||||
* @Desc: 工具栏
|
* @Desc: 工具栏
|
||||||
*/
|
*/
|
||||||
|
let fileHandle = null;
|
||||||
export default {
|
export default {
|
||||||
name: "Toolbar",
|
name: "Toolbar",
|
||||||
components: {
|
components: {
|
||||||
@ -189,10 +206,13 @@ export default {
|
|||||||
activeNodes: [],
|
activeNodes: [],
|
||||||
backEnd: false,
|
backEnd: false,
|
||||||
forwardEnd: true,
|
forwardEnd: true,
|
||||||
readonly: false
|
readonly: false,
|
||||||
|
isFullDataFile: false,
|
||||||
|
timer: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
...mapState(['isHandleLocalFile']),
|
||||||
hasRoot() {
|
hasRoot() {
|
||||||
return this.activeNodes.findIndex((node) => {
|
return this.activeNodes.findIndex((node) => {
|
||||||
return node.isRoot;
|
return node.isRoot;
|
||||||
@ -204,6 +224,13 @@ export default {
|
|||||||
}) !== -1;;
|
}) !== -1;;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
isHandleLocalFile(val) {
|
||||||
|
if (!val) {
|
||||||
|
Notification.closeAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
created() {
|
created() {
|
||||||
this.$bus.$on("mode_change", (mode) => {
|
this.$bus.$on("mode_change", (mode) => {
|
||||||
this.readonly = mode === 'readonly'
|
this.readonly = mode === 'readonly'
|
||||||
@ -215,7 +242,168 @@ export default {
|
|||||||
this.backEnd = index <= 0
|
this.backEnd = index <= 0
|
||||||
this.forwardEnd = index >= len - 1
|
this.forwardEnd = index >= len - 1
|
||||||
});
|
});
|
||||||
|
this.$bus.$on("write_local_file", (content) => {
|
||||||
|
clearTimeout(this.timer);
|
||||||
|
this.timer = setTimeout(() => {
|
||||||
|
this.writeLocalFile(content);
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2022-09-24 15:40:09
|
||||||
|
* @Desc: 打开本地文件
|
||||||
|
*/
|
||||||
|
async openLocalFile() {
|
||||||
|
try {
|
||||||
|
let [ _fileHandle ] = await window.showOpenFilePicker({
|
||||||
|
types: [
|
||||||
|
{
|
||||||
|
description: 'file',
|
||||||
|
accept: {
|
||||||
|
'application/*': ['.json', '.smm']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
excludeAcceptAllOption: true,
|
||||||
|
multiple: false
|
||||||
|
});
|
||||||
|
if (!_fileHandle) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fileHandle = _fileHandle;
|
||||||
|
if (fileHandle.kind === 'directory') {
|
||||||
|
this.$message.warning('请选择文件');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.readFile();
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
this.$message.warning('你的浏览器可能不支持哦');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2022-09-24 15:40:18
|
||||||
|
* @Desc: 读取本地文件
|
||||||
|
*/
|
||||||
|
async readFile() {
|
||||||
|
let file = await fileHandle.getFile();
|
||||||
|
let fileReader = new FileReader();
|
||||||
|
fileReader.onload = async () => {
|
||||||
|
this.$store.commit('setIsHandleLocalFile', true);
|
||||||
|
this.setData(fileReader.result);
|
||||||
|
Notification.closeAll();
|
||||||
|
Notification({
|
||||||
|
title: '提示',
|
||||||
|
message: `当前正在编辑你本机的【${ file.name }】文件`,
|
||||||
|
duration: 0,
|
||||||
|
showClose: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fileReader.readAsText(file);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2022-09-24 15:40:26
|
||||||
|
* @Desc: 渲染读取的数据
|
||||||
|
*/
|
||||||
|
setData(str) {
|
||||||
|
try {
|
||||||
|
let data = JSON.parse(str);
|
||||||
|
if (typeof data !== 'object') {
|
||||||
|
throw new Error('文件内容有误');
|
||||||
|
}
|
||||||
|
if (data.root) {
|
||||||
|
this.isFullDataFile = true;
|
||||||
|
} else {
|
||||||
|
this.isFullDataFile = false;
|
||||||
|
data = {
|
||||||
|
...exampleData,
|
||||||
|
root: data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.$bus.$emit('setData', data);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
this.$message.error("文件打开失败");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2022-09-24 15:40:42
|
||||||
|
* @Desc: 写入本地文件
|
||||||
|
*/
|
||||||
|
async writeLocalFile(content) {
|
||||||
|
if (!fileHandle || !this.isHandleLocalFile) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this.isFullDataFile) {
|
||||||
|
content = content.root;
|
||||||
|
}
|
||||||
|
let string = JSON.stringify(content);
|
||||||
|
const writable = await fileHandle.createWritable();
|
||||||
|
await writable.write(string);
|
||||||
|
await writable.close();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2022-09-24 15:40:48
|
||||||
|
* @Desc: 创建本地文件
|
||||||
|
*/
|
||||||
|
async createNewLocalFile() {
|
||||||
|
await this.createLocalFile(exampleData);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2022-09-24 15:49:17
|
||||||
|
* @Desc: 另存为
|
||||||
|
*/
|
||||||
|
async saveLocalFile() {
|
||||||
|
let data = getData();
|
||||||
|
await this.createLocalFile(data);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2022-09-24 15:50:22
|
||||||
|
* @Desc: 创建本地文件
|
||||||
|
*/
|
||||||
|
async createLocalFile(content) {
|
||||||
|
try {
|
||||||
|
let _fileHandle = await window.showSaveFilePicker({
|
||||||
|
types: [{
|
||||||
|
description: 'file',
|
||||||
|
accept: {'application/*': ['.json', '.smm']},
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
if (!_fileHandle) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const loading = this.$loading({
|
||||||
|
lock: true,
|
||||||
|
text: '正在创建文件',
|
||||||
|
spinner: 'el-icon-loading',
|
||||||
|
background: 'rgba(0, 0, 0, 0.7)'
|
||||||
|
});
|
||||||
|
fileHandle = _fileHandle;
|
||||||
|
this.$store.commit('setIsHandleLocalFile', true);
|
||||||
|
this.isFullDataFile = true;
|
||||||
|
await this.writeLocalFile(content);
|
||||||
|
await this.readFile();
|
||||||
|
loading.close();
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
this.$message.warning('你的浏览器可能不支持哦');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,8 @@ Vue.use(Vuex)
|
|||||||
|
|
||||||
const store = new Vuex.Store({
|
const store = new Vuex.Store({
|
||||||
state: {
|
state: {
|
||||||
mindMapData: null // 思维导图数据
|
mindMapData: null, // 思维导图数据
|
||||||
|
isHandleLocalFile: false// 是否操作的是本地文件
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
/**
|
/**
|
||||||
@ -16,6 +17,16 @@ const store = new Vuex.Store({
|
|||||||
*/
|
*/
|
||||||
setMindMapData(state, data) {
|
setMindMapData(state, data) {
|
||||||
state.mindMapData = data
|
state.mindMapData = data
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2022-09-24 13:55:38
|
||||||
|
* @Desc: 设置操作本地文件标志位
|
||||||
|
*/
|
||||||
|
setIsHandleLocalFile(state, data) {
|
||||||
|
state.isHandleLocalFile = data
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user