wangeditor 富文本 使用及 上传本地图片的方法

发布时间 2023-12-02 15:17:01作者: 柯基与佩奇

文章标题:Vue 组件实现富文本编辑器

文章摘要:本文介绍了如何使用 Vue 和 Wangeditor 插件实现富文本编辑器组件,并详细解释了组件中的各个部分和功能。

Vue 组件实现富文本编辑器 在 Web 开发中,富文本编辑器是一个非常常见的功能,它能够让用户以所见即所得的方式编辑和排版文本内容。本文将介绍如何使用 Vue 和 Wangeditor 插件实现一个富文本编辑器组件。

  1. 安装依赖 首先,我们需要安装@wangeditor/editor-for-vue 插件,该插件提供了与 Vue 集成的富文本编辑器组件。可以通过以下命令来安装:

npm install @wangeditor/editor-for-vue

  1. 创建富文本编辑器组件 在 Vue 项目中,创建一个名为 RichTextEditor 的组件,用于展示富文本编辑器界面和处理相关逻辑。

组件模板代码如下:

<template>
  <div v-if="newVisible">
    <div class="container"></div>
    <div style="border: 1px solid #ccc">
      <!-- 工具栏 -->

      <Toolbar
        :editor="editorRef"
        style="border-bottom: 1px solid #ccc"
        :defaultConfig="toolbarConfig"
      />
      <!-- 编辑器 -->
      <Editor
        v-model="valueHtml"
        :defaultConfig="editorConfig"
        style="height: 500px; overflow-y: hidden"
        @onCreated="handleCreated"
      />
    </div>
    <div class="btn-container">
      <CBotton type="primary" @click="save">保存</CBotton>
      <CBotton type="dashed" @click="cancel">取消</CBotton>
    </div>
  </div>
</template>

在上述代码中,我们通过 v-if 指令控制编辑器组件的显示和隐藏。组件包含一个工具栏和一个编辑器,并在底部添加了保存和取消按钮。

  1. 定义组件的数据和方法在标签中,我们需要定义组件的数据和方法。首先,引入所需的依赖:
