开发智联笔记项目时的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
验证解决方案
- 访问
http://localhost:5000 - 注册新用户并登录
- 创建新的脑图文件
- 测试脑图的各项功能(添加节点、编辑、拖拽、撤销重做等)

浙公网安备 33010602011771号