开源一个 JSON 编辑自定义字段

分享 自定义字段  收藏
5 / 322

image.png

function EditorField({ value, onChange, env }) {
  const editorRef = React.useRef(null);
  const containerRef = React.useRef(null);
  const [isLoading, setIsLoading] = React.useState(true);
  
  React.useEffect(() => {
    if (editorRef.current || !containerRef.current) return;
    
    // 加载 JSONEditor 的 CSS 和 JS
    const loadStyles = () => {
      const link = document.createElement('link');
      link.href = 'https://cdn.bootcdn.net/ajax/libs/jsoneditor/10.1.0/jsoneditor.min.css';
      link.rel = 'stylesheet';
      link.type = 'text/css';
      document.head.appendChild(link);
      return link;
    };
    
    const styleElement = loadStyles();
    const script = document.createElement('script');
    script.src = 'https://cdn.bootcdn.net/ajax/libs/jsoneditor/10.1.0/jsoneditor.min.js';
    script.async = true;
    
    script.onload = () => {
      const options = {
        mode: 'tree',
        modes: ['tree', 'code', 'text'],
        onChangeJSON: (json) => {
          try {
            onChange(JSON.stringify(json));
          } catch (err) {
            console.error('JSON转换失败:', err);
          }
        },
        onModeChange: (newMode) => {
          console.log('编辑器模式切换为:', newMode);
        },
        search: true,
        statusBar: true,
        mainMenuBar: true,
        navigationBar: true,
        readOnly: env.isDisabled
      };

      try {
        editorRef.current = new window.JSONEditor(containerRef.current, options);
        
        // 设置初始值
        const initialValue = value ? JSON.parse(value) : {};
        editorRef.current.set(initialValue);
        
        setIsLoading(false);
      } catch (err) {
        console.error('JSONEditor初始化失败:', err);
        setIsLoading(false);
      }
    };
    
    document.body.appendChild(script);
    
    return () => {
      if (editorRef.current) {
        editorRef.current.destroy();
        editorRef.current = null;
      }
      
      if (script.parentNode) {
        script.parentNode.removeChild(script);
      }
      
      if (styleElement.parentNode) {
        styleElement.parentNode.removeChild(styleElement);
      }
    };
  }, []);

  // 监听外部value变化
  React.useEffect(() => {
    if (editorRef.current && value) {
      try {
        const currentValue = editorRef.current.get();
        const newValue = JSON.parse(value);
        
        if (JSON.stringify(currentValue) !== JSON.stringify(newValue)) {
          editorRef.current.set(newValue);
        }
      } catch (err) {
        console.error('更新JSON数据失败:', err);
      }
    }
  }, [value]);

  return (
    <div className="w-full">
      {isLoading && (
        <div className="flex items-center justify-center h-[400px] border rounded-lg">
          <div className="text-gray-500">加载中...</div>
        </div>
      )}
      <div 
        ref={containerRef}
        className={`border rounded-lg ${isLoading ? 'hidden' : ''}`}
        style={{ height: '400px' }}
      />
    </div>
  );
}