<script setup>
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import { uploadFile } from "@/api/base";
import { submitUploadInfoApi, getHelpContent } from "@/api/sale/help-set.ts";
import { message } from "ant-design-vue";
import {
  onBeforeUnmount,
  shallowRef,
  defineProps,
  ref,
  computed,
  defineEmits,
  reactive,
  watch,
} from "vue";
</script>
接着,定义组件需要的数据和方法: ```javascript
<script setup>
// 编辑器实例,必须用 shallowRef,重要!
const editorRef = shallowRef();
const photoGalleryDialogVisible = ref();
const spinning = ref(false);

// 内容 HTML
const valueHtml = ref("");

const props = defineProps({
  visible: { type: Boolean, default: false },
  info: { type: Object, default: null },
  content: { type: Object, default: null },
});
const emit = defineEmits(["confirm", "update:visible", "select"]);

const newVisible = computed({
  get() {
    // 传过来的一行
    return props.visible;
  },
});

watch(
  () => props.visible,
  (val) => {
    console.log("val: ", props.info);
    if (val) {
      if (props?.content?.content) {
        valueHtml.value = props.content.content;
      }
    } else {
    }
  }
);

const handleCreated = (editor) => {
  editorRef.value = editor; // 记录 editor 实例,重要!
};

const save = async () => {
  // 保存逻辑
  const p = {
    categoryId: props.info.id,
    contentType: 1,
    content: valueHtml.value,
  };
  const res = await submitUploadInfoApi(p);
  if (res.code == 0) {
    cancel();
    emit("select", props.info.id);
    return message.success(res.msg);
  }
};

const cancel = () => {
  // 取消逻辑
  console.log("取消编辑");
  emit("update:visible", false);
  valueHtml.value = "";
};

// 组件销毁时,及时销毁编辑器
onBeforeUnmount(() => {
  const editor = editorRef.value;
  if (editor == null) return;
  editor.destroy();
});
</script>

在上述代码中,我们使用了 Vue 3 中的 Composition API 来定义组件的数据和方法。其中,editorRef 用于保存编辑器实例,valueHtml 用于存储编辑器中的 HTML 内容。

save 方法用于保存编辑的内容,首先将内容发送到后端进行保存,并在保存成功后触发 select 事件。cancel 方法用于取消编辑操作,清空内容并隐藏编辑器。

最后,我们使用 onBeforeUnmount 钩子函数,在组件销毁前及时销毁编辑器实例。

  1. 配置工具栏和编辑器 在上述代码中,我们还需要配置编辑器的工具栏和编辑器本身的相关属性。代码如下:
<script setup>
// 工具栏配置
const toolbarConfig = {
  toolbarKeys: [
    // 一些常用的菜单 key
    "bold", // 加粗
    "italic", // 斜体
    "through", // 删除线
    "underline", // 下划线
    "bulletedList", // 无序列表
    "numberedList", // 有序列表
    "color", // 文字颜色
    "fontSize", // 字体大小
    "lineHeight", // 行高
    "uploadImage", // 上传图片
    "delIndent", // 缩进
    "indent", // 增进
    "deleteImage", //删除图片
    "divider", // 分割线
    "justifyCenter", // 居中对齐
    "justifyJustify", // 两端对齐
    "justifyLeft", // 左对齐
    "justifyRight", // 右对齐
    "undo", // 撤销
    "redo", // 重做
    "clearStyle", // 清除格式
  ],
};

// 编辑器配置
const editorConfig = {
  placeholder: "",
  MENU_CONF: {
    uploadImage: {
      server: uploadFile.url,
      headers: { Authorization: uploadFile.Authorization },
      "tenant-id": "1",
      fieldName: "file",
      customInsert(res, insertFn) {
        if (res.code == 0) {
          insertFn(res.data, null, res.data);
        }
      },
    },
  },
};
</script>

在上述代码中,我们通过 toolbarConfig 配置对象定义了工具栏的显示菜单,包括加粗、斜体、删除线、下划线、无序列表、有序列表、文字颜色、字体大小、行高、上传图片等功能。

editorConfig 用于配置编辑器的相关属性,包括占位符文本(placeholder)以及上传图片的配置。

  1. 添加样式 最后,在组件的标签中,我们可以添加一些样式来美化富文本编辑器的界面。例如:
<style src="@wangeditor/editor/dist/css/style.css"></style>
<style>
  .btn-container {
    display: flex;
    justify-content: space-evenly;
    align-items: center;
    margin-top: 60px;
  }
  .container {
    display: flex;
    justify-content: center;
    align-items: center;
  }

  h1 {
    text-align: center;
    font-size: 28px;
  }
</style>

以上代码中,我们引入了 Wangeditor 默认的样式文件,并自定义了一些样式来调整按钮容器和编辑器容器的布局。

  1. 使用富文本编辑器组件 完成以上步骤后,我们就可以在其他 Vue 组件中使用 RichTextEditor 组件了。例如:
<Editor
  v-show="onsitesVisible"
  :info="onsiteActive"
  :content="content"
  v-model:visible="onsitesVisible"
  @confirm="getLists"
  @select="selects"
/>

在上述代码中,我们将 RichTextEditor 组件作为子组件引入,并通过:visible、:info 和:content 属性来传递组件需要的参数。同时,可以监听 select 事件来处理富文本编辑器中的选中操作。

结语 在本文中,我们介绍了如何使用 Vue 和 Wangeditor 插件实现一个富文本编辑器组件,并详细解释了组件中的各个部分和功能。通过这个组件,用户可以方便地进行富文本内容的编辑和排版。希望本文能对你理解和使用富文本编辑器有所帮助!

完整代码

<template>
  <div v-if="newVisible">
    <div class="container"></div>
    <div style="border: 1px solid #ccc">
      <!-- 工具栏 -->

      <Toolbar
        :editor="editorRef"
        style="border-bottom: 1px solid #ccc"
        :defaultConfig="toolbarConfig"
      />
      <!-- 编辑器 -->
      <Editor
        v-model="valueHtml"
        :defaultConfig="editorConfig"
        style="height: 500px; overflow-y: hidden"
        @onCreated="handleCreated"
      />
    </div>
    <div class="btn-container">
      <CBotton type="primary" @click="save">保存</CBotton>
      <CBotton type="dashed" @click="cancel">取消</CBotton>
    </div>
  </div>
</template>
<script setup>
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import { uploadFile } from "@/api/base";
import { submitUploadInfoApi, getHelpContent } from "@/api/sale/help-set.ts";
import { message } from "ant-design-vue";
import {
  onBeforeUnmount,
  shallowRef,
  defineProps,
  ref,
  computed,
  defineEmits,
  reactive,
  watch,
} from "vue";

// 编辑器实例,必须用 shallowRef,重要!
const editorRef = shallowRef();
const photoGalleryDialogVisible = ref();
const spinning = ref(false);

// 内容 HTML
const valueHtml = ref("");

const props = defineProps({
  visible: { type: Boolean, default: false },
  info: { type: Object, default: null },
  content: { type: Object, default: null },
});
const emit = defineEmits(["confirm", "update:visible", "select"]);

const newVisible = computed({
  get() {
    // 传过来的一行
    return props.visible;
  },
});
watch(
  () => props.visible,
  (val) => {
    console.log("val: ", props.info);
    if (val) {
      if (props?.content?.content) {
        valueHtml.value = props.content.content;
      }
    } else {
    }
  }
);
const handleCreated = (editor) => {
  editorRef.value = editor; // 记录 editor 实例,重要!
};
const save = async () => {
  // 保存逻辑
  const p = {
    categoryId: props.info.id,
    contentType: 1,
    content: valueHtml.value,
  };
  const res = await submitUploadInfoApi(p);
  if (res.code == 0) {
    cancel();
    emit("select", props.info.id);
    return message.success(res.msg);
  }
};

const cancel = () => {
  // 取消逻辑
  console.log("取消编辑");
  emit("update:visible", false);
  valueHtml.value = "";
};

// 组件销毁时,及时销毁编辑器
onBeforeUnmount(() => {
  const editor = editorRef.value;
  if (editor == null) return;
  editor.destroy();
});
// 工具栏配置
const toolbarConfig = {
  toolbarKeys: [
    // 一些常用的菜单 key
    "bold", // 加粗
    "italic", // 斜体
    "through", // 删除线
    "underline", // 下划线
    "bulletedList", // 无序列表
    "numberedList", // 有序列表
    "color", // 文字颜色
    "fontSize", // 字体大小
    "lineHeight", // 行高
    "uploadImage", // 上传图片
    "delIndent", // 缩进
    "indent", // 增进
    "deleteImage", //删除图片
    "divider", // 分割线
    "justifyCenter", // 居中对齐
    "justifyJustify", // 两端对齐
    "justifyLeft", // 左对齐
    "justifyRight", // 右对齐
    "undo", // 撤销
    "redo", // 重做
    "clearStyle", // 清除格式
  ],
};
// 编辑器配置

const editorConfig = {
  placeholder: "",
  MENU_CONF: {
    uploadImage: {
      server: uploadFile.url,
      headers: { Authorization: uploadFile.Authorization },
      "tenant-id": "1",
      fieldName: "file", // 这里有个坑,如果返回的响应结果是没有上传文件,跟这里关系很大
      customInsert(res, insertFn) {
        if (res.code == 0) {
          insertFn(res.data, null, res.data);
        }
      },
    },
  },
};
</script>

<!-- 别忘了引入样式 -->
<style src="@wangeditor/editor/dist/css/style.css"></style>
<style>
.btn-container {
  display: flex;
  justify-content: space-evenly;
  align-items: center;
  margin-top: 60px;
}
.container {
  display: flex;
  justify-content: center;
  align-items: center;
}

h1 {
  text-align: center;
  font-size: 28px;
}
</style>