import { parse, generate, baseParse } from '@vue/compiler-dom'; /** * Vue模板编辑器类 * 支持节点的移动、交换、修改等操作 */ export class VueTemplateEditor { constructor(template) { this.originalTemplate = template; this.ast = parse(template); } /** * 获取模板的AST结构 */ getAST() { return this.ast; } /** * 根据选择器查找节点 * @param {string} selector - 选择器(标签名、class、id等) * @returns {Array} 匹配的节点数组 */ findNodes(selector) { const results = []; this._traverseAST(this.ast, (node) => { if (this._matchSelector(node, selector)) { results.push(node); } }); return results; } /** * 移动节点到新位置 * @param {Object} node - 要移动的节点 * @param {Object} targetParent - 目标父节点 * @param {number} position - 在子节点中的位置 */ moveNode(node, targetParent, position = -1) { // 从原位置移除节点 this._removeNodeFromParent(node); // 添加到新位置 if (!targetParent.children) { targetParent.children = []; } if (position === -1) { targetParent.children.push(node); } else { targetParent.children.splice(position, 0, node); } // 更新父节点引用 node.parent = targetParent; } /** * 交换两个节点的位置 * @param {Object} node1 - 第一个节点 * @param {Object} node2 - 第二个节点 */ swapNodes(node1, node2) { if (node1.parent !== node2.parent) { throw new Error('只能交换同一父节点下的兄弟节点'); } const parent = node1.parent; const index1 = parent.children.indexOf(node1); const index2 = parent.children.indexOf(node2); if (index1 === -1 || index2 === -1) { throw new Error('节点不在父节点的子节点列表中'); } // 交换位置 parent.children[index1] = node2; parent.children[index2] = node1; } /** * 修改节点属性 * @param {Object} node - 要修改的节点 * @param {Object} attributes - 新的属性对象 */ modifyNodeAttributes(node, attributes) { if (!node.props) { node.props = []; } Object.entries(attributes).forEach(([key, value]) => { const existingPropIndex = node.props.findIndex(prop => prop.name === key || (prop.arg && prop.arg.content === key) ); if (existingPropIndex !== -1) { // 更新现有属性 const prop = node.props[existingPropIndex]; if (prop.value) { prop.value.content = value; } } else { // 添加新属性 node.props.push({ type: 6, // 属性节点 name: key, value: { type: 2, // 文本节点 content: value } }); } }); } /** * 生成修改后的模板代码 * @returns {string} 新的模板代码 */ generateTemplate() { const result = generate(this.ast, { mode: 'module', source: this.originalTemplate }); return result.code; } /** * 遍历AST树 */ _traverseAST(node, callback) { callback(node); if (node.children) { node.children.forEach(child => { if (child.type) { // 有效的AST节点 this._traverseAST(child, callback); } }); } } /** * 匹配选择器 */ _matchSelector(node, selector) { if (!node.tag) return false; // 简单选择器匹配(可扩展) if (selector.startsWith('.')) { // class选择器 const className = selector.slice(1); return node.props?.some(prop => prop.name === 'class' && prop.value?.content.includes(className) ); } else if (selector.startsWith('#')) { // id选择器 const id = selector.slice(1); return node.props?.some(prop => prop.name === 'id' && prop.value?.content === id ); } else { // 标签名选择器 return node.tag === selector; } } /** * 从父节点移除节点 */ _removeNodeFromParent(node) { if (node.parent && node.parent.children) { const index = node.parent.children.indexOf(node); if (index !== -1) { node.parent.children.splice(index, 1); } } } } /** * 工具函数:创建新的Vue模板编辑器实例 */ export function createTemplateEditor(template) { return new VueTemplateEditor(template); } /** * 工具函数:格式化模板代码 */ export function formatTemplate(template) { const ast = parse(template); const result = generate(ast, { mode: 'module', source: template }); return result.code; }