开发智联笔记项目时的js问题(1)

问题分析

应用需要以下JS文件:

  • jsmind.js - 核心脑图库
  • jsmind.draggable.js - 拖拽功能
  • jsmind.undo.js - 撤销重做功能

解决方案

1. 获取缺失的JS文件

需要下载这些JS文件并放在 static 目录下:

jsmind.js - 核心文件
可以从官方仓库获取:https://github.com/hizzgdev/jsmind

jsmind.draggable.js - 拖拽插件

// jsmind.draggable.js
(function(){
    if(!window.jsMind) throw new Error('jsMind is not defined');
    var jm = window.jsMind;
    jm.draggable = function(jm){
        this.jm = jm;
        this.selected_node = null;
        this.moving = false;
        this.offset_x = 0;
        this.offset_y = 0;
        this.init();
    };
    jm.draggable.prototype = {
        init: function(){
            var container = this.jm.view.container;
            container.addEventListener('mousedown', this.mousedown_handler.bind(this));
            container.addEventListener('mousemove', this.mousemove_handler.bind(this));
            container.addEventListener('mouseup', this.mouseup_handler.bind(this));
            container.addEventListener('touchstart', this.touchstart_handler.bind(this));
            container.addEventListener('touchmove', this.touchmove_handler.bind(this));
            container.addEventListener('touchend', this.touchend_handler.bind(this));
        },
        mousedown_handler: function(e){
            if(e.button !== 0) return;
            var node = this.find_node(e);
            if(!node) return;
            this.start_drag(node, e.clientX, e.clientY);
            e.stopPropagation();
            e.preventDefault();
        },
        mousemove_handler: function(e){
            if(!this.moving) return;
            this.drag(e.clientX, e.clientY);
            e.stopPropagation();
            e.preventDefault();
        },
        mouseup_handler: function(e){
            if(!this.moving) return;
            this.end_drag();
            e.stopPropagation();
            e.preventDefault();
        },
        touchstart_handler: function(e){
            if(e.touches.length !== 1) return;
            var touch = e.touches[0];
            var node = this.find_node(touch);
            if(!node) return;
            this.start_drag(node, touch.clientX, touch.clientY);
            e.stopPropagation();
            e.preventDefault();
        },
        touchmove_handler: function(e){
            if(!this.moving || e.touches.length !== 1) return;
            var touch = e.touches[0];
            this.drag(touch.clientX, touch.clientY);
            e.stopPropagation();
            e.preventDefault();
        },
        touchend_handler: function(e){
            if(!this.moving) return;
            this.end_drag();
            e.stopPropagation();
            e.preventDefault();
        },
        find_node: function(e){
            var target = e.target;
            while(target && target !== this.jm.view.container){
                if(target.nodeName.toLowerCase() === 'jmnode'){
                    var node_id = target.getAttribute('nodeid');
                    return this.jm.get_node(node_id);
                }
                target = target.parentNode;
            }
            return null;
        },
        start_drag: function(node, client_x, client_y){
            this.selected_node = node;
            this.moving = true;
            var view_data = this.jm.view.get_node_view_data(node.id);
            this.offset_x = client_x - view_data.abs_x;
            this.offset_y = client_y - view_data.abs_y;
            this.jm.view.select_node(node);
        },
        drag: function(client_x, client_y){
            if(!this.moving || !this.selected_node) return;
            var x = client_x - this.offset_x;
            var y = client_y - this.offset_y;
            this.jm.view.move_node(this.selected_node, x, y);
        },
        end_drag: function(){
            this.moving = false;
            this.selected_node = null;
        }
    };
    jm.plugin.draggable = jm.draggable;
})();

jsmind.undo.js - 撤销重做插件

// jsmind.undo.js
(function(){
    if(!window.jsMind) throw new Error('jsMind is not defined');
    var jm = window.jsMind;
    jm.undo = function(jm){
        this.jm = jm;
        this.stack = [];
        this.index = -1;
        this.max_stack_size = 100;
        this.init();
    };
    jm.undo.prototype = {
        init: function(){
            this.jm.add_event_listener(this.event_handler.bind(this));
            // 绑定快捷键
            var self = this;
            document.addEventListener('keydown', function(e){
                if((e.ctrlKey || e.metaKey) && !e.altKey){
                    if(e.keyCode === 90){ // Ctrl+Z
                        if(e.shiftKey) self.redo();
                        else self.undo();
                        e.preventDefault();
                    }else if(e.keyCode === 89){ // Ctrl+Y
                        self.redo();
                        e.preventDefault();
                    }
                }
            });
        },
        event_handler: function(type, data){
            if(type === 'edit' || type === 'add_node' || type === 'remove_node' || 
               type === 'move_node' || type === 'resize'){
                this.push_snapshot();
            }
        },
        push_snapshot: function(){
            // 移除当前索引之后的所有记录
            this.stack = this.stack.slice(0, this.index + 1);
            // 添加新快照
            var snapshot = this.jm.get_data();
            this.stack.push(snapshot);
            // 限制栈大小
            if(this.stack.length > this.max_stack_size){
                this.stack.shift();
            }
            this.index = this.stack.length - 1;
        },
        undo: function(){
            if(this.index <= 0) return;
            this.index--;
            var snapshot = this.stack[this.index];
            this.jm.show(snapshot);
        },
        redo: function(){
            if(this.index >= this.stack.length - 1) return;
            this.index++;
            var snapshot = this.stack[this.index];
            this.jm.show(snapshot);
        },
        clear: function(){
            this.stack = [];
            this.index = -1;
        }
    };
    jm.plugin.undo = jm.undo;
})();

2. 创建项目目录结构

项目结构如下:

your_project/
├── app.py
├── templates/
│   ├── index.html
│   ├── login.html
│   └── register.html
└── static/
    ├── jsmind.js
    ├── jsmind.draggable.js
    ├── jsmind.undo.js
    ├── jsmind.css
    └── all.min.css

3. 数据库配置

确保MySQL数据库已创建:

CREATE DATABASE zhilian CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

4. 安装依赖

pip install flask flask-login flask-sqlalchemy flask-cors pymysql

5. 启动应用

python app.py

验证解决方案

  1. 访问 http://localhost:5000
  2. 注册新用户并登录
  3. 创建新的脑图文件
  4. 测试脑图的各项功能(添加节点、编辑、拖拽、撤销重做等)
posted @ 2025-11-21 19:47  Jade_Z  阅读(6)  评论(0)    收藏  举报