UNPKG

@wiajs/ui

Version:

wia ui packages

347 lines (346 loc) 13.4 kB
/** @jsxImportSource @wiajs/core */ import { jsx as _jsx, jsxs as _jsxs } from "@wiajs/core/jsx-runtime"; import { log as Log } from '@wiajs/util'; // 创建日志实例 const log = Log({ m: 'jsonView' }); /** * @typedef {import('jquery')} $ * @typedef {JQuery} Dom */ export default class JsonView { /** * 构造函数 * @param {Object} options 配置项 * @param {HTMLElement|jQuery} options.parent 父容器元素 * @param {Object} options.data 初始JSON数据 * @param {Object} options.source 更新接口信息 */ constructor(options){ // 初始化配置 this.parent = options.parent instanceof $ ? options.parent : $(options.parent); this.data = options.data || {}; this.source = options.source; // 初始化DOM元素引用 this.$jsonEditor = null; this.$jsonPreview = null; this.$treeView = null; this.$lineCount = null; this.$charCount = null; this.$lineNumbers = null; this.$editorMessage = null; // 初始化视图 this.initDOM(); this.initEvents(); this.initData(); } /** * 初始化DOM结构 */ initDOM() { try { // 创建主容器HTML const el = /*#__PURE__*/ _jsxs("div", { class: "json-view-box", children: [ /*#__PURE__*/ _jsxs("div", { style: "width:50%", children: [ /*#__PURE__*/ _jsxs("div", { class: "editor-container", children: [ /*#__PURE__*/ _jsx("div", { class: "line-numbers", id: "lineNumbers" }), /*#__PURE__*/ _jsx("textarea", { style: "width:100%", class: "editor jsonEditor" }) ] }), /*#__PURE__*/ _jsxs("div", { class: "status-bar", children: [ /*#__PURE__*/ _jsxs("span", { children: [ "行数: ", /*#__PURE__*/ _jsx("span", { class: "lineCount", children: "0" }) ] }), /*#__PURE__*/ _jsxs("span", { children: [ "字符数: ", /*#__PURE__*/ _jsx("span", { class: "charCount", children: "0" }) ] }) ] }), /*#__PURE__*/ _jsx("div", { class: "editor-message" }) ] }), /*#__PURE__*/ _jsx("div", { class: "preview-panel", children: /*#__PURE__*/ _jsx("div", { class: "preview jsonPreview", children: /*#__PURE__*/ _jsx("div", { class: "tree-view treeView" }) }) }) ] }); // 添加到父容器 this.parent.append(el); // 获取DOM元素引用 this.$jsonEditor = this.parent.find('.jsonEditor'); this.$jsonPreview = this.parent.find('.jsonPreview'); this.$treeView = this.parent.find('.treeView'); this.$lineCount = this.parent.find('.lineCount'); this.$charCount = this.parent.find('.charCount'); this.$lineNumbers = this.parent.find('.line-numbers'); this.$editorMessage = this.parent.find('.editor-message'); // 验证关键DOM元素是否存在 if (!this.$jsonEditor.length) { throw new Error('未找到JSON编辑器元素'); } } catch (error) { log.err(error, 'initDOM'); } } /** * 初始化事件绑定 */ initEvents() { try { this.$jsonEditor.on('input', ()=>this.updateEditorStatus()); this.$jsonEditor.on('input', ()=>this.updateLineNumbers()); this.$jsonEditor.on('input', this.debounce(()=>this.updatePreview(), 500)); // 滚动同步事件 this.$jsonEditor.on('scroll', ()=>{ this.$lineNumbers.scrollTop(this.$jsonEditor.scrollTop()); }); } catch (error) { log.err(error, 'initEvents'); } // 绑定输入事件(使用箭头函数保持this指向) } /** * 初始化数据 */ initData() { try { // 设置初始JSON数据 this.$jsonEditor.val(JSON.stringify(this.data, null, 2)); // 初始化状态 this.updateEditorStatus(); this.updateLineNumbers(); this.renderJsonTree(this.data); this.formatJson(); } catch (error) { log.err(error, 'initData'); } } /** * 更新行号 */ updateLineNumbers() { try { const lines = this.$jsonEditor.val().split('\n'); const lineNumbersHTML = lines.map((_, i)=>`<div class="line-number">${i + 1}</div>`).join(''); this.$lineNumbers.html(lineNumbersHTML); } catch (error) { log.err(error, 'updateLineNumbers'); } } /** * 更新编辑器状态(行数、字符数) */ updateEditorStatus() { try { const text = this.$jsonEditor.val(); const lines = text.split('\n').length; const characters = text.length; this.$lineCount.text(lines); this.$charCount.text(characters); } catch (error) { log.err(error, 'updateEditorStatus'); } } /** * 格式化JSON */ formatJson() { try { const jsonValue = JSON.parse(this.$jsonEditor.val()); this.$jsonEditor.val(JSON.stringify(jsonValue, null, 2)); this.updateEditorStatus(); this.updateLineNumbers(); this.showMessage('JSON已格式化', 'success'); } catch (error) { log.err(error, 'formatJson'); this.showMessage(`错误: ${error.message}`, 'error'); } } /** * 显示消息提示 * @param {string} text 消息文本 * @param {string} type 消息类型(success/error) */ showMessage(text, type) { try { if (this.$editorMessage) { this.$editorMessage.text(text); this.$editorMessage.attr('class', `editor-message ${type}`); } } catch (error) { log.err(error, 'showMessage'); } } /** * 防抖函数 * @param {Function} func 目标函数 * @param {number} delay 延迟时间(ms) * @returns {Function} 防抖后的函数 */ debounce(func, delay) { try { let timeoutId; return (...args)=>{ clearTimeout(timeoutId); timeoutId = setTimeout(()=>func.apply(this, args), delay); }; } catch (error) { log.err(error, 'debounce'); // 失败时返回原函数,避免功能中断 return func; } } /** * 更新预览面板 */ updatePreview() { try { const jsonValue = JSON.parse(this.$jsonEditor.val()); this.renderJsonTree(jsonValue); // @ts-expect-error this.showMessage(''); } catch (error) { log.err(error, 'updatePreview'); this.showMessage(`错误: ${error.message}`, 'error'); } } /** * 渲染JSON树形视图 * @param {Object} jsonData 需要渲染的JSON数据 */ renderJsonTree(jsonData) { try { this.$treeView.html(''); // @ts-expect-error const tree = this.createTreeElement(jsonData); this.$treeView.append(tree); } catch (error) { log.err(error, 'renderJsonTree'); } } /** * 创建树形结构元素 * @param {any} data 数据节点 * @param {string|null} key 节点键名 * @returns {HTMLElement} 生成的DOM元素 */ createTreeElement(data, key) { try { const item = document.createElement('div'); item.className = 'tree-item'; if (typeof data === 'object' && data !== null) { const collapsible = document.createElement('span'); collapsible.className = 'collapsible'; collapsible.textContent = key ? `${key}: ` : ''; const isArray = Array.isArray(data); const type = isArray ? 'Array' : 'Object'; const count = isArray ? data.length : Object.keys(data).length; const preText = document.createElement('span'); preText.textContent = `${type} ${isArray ? `[${count}]` : `{${count}}`}`; collapsible.appendChild(preText); item.appendChild(collapsible); const children = document.createElement('div'); children.className = 'children'; // 遍历子节点 for (const [childKey, value] of Object.entries(data)){ children.appendChild(this.createTreeElement(value, isArray ? null : childKey)); } item.appendChild(children); // 绑定展开/折叠事件 collapsible.addEventListener('click', function() { this.classList.toggle('expanded'); }); } else { const valueSpan = document.createElement('span'); valueSpan.textContent = key ? `${key}: ` : ''; const value = document.createElement('span'); // 根据数据类型添加不同样式 if (typeof data === 'string') { value.className = 'json-string'; value.textContent = `"${data}"`; } else if (typeof data === 'number') { value.className = 'json-number'; value.textContent = data; } else if (typeof data === 'boolean') { value.className = 'json-boolean'; value.textContent = data ? 'true' : 'false'; } else if (data === null) { value.className = 'json-null'; value.textContent = 'null'; } valueSpan.appendChild(value); item.appendChild(valueSpan); } return item; } catch (error) { log.err(error, 'createTreeElement'); } } /** * 保存JSON数据(可由外部重写或扩展) */ async saveJson() { let R; try { if (this.$jsonEditor.dom) { // 验证JSON格式 const newJson = JSON.parse(this.$jsonEditor.val()); const _id = newJson._id; // @ts-expect-error const { url } = this.source; let { token } = this.source; token = token ?? 'token'; const tk = token ? $.store.get(token) : ''; console.log(tk, 'tk'); const param = { id: _id, json: newJson }; // if (param) param.value = inputValue; // else param = { // value: inputValue // }; const rs = await $.post(url, param, { 'x-wia-token': tk }); console.log(rs, 'rs'); // // 输入完成后再触发查询 // if (rs) { // _.data = rs; // const filteredData = _.filter(inputValue); // _.showList(filteredData, inputValue); // _.hideStatus(); // } } // 4. 显示保存成功消息 this.showMessage('JSON数据保存成功', 'success'); R = true // 保存成功 ; } catch (error) { // console.log(error,'error') // 格式错误,显示错误消息(理论上不会走到这里,因为按钮已禁用) this.showMessage(`保存失败:${error.message}`, 'error'); } return R; } }