使用 HTML + jsmind 实现在线思维导图

在日常工作和学习中,思维导图是一种非常有效的可视化工具,可以帮助我们梳理思路、规划任务、整理知识结构。本文将带你一步步了解如何使用 HTML 和 jsmind 实现一个基础的在线思维导图应用。

效果演示

image-20250527223000780

image-20250527223032429

项目概述

本项目主要包含以下核心功能:

  • 初始化思维导图
  • 添加子节点、删除节点、编辑节点内容
  • 保存数据到本地存储,刷新页面后数据不丢失
  • 导出思维导图数据为 JSON 文件
  • 导入 JSON 数据
  • 保存为图片

准备工作

下载 jsmind 文件,项目中引入以下主要文件:jsmind.css、jsmind.js、jsmind.draggable-node.js、jsmind.screenshot.js。

jsmind 下载地址:https://github.com/hizzgdev/jsmind

<link type="text/css" rel="stylesheet" href="./jsmind.css" />
<script src="./jsmind.js"></script>
<script src="./jsmind.draggable-node.js"></script>
<script src="./jsmind.screenshot.js"></script>

页面结构与样式设计

创建 HTML 结构
<!-- 工具栏 -->
<div class="toolbar">
    <button onclick="addNode()">添加子节点</button>
    <button onclick="removeNode()">删除节点</button>
    <button onclick="editNode()">编辑节点</button>
    <button onclick="saveDataToLocal()">保存</button>
    <button onclick="downloadData()">导出</button>
    <button onclick="saveAsImage()">保存为图片</button>
    <input type="file" id="importFile" accept=".json" style="display: none;" onchange="importDataFromFile(event)">
    <label for="importFile" class="button">导入数据</label>
</div>
<!-- 思维导图容器 -->
<div id="jsmind_container"></div>
设计 CSS 样式
body {
    margin: 0;
    padding: 0;
}
#jsmind_container {
    width: 100vw;
    height: 100vh;
    overflow: auto;
    box-sizing: border-box;
    top: 0;
}
.toolbar {
    position: fixed;
    top: 10px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 1000;
    display: flex;
    gap: 10px;
}
.toolbar button,.toolbar .button {
    padding: 8px 16px;
    border: none;
    border-radius: 4px;
    background-color: #007bff;
    color: white;
    cursor: pointer;
    transition: background-color 0.3s ease;
}
.toolbar button:hover {
    background-color: #0056b3;
}

核心功能实现

初始化思维导图

使用 jsMind 初始化一个可编辑的思维导图实例,支持从浏览器本地存储(localStorage)中加载上次保存的数据。

// 初始化思维导图
let jm = null;
const initMindMap = () => {
    const options = {
        container: 'jsmind_container',
        editable: true,
        theme: 'white',
    };

    // 初始数据
    let data = {
        "meta": {
            "name": "示例思维导图",
            "author": "user",
            "version": "1.0"
        },
        "format": "node_tree",
        "data": {
            "id": "root",
            "topic": "中心主题",
            "children": [
            ]
        }
    };
    const savedData = localStorage.getItem('mindmapData');
    if (savedData) {
        try {
            data = JSON.parse(savedData);
        } catch (e) {
            console.error("解析本地数据失败", e);
        }
    }
    jm = new jsMind(options);
    jm.show(data);
}
window.onload = initMindMap;
添加子节点
function addNode() {
    const selectedNode = jm.get_selected_node();
    if (selectedNode) {
        const nodeId = Date.now().toString();
        jm.add_node(selectedNode.id, nodeId, '新增子节点', {});
    }
}
删除节点
function removeNode() {
    const selectedNode = jm.get_selected_node();
    if (selectedNode && selectedNode.id !== 'root') {
        jm.remove_node(selectedNode);
    }
}
编辑节点
function editNode() {
    const selectedNode = jm.get_selected_node();
    if (selectedNode) {
        const newText = prompt('输入新内容', selectedNode.topic);
        if (newText) {
            jm.update_node(selectedNode.id, newText);
        }
    }
}
保存数据到本地存储
function saveDataToLocal() {
    const mindData = jm.get_data();
    localStorage.setItem('mindmapData', JSON.stringify(mindData));
}
导出思维导图数据

将当前数据保存为 .json 文件并触发下载。

function downloadData() {
    saveDataToLocal();
    const mindData = jm.get_data();
    const dataStr = JSON.stringify(mindData, null, 2);
    const blob = new Blob([dataStr], {type: 'application/json'});
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'mindmap.json';
    a.click();
}
导入 JSON 数据

可以通过上传已导出的 JSON 文件恢复之前的思维导图结构。

