Commit be273437 by pangchong

fix: 富文本编辑器问题处理

parent 5aaa8926
......@@ -7,15 +7,21 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
NButton: typeof import('naive-ui')['NButton']
NCard: typeof import('naive-ui')['NCard']
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
NDataTable: typeof import('naive-ui')['NDataTable']
NInput: typeof import('naive-ui')['NInput']
NLayout: typeof import('naive-ui')['NLayout']
NLayoutContent: typeof import('naive-ui')['NLayoutContent']
NLayoutFooter: typeof import('naive-ui')['NLayoutFooter']
NLayoutHeader: typeof import('naive-ui')['NLayoutHeader']
NMessageProvider: typeof import('naive-ui')['NMessageProvider']
NResult: typeof import('naive-ui')['NResult']
NSpace: typeof import('naive-ui')['NSpace']
NSpin: typeof import('naive-ui')['NSpin']
NTree: typeof import('naive-ui')['NTree']
NUpload: typeof import('naive-ui')['NUpload']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
}
......
<template>
<div class="z-10 h-full flex flex-col">
<!-- 工具栏 -->
<Toolbar :editor="editorRef" :editorId="editorId" :defaultConfig="toolbarConfig" class="border-b border-solid border-borderColor" />
<div class="flex">
<div class="flex-1">
<Toolbar :editor="editorRef" :editorId="editorId" class="border-b border-solid border-borderColor" />
</div>
<n-button @click="uploadXml" class="h-full">上传XML</n-button>
</div>
<!-- 编辑器 -->
<div class="p-[15px] flex flex-1 overflow-hidden">
<slot name="left"></slot>
......@@ -28,7 +34,7 @@ import { Boot, IModuleConf } from '@wangeditor/editor'
import renderElemConf from '../functions/render-elem'
import elemToHtmlConf from '../functions/elem-to-html'
import parseHtmlConf from '../functions/parse-elem-html'
import myMenuConf from '../functions/extra-menu'
import { uploadXml } from '../functions'
const module: Partial<IModuleConf> = {
renderElems: renderElemConf,
......@@ -36,7 +42,6 @@ const module: Partial<IModuleConf> = {
parseElemsHtml: parseHtmlConf
}
Boot.registerModule(module)
Boot.registerMenu(myMenuConf) // 注册菜单
//菜单配置
const toolbarConfig = {
......@@ -59,8 +64,7 @@ const toolbarConfig = {
'uploadImage',
'insertLink',
'fullScreen',
'clearStyle',
'XML'
'clearStyle'
]
}
......
......@@ -2,10 +2,11 @@
import type { TreeOption } from 'naive-ui'
import { TreeRenderResult } from '@/lib/XMLProcessor/src/typing'
export const showLoading = ref(false)
// 菜单相关
export const searchKey = ref('')
export const treeData: Ref<TreeOption[]> = ref([])
export const xmlDOM :Ref<Document>= ref()
export const xmlDOM: Ref<Document> = ref()
export const treeSelectedKeys = ref<string[]>([])
export const xmlContent: Ref<string> = ref('')
//编辑器相关
......@@ -15,36 +16,33 @@ export const formData = reactive({
})
// 递归函数:检查树中是否存在满足条件的节点
// 递归函数:检查树中是否存在满足条件的节点,并构建新的树结构
function buildFilteredTree(
tree: TreeRenderResult,
searchString: string
): TreeRenderResult | null {
function buildFilteredTree(tree: TreeRenderResult, searchString: string): TreeRenderResult | null {
// 如果当前节点的 label 包含指定字符串,直接返回当前节点
if (tree.label.includes(searchString)) {
return { ...tree }; // 返回当前节点的副本
return { ...tree } // 返回当前节点的副本
}
// 如果当前节点有子节点,递归检查每个子节点
if (tree.children) {
const filteredChildren: TreeRenderResult[] = [];
const filteredChildren: TreeRenderResult[] = []
for (let child of tree.children) {
const result = buildFilteredTree(child, searchString);
const result = buildFilteredTree(child, searchString)
if (result) {
filteredChildren.push(result); // 如果子节点符合条件,加入到当前节点的子节点列表
filteredChildren.push(result) // 如果子节点符合条件,加入到当前节点的子节点列表
}
}
// 如果有符合条件的子节点,返回当前节点,并更新子节点列表
if (filteredChildren.length > 0) {
return { ...tree, children: filteredChildren };
return { ...tree, children: filteredChildren }
}
}
// 如果当前节点及其子节点都不满足条件,返回 null
return null;
return null
}
export const realComposableData = computed(function() {
export const realComposableData = computed(function () {
if (!searchKey.value) {
return treeData.value
}
......
import { IButtonMenu, IDomEditor } from '@wangeditor/editor'
import { uploadXml } from '.'
class XMLMenu implements IButtonMenu {
title: string
tag: string
constructor() {
this.title = '上传XML' // 自定义菜单标题
this.tag = 'button' // 菜单的标签,默认是button
}
getValue(editor: IDomEditor): string | boolean {
// 获取菜单执行时的 value,用不到则返回空字符串或 false
return ''
}
isActive(editor: IDomEditor): boolean {
// 菜单是否需要激活,用不到则返回 false
return false
}
isDisabled(editor: IDomEditor): boolean {
// 菜单是否需要禁用,用不到则返回 false
return false
}
async exec(editor: IDomEditor, value: string | boolean) {
// 点击菜单时触发的函数
if (this.isDisabled(editor)) return
const arrFileHandle = await (window as any).showOpenFilePicker({
types: [
{
accept: {
'XML/*': ['.xml']
}
}
]
})
const file = await arrFileHandle[0].getFile()
uploadXml(file)
}
}
export default {
key: 'XML', // 定义 menu key,要保证唯一、不重复
factory() {
return new XMLMenu() // 返回定义的菜单类实例
}
}
import { IDomEditor } from '@wangeditor/editor'
import { editorRef, treeData, xmlContent, xmlDOM } from '../constants'
import { editorRef, showLoading, treeData, xmlContent, xmlDOM } from '../constants'
import { TreeOption } from 'naive-ui'
import { nodeSet } from '../constants/nodeParsed'
import { getCurrentInstance, getCurrentScope } from 'vue'
export const handleEditor = (editor: IDomEditor) => {
// console.log(editor.getElemsByTypePrefix('JOBCARD'))
// console.log(editor)
// const headers = editor.getElemsByTypePrefix('header')
// const menu = headers.map((header: any) => {
// const title = SlateNode.string(header)
// return {
// title,
// key: header.id,
// type: header.type
// }
// })
// treeData.value = buildTree(menu)
// if (editor.getHtml() == '<p><br></p>') return
// const xmlProcessing = useXMLProcessing()
// const res = xmlProcessing.processXML(editor.getHtml(), nodeSet)
// treeData.value = res.treeData
// xmlDOM.value = res.xmlDOM
// xmlContent.value = res.xmlContent
}
let lastFocusedId = ''
......@@ -35,10 +28,24 @@ export const nodeProps = ({ option }: { option: TreeOption }) => {
}
}
}
export const uploadXml = async (file: File) => {
const xmlProcessing = useXMLProcessing()
const res = await xmlProcessing.processFile(file, nodeSet)
treeData.value = res.treeData
xmlDOM.value = res.xmlDOM
xmlContent.value = res.xmlContent
export const uploadXml = async () => {
const input = document.createElement('input')
input.type = 'file'
input.accept = 'application/xml,text/xml'
input.multiple = false
input.click()
input.addEventListener('change', async (event: Event) => {
const files = (event.target as HTMLInputElement).files
if (files && files.length > 0) {
const file = files[0]
const xmlProcessing = useXMLProcessing()
showLoading.value = true
const res = await xmlProcessing.processFile(file, nodeSet)
showLoading.value = false
treeData.value = res.treeData
xmlDOM.value = res.xmlDOM
xmlContent.value = res.xmlContent
editorRef.value?.editorRef?.setHtml(xmlContent.value)
}
})
}
<template>
<ContentEditor ref="editorRef" v-model="formData.html" @change="handleEditor" @created="handleEditor">
<template #left>
<n-card class="h-full min-w-[300px] max-w-[300px] mr-[15px]" content-class="bg-baseColor !p-0 overflow-hidden">
<ContentTree></ContentTree>
</n-card>
</template>
</ContentEditor>
<n-spin class="h-full w-full" content-class="h-full w-full" :show="showLoading" description="加载中...">
<ContentEditor ref="editorRef" v-model="formData.html" @change="handleEditor" @created="handleEditor">
<template #left>
<n-card class="h-full min-w-[300px] max-w-[300px] mr-[15px]" content-class="bg-baseColor !p-0 overflow-hidden">
<ContentTree></ContentTree>
</n-card>
</template>
</ContentEditor>
</n-spin>
</template>
<script setup lang="ts">
import ContentEditor from './components/ContentEditor.vue'
import ContentTree from './components/ContentTree.vue'
import { editorRef, formData, xmlContent } from './constants'
import { editorRef, formData, showLoading, xmlContent } from './constants'
import { handleEditor } from './functions'
onMounted(() => {
watchEffect(function() {
editorRef.value?.editorRef?.setHtml(xmlContent.value)
}, {flush: 'post'})
// nextTick(() => {
// editorRef.value?.editorRef?.setHtml(xmlContent.value)
// })
})
</script>
<style lang="less" scoped>
......
......@@ -23,7 +23,7 @@ export default defineConfig({
{
'naive-ui': ['useDialog', 'useMessage', 'useNotification', 'useLoadingBar'],
'@/hooks/useEventBus': ['useEventBus'],
"@/lib/XMLProcessor/src/index": ['useXMLProcessing']
'@/lib/XMLProcessor/src/index': ['useXMLProcessing']
}
],
dts: 'src/auto-import.d.ts',
......@@ -39,5 +39,11 @@ export default defineConfig({
alias: {
'@': resolve('src')
}
},
base: './', // 打包路径
server: {
open: true, // 自动打开
cors: true, // 跨域
host: true
}
})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment