vue使用百度富文本编辑器

首先需要安装富文本插件

 npm add vue-ueditor-wrap
或
 pnpm add vue-ueditor-wrap  

这里我用的是我自己的包,不是官方的

然后下载压缩包解压至项目中的public文件夹里面

然后再main.js 里面配置,引入我们的富文本插件

import { createApp } from 'vue';
import pinia from '/@/stores/index';
import App from '/@/App.vue';
import router from '/@/router';
import { directive } from '/@/directive/index';
import { i18n } from '/@/i18n/index';
import other from '/@/utils/other';
import * as ElementPlusIconsVue from '@element-plus/icons-vue';
import ElementPlus from 'element-plus';
import '/@/theme/index.scss';
import VueGridLayout from 'vue-grid-layout';

// 引入 UEditor 富文本插件
import '../public/UEditor/ueditor.config.js';
import '../public/UEditor/ueditor.all.min.js';
import '../public/UEditor/lang/zh-cn/zh-cn.js';
import '../public/UEditor/themes/default/css/ueditor.css'; // 确保引入 UEditor 的 CSS 文件

const app = createApp(App);

directive(app);
other.elSvg(app);
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
	app.component(key, component);
}
app.use(pinia).use(router).use(ElementPlus).use(i18n).use(VueGridLayout).mount('#app');

然后再src目录下方的components文件夹里面创建文件UEditor.vue进行配置

<!-- UEditor 富文本编辑器组件,支持图片上传及多图上传 -->


<template>
  <div ref="editor"></div>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, watch, nextTick } from 'vue';

declare global {
  interface Window {
    UE: {
      getEditor: (element: HTMLElement | string, options?: Record<string, any>) => any;
      delEditor: (element: HTMLElement | string) => void;
    };
    loader: {
      load: (resources: string | string[], callback?: () => void, errorCallback?: () => void) => void;
      loadJs: (url: string, callback?: () => void, errorCallback?: () => void) => void;
      loadCss: (url: string, callback?: () => void, errorCallback?: () => void) => void;
      loadImg: (url: string, callback?: () => void, errorCallback?: () => void) => void;
    };
  }
}

// 完整实现loader对象
if (!window.loader) {
  window.loader = {
    load: (resources: string | string[], callback?: () => void, errorCallback?: () => void) => {
      console.log('加载资源:', resources);
      
      // 处理单个资源或资源数组
      const resourceArray = Array.isArray(resources) ? resources : [resources];
      let loadedCount = 0;
      
      resourceArray.forEach((resource, index) => {
        if (resource.endsWith('.js')) {
          // 加载JS
          loadScript(resource, () => {
            if (++loadedCount === resourceArray.length && callback) {
              callback();
            }
          }, errorCallback);
        } else if (resource.endsWith('.css')) {
          // 加载CSS
          loadStyle(resource, () => {
            if (++loadedCount === resourceArray.length && callback) {
              callback();
            }
          }, errorCallback);
        } else {
          // 未知类型,直接回调
          if (++loadedCount === resourceArray.length && callback) {
            callback();
          }
        }
      });
    },
    
    loadJs: (url: string, callback?: () => void, errorCallback?: () => void) => {
      console.log('加载JS:', url);
      loadScript(url, callback, errorCallback);
    },
    
    loadCss: (url: string, callback?: () => void, errorCallback?: () => void) => {
      console.log('加载CSS:', url);
      loadStyle(url, callback, errorCallback);
    },
    
    loadImg: (url: string, callback?: () => void, errorCallback?: () => void) => {
      console.log('加载图片:', url);
      const img = new Image();
      img.onload = () => callback?.();
      img.onerror = () => errorCallback?.();
      img.src = url;
    }
  };
}

// 辅助函数:加载JS脚本
const loadScript = (url: string, callback?: () => void, errorCallback?: () => void) => {
  const script = document.createElement('script');
  script.src = url;
  script.onload = () => callback?.();
  script.onerror = () => errorCallback?.();
  document.head.appendChild(script);
};

// 辅助函数:加载CSS样式
const loadStyle = (url: string, callback?: () => void, errorCallback?: () => void) => {
  const link = document.createElement('link');
  link.href = url;
  link.rel = 'stylesheet';
  link.onload = () => callback?.();
  link.onerror = () => errorCallback?.();
  document.head.appendChild(link);
};

const props = defineProps({
  modelValue: {
    type: String,
    default: '',
  },
});

const emit = defineEmits(['update:modelValue', 'content-change']);

const editor = ref<HTMLElement | null>(null);
let ueditorInstance: any = null;
const ueditorHomeUrl = `${window.location.origin}/UEditor/`;

onMounted(() => {
  nextTick(() => {
    initUEditor();
  });
});

onBeforeUnmount(() => {
  destroyUEditor();
});

const initUEditor = () => {
  if (!editor.value || !window.UE) return;

  try {
    ueditorInstance = window.UE.getEditor(editor.value, {
      initialFrameWidth: "100%",
      initialFrameHeight: 200,
      autoHeightEnabled: false,
      serverUrl: "/pc/file/index",//改成自己的富文本上传接口
      imageUrl: "/pc/file/index",//改成自己的富文本上传接口
      UEDITOR_HOME_URL: ueditorHomeUrl,
      imageFieldName: "upfile",
    });

    ueditorInstance.ready(() => {
      const processedContent = processContent(props.modelValue);
      ueditorInstance.setContent(processedContent);
      
      ueditorInstance.addListener('contentChange', () => {
        const content = ueditorInstance.getContent();
        emit('update:modelValue', content);
        emit('content-change', content);
      });
      
      ueditorInstance.addListener('afterInsertImage', () => {
        setTimeout(() => {
          replaceImagesInEditor();
        }, 100);
      });
      
      ueditorInstance.addListener('aftersetcontent', () => {
        setTimeout(() => {
          replaceImagesInEditor();
        }, 100);
      });
    });
  } catch (error) {
    console.error('UEditor初始化失败:', error);
  }
};

const processContent = (content: string) => {
  if (!content) return '';
  
  return content.replace(/<img[^>]+>/g, (imgTag) => {
    const srcMatch = imgTag.match(/src="([^"]+)"/);
    const src = srcMatch ? srcMatch[1] : '';
    
    if (!src) return imgTag;
    
    return `
      <img 
        src="${src}" 
        style="
          width: 200px !important;
          height: 200px !important;
          object-fit: contain !important;
          display: inline-block !important;
          margin: 5px !important;
          vertical-align: middle !important;
          border: 1px solid #eee !important;
        "
      >
    `;
  });
};

const replaceImagesInEditor = () => {
  if (!ueditorInstance) return;
  
  try {
    const body = ueditorInstance.document.body;
    const images = body.querySelectorAll('img');
    
    images.forEach((img:any) => {
      const src = img.getAttribute('src') || '';
      if (src) {
        const newImg = document.createElement('img');
        newImg.src = src;
        newImg.style.width = '200px';
        newImg.style.height = '200px';
        newImg.style.objectFit = 'contain';
        newImg.style.display = 'inline-block';
        newImg.style.margin = '5px';
        newImg.style.verticalAlign = 'middle';
        newImg.style.border = '1px solid #eee';
        
        img.parentNode?.replaceChild(newImg, img);
      }
    });
  } catch (error) {
    console.error('替换图片失败:', error);
  }
};



const destroyUEditor = () => {
  if (ueditorInstance && editor.value && window.UE) {
    window.UE.delEditor(editor.value);
    ueditorInstance = null;
  }
};

watch(
  () => props.modelValue,
  (newValue) => {
    if (ueditorInstance && newValue !== ueditorInstance.getContent()) {
      const processedContent = processContent(newValue);
      ueditorInstance.setContent(processedContent);
    }
  }
);
</script>

<style>
.edui-container {
  width: 100% !important;
}
</style>

(该配置里面也包含图片上传及多图上传)配置完成之后,在你所需页面引入使用

import UEditor from "/@/components/UEditor.vue";// 富文本引入

在所需要使用的地方写

<UEditor v-model="form.content" @content-change="handleContentChange" />
<!-- 富文本使用 -->



// 富文本手动触发校验
const handleContentChange = () => {
    nextTick(() => {
        formRef.value?.validateField('content'); // 手动触发验证
    });
};

如果你需要上传图片,上传图片报错,说未配置

serverUrl:"/pcapi/editor/index",//根据实际情况配置,serverUrl修改成自己的富文本编辑的接口即可。 

如果还有其他地方不懂的或者有什么问题,可以上网搜索自行查找🌹

### 在 Vue3 中集成和使用百度富文本编辑器 #### 准备工作 为了在 Vue3 项目中成功集成百度 UEditor 富文本编辑器,需先下载并准备 UEditor 的源码[^1]。 #### 引入必要的文件 打开 `/src/main.js` 文件,在适当的位置插入如下代码来配置百度编辑器: ```javascript import '../static/ue/ueditor.config.js' import '../static/ue/ueditor.all.min.js' import '../static/ue/lang/zh-cn/zh-cn.js' import '../static/ue/ueditor.parse.min.js' ``` 这些脚本负责初始化编辑器实例及其所需的语言包和其他资源文件[^3]。 #### 创建组件封装 创建一个新的 Vue 组件用于封装 UEditor 实例。例如 `UEditor.vue`: ```vue <template> <div id="editor"></div> </template> <script setup> import { onMounted } from 'vue'; // 假设已按照上述方法导入了 UE 对象 let editor; onMounted(() => { const ueContainerId = "editor"; editor = window.UE.getEditor(ueContainerId); }); </script> <style scoped> /* 可选样式 */ #editor{ width: 80%; } </style> ``` 此部分利用 Composition API (`setup`) 和生命周期钩子 `onMounted()` 来确保页面加载完成后才启动编辑器实例化过程。 #### 图片上传处理 当涉及到图片粘贴或上传操作时,需要注意设置相应的回调函数以处理图像数据,并最终通过 `insertHtml` 方法将 URL 插入到编辑区域中[^4]: ```javascript const handleImageUpload = (file) => new Promise((resolve, reject) => { // 这里可以加入实际的服务器端接口请求逻辑 let formData = new FormData(); formData.append('image', file); fetch('/api/upload-image', { method: 'POST', body: formData, }) .then(response => response.json()) .then(data => resolve(data.url)) .catch(error => reject(error)); }); editor.addListener('beforeInsertImage', function (_, list){ list.forEach(item=>{ if (!item.src.startsWith('http')){ // 如果不是远程链接,则认为是本地上传 handleImageUpload(item).then(url=>Object.assign(item,{ src:url })); } }); }); ``` 这段 JavaScript 代码展示了如何监听 `beforeInsertImage` 事件并对每张待插入的图片执行异步上传动作;一旦获取到了有效的网络地址就更新原对象中的 `src` 属性值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值