Balkan FamilyTreeJS结合Flask实现家谱数据自动存读问题求助
Flask + Balkan FamilyTree 实现家谱数据自动同步与去重加载
核心问题梳理
你当前的代码存在三个关键问题:
- 前端配置拼写错误,导致组件部分功能失效
- 浏览器安全限制无法直接写入服务器JSON文件,必须通过Flask后端处理
- 数据加载时的ID重置逻辑会破坏节点间的关联关系,去重逻辑不完善
一、修复前端配置拼写错误
先修正代码中的两处拼写错误,这是组件正常运行的基础:
var family = new FamilyTree(document.getElementById('tree'), { mouseScroll: FamilyTree.none, // 修正:mouseScrool → mouseScroll mode: 'dark', template: 'hugo', roots: [1], nodeMenu: { edit: { text: 'Edit' }, details: { text: 'Details' }, }, nodeTreeMenu: true, nodeBindings: { // 修正:nodeBinding → nodeBindings field_0: 'name', field_1: 'born', img_0: 'photo' }, // 其余配置保留不变 });
二、实现Flask后端读写接口
浏览器无法直接操作服务器文件,必须通过后端接口处理数据的读写:
1. Flask后端代码(app.py)
from flask import Flask, request, jsonify, render_template import json import os app = Flask(__name__) # 把数据文件放在static外,避免静态文件缓存问题 DATA_FILE = os.path.join(app.root_path, 'data', 'family_tree.json') # 初始化数据目录和空文件 os.makedirs(os.path.dirname(DATA_FILE), exist_ok=True) if not os.path.exists(DATA_FILE): with open(DATA_FILE, 'w', encoding='utf-8') as f: json.dump([], f) # 前端页面路由 @app.route('/') def index(): return render_template('index.html') # 获取家谱数据 @app.route('/api/tree-data', methods=['GET']) def get_tree_data(): with open(DATA_FILE, 'r', encoding='utf-8') as f: data = json.load(f) return jsonify(data) # 保存/更新家谱数据 @app.route('/api/tree-data', methods=['POST']) def save_tree_data(): try: update_data = request.get_json() # 读取现有数据 with open(DATA_FILE, 'r', encoding='utf-8') as f: existing_data = json.load(f) # 处理不同操作类型 if update_data.get('updateNodesData'): for node in update_data['updateNodesData']: # 按ID覆盖或添加节点 idx = next((i for i, n in enumerate(existing_data) if n['id'] == node['id']), -1) if idx != -1: existing_data[idx] = node else: existing_data.append(node) elif update_data.get('addNodesData'): existing_data.extend(update_data['addNodesData']) elif update_data.get('removeNodeId'): existing_data = [n for n in existing_data if n['id'] != update_data['removeNodeId']] # 写入文件 with open(DATA_FILE, 'w', encoding='utf-8') as f: json.dump(existing_data, f, indent=2, ensure_ascii=False) return jsonify({"status": "success", "data": existing_data}) except Exception as e: return jsonify({"status": "error", "message": str(e)}), 500 if __name__ == '__main__': app.run(debug=True)
2. 前端修改请求逻辑
把原来的本地文件请求改成调用后端API:
// 替换原有的onUpdateNode逻辑 family.onUpdateNode((args) => { fetch('/api/tree-data', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(args) }) .then(response => response.json()) .then(data => { console.log('保存成功:', data); // 保存后重新加载数据确保同步 loadTreeData(); }) .catch(error => console.error('保存失败:', error)); }); // 替换原有的数据加载逻辑 async function loadTreeData() { try { const response = await fetch('/api/tree-data'); const data = await response.json(); processData(data); } catch (error) { console.error("加载数据失败:", error); } } // 页面加载时初始化 window.addEventListener('DOMContentLoaded', loadTreeData);
三、修复数据加载的去重逻辑
原代码重置ID会破坏节点关联,改为按原ID去重,保留节点间的关系:
// 用原ID作为键去重,保留最新的节点数据 const nodesDictionary = {}; function processData(data) { data.forEach(node => { const requiredFields = [ "born", "city", "country", "email", "gender", "name", "phone", "photo" ]; // 检查必填字段,同时按ID去重 const hasAllFields = requiredFields.every(field => node[field] !== undefined); if (hasAllFields && node.id) { nodesDictionary[node.id] = node; } }); const nodesArray = Object.values(nodesDictionary); console.log('去重后的节点:', nodesArray); family.load(nodesArray); }
关键注意事项
- 生产环境建议改用数据库(如SQLite、PostgreSQL)存储数据,JSON文件仅适合小型测试场景
- 不要随意修改节点ID,否则会丢失家谱中的父子/亲属关联关系
- 若需要跨设备同步,确保Flask服务部署在公网可访问的服务器上
内容的提问来源于stack exchange,提问作者ThatOneGuyFromCanada
相关产品推荐
相关产品推荐