function importDataFromFile(event) {
    const file = event.target.files[0];
    if (!file) return;

    const reader = new FileReader();
    reader.onload = function(e) {
        try {
            const mindData = JSON.parse(e.target.result);
            jm.show(mindData);
            alert("导入成功!");
        } catch (error) {
            alert("导入失败,请选择有效的JSON文件。");
            console.error("解析文件失败:", error);
        }
    };
    reader.readAsText(file);
}
保存为图片

利用 jsmind.screenshot.js 插件将整个思维导图截图并保存为图片文件。

function saveAsImage() {
    saveDataToLocal();
    jm.screenshot.shootDownload();
}

扩展建议

  • 主题切换:通过修改 jm 的 theme 配置,提供多种预设主题
  • 节点图标与样式设置
  • 快捷键支持

完整代码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <title>在线思维导图</title>
    <meta charset="utf-8">
    <!-- 引入 jsMind 样式 -->
    <link type="text/css" rel="stylesheet" href="./jsmind.css" />
    <style>
        body {
            margin: 0;
            padding: 0;
        }
        #jsmind_container {
            width: 100vw;
            height: 100vh;
            overflow: auto;
            box-sizing: border-box;
            top: 0;
        }
        .toolbar {
            position: fixed;
            top: 10px;
            left: 50%;
            transform: translateX(-50%);
            z-index: 1000;
            display: flex;
            gap: 10px;
        }
        .toolbar button,.toolbar .button {
            padding: 8px 16px;
            border: none;
            border-radius: 4px;
            background-color: #007bff;
            color: white;
            cursor: pointer;
            transition: background-color 0.3s ease;
        }
        .toolbar button:hover {
            background-color: #0056b3;
        }
    </style>
</head>
<body>
<!-- 工具栏 -->
<div class="toolbar">
    <button onclick="addNode()">添加子节点</button>
    <button onclick="removeNode()">删除节点</button>
    <button onclick="editNode()">编辑节点</button>
    <button onclick="saveDataToLocal()">保存</button>
    <button onclick="downloadData()">导出</button>
    <button onclick="saveAsImage()">保存为图片</button>
    <input type="file" id="importFile" accept=".json" style="display: none;" onchange="importDataFromFile(event)">
    <label for="importFile" class="button">导入数据</label>
</div>
<!-- 思维导图容器 -->
<div id="jsmind_container"></div>

<script src="./jsmind.js"></script>
<script src="./jsmind.draggable-node.js"></script>
<script src="./jsmind.screenshot.js"></script>
<script>
    // 初始化思维导图
    let jm = null;
    const initMindMap = () => {
        const options = {
            container: 'jsmind_container',
            editable: true,
            theme: 'white',
        };

        // 初始数据
        let data = {
            "meta": {
                "name": "示例思维导图",
                "author": "user",
                "version": "1.0"
            },
            "format": "node_tree",
            "data": {
                "id": "root",
                "topic": "中心主题",
                "children": [
                ]
            }
        };
        const savedData = localStorage.getItem('mindmapData');
        if (savedData) {
            try {
                data = JSON.parse(savedData);
            } catch (e) {
                console.error("解析本地数据失败", e);
            }
        }
        jm = new jsMind(options);
        jm.show(data);
    }

    // 添加子节点
    function addNode() {
        const selectedNode = jm.get_selected_node();
        if (selectedNode) {
            const nodeId = Date.now().toString();
            jm.add_node(selectedNode.id, nodeId, '新增子节点', {});
        }
    }

    // 删除节点
    function removeNode() {
        const selectedNode = jm.get_selected_node();
        if (selectedNode && selectedNode.id !== 'root') {
            jm.remove_node(selectedNode);
        }
    }

    // 编辑节点
    function editNode() {
        const selectedNode = jm.get_selected_node();
        if (selectedNode) {
            const newText = prompt('输入新内容', selectedNode.topic);
            if (newText) {
                jm.update_node(selectedNode.id, newText);
            }
        }
    }
    // 保存数据到本地存储
    function saveDataToLocal() {
        const mindData = jm.get_data();
        localStorage.setItem('mindmapData', JSON.stringify(mindData));
    }
    // 导出数据
    function downloadData() {
        saveDataToLocal();
        const mindData = jm.get_data();
        const dataStr = JSON.stringify(mindData, null, 2);
        const blob = new Blob([dataStr], {type: 'application/json'});
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = 'mindmap.json';
        a.click();
    }
    // 导入数据
    function importDataFromFile(event) {
        const file = event.target.files[0];
        if (!file) return;

        const reader = new FileReader();
        reader.onload = function(e) {
            try {
                const mindData = JSON.parse(e.target.result);
                jm.show(mindData);
                alert("导入成功!");
            } catch (error) {
                alert("导入失败,请选择有效的JSON文件。");
                console.error("解析文件失败:", error);
            }
        };
        reader.readAsText(file);
    }
    function saveAsImage() {
        saveDataToLocal();
        jm.screenshot.shootDownload();
    }

    // 初始化
    window.onload = initMindMap;
</script>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值