Guoguo-notes
主页
常用笔记
vue笔记及周边生态
  • 团队协作及规范
  • 项目框架及架构
  • 飞码篇
  • Java
  • React笔记
GitHub
主页
常用笔记
vue笔记及周边生态
  • 团队协作及规范
  • 项目框架及架构
  • 飞码篇
  • Java
  • React笔记
GitHub

使用

 <Editor height="300px" v-model="formData.content" />

富文本组件

<!-- @format -->

<script lang="ts" setup>
  import { PropType } from 'vue';
  import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
  import {
    i18nChangeLanguage,
    IDomEditor,
    IEditorConfig,
  } from '@wangeditor/editor';
  import { propTypes } from '@/utils/propTypes';
  import { isNumber } from '@/utils/is';
  import { ElMessage } from 'element-plus';
  import { useLocaleStore } from '@/store/modules/locale';
  import { getRefreshToken, getTenantId } from '@/utils/auth';
  import { getUploadUrl } from '@/components/UploadFile/src/useUpload';

  defineOptions({ name: 'Editor' });

  type InsertFnType = (url: string, alt: string, href: string) => void;

  const localeStore = useLocaleStore();

  const currentLocale = computed(() => localeStore.getCurrentLocale);

  i18nChangeLanguage(unref(currentLocale).lang);

  const props = defineProps({
    editorId: propTypes.string.def('wangeEditor-1'),
    height: propTypes.oneOfType([Number, String]).def('500px'),
    editorConfig: {
      type: Object as PropType<Partial<IEditorConfig>>,
      default: () => undefined,
    },
    readonly: propTypes.bool.def(false),
    modelValue: propTypes.string.def(''),
  });

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

  // 编辑器实例,必须用 shallowRef
  const editorRef = shallowRef<IDomEditor>();

  const valueHtml = ref('');

  watch(
    () => props.modelValue,
    (val: string) => {
      if (val === unref(valueHtml)) return;
      valueHtml.value = val;
    },
    {
      immediate: true,
    },
  );

  // 监听
  watch(
    () => valueHtml.value,
    (val: string) => {
      emit('update:modelValue', val);
    },
  );

  const handleCreated = (editor: IDomEditor) => {
    editorRef.value = editor;
  };

  // 编辑器配置
  const editorConfig = computed((): IEditorConfig => {
    return Object.assign(
      {
        placeholder: '请输入内容...',
        readOnly: props.readonly,
        customAlert: (s: string, t: string) => {
          switch (t) {
            case 'success':
              ElMessage.success(s);
              break;
            case 'info':
              ElMessage.info(s);
              break;
            case 'warning':
              ElMessage.warning(s);
              break;
            case 'error':
              ElMessage.error(s);
              break;
            default:
              ElMessage.info(s);
              break;
          }
        },
        autoFocus: false,
        scroll: true,
        MENU_CONF: {
          ['uploadImage']: {
            server: getUploadUrl(),
            // 单个文件的最大体积限制,默认为 2M
            maxFileSize: 5 * 1024 * 1024,
            // 最多可上传几个文件,默认为 100
            maxNumberOfFiles: 10,
            // 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 []
            allowedFileTypes: ['image/*'],

            // 自定义增加 http  header
            headers: {
              Accept: '*',
              Authorization: 'Bearer ' + getRefreshToken(), // 使用 getRefreshToken() 方法,而不使用 getAccessToken() 方法的原因:Editor 无法方便的刷新访问令牌
              'tenant-id': getTenantId(),
            },

            // 超时时间,默认为 10 秒
            timeout: 5 * 1000, // 5 秒

            // form-data fieldName,后端接口参数名称,默认值wangeditor-uploaded-image
            fieldName: 'file',

            // 上传之前触发
            onBeforeUpload(file: File) {
              // console.log(file)
              return file;
            },
            // 上传进度的回调函数
            onProgress(progress: number) {
              // progress 是 0-100 的数字
              console.log('progress', progress);
            },
            onSuccess(file: File, res: any) {
              console.log('onSuccess', file, res);
            },
            onFailed(file: File, res: any) {
              alert(res.message);
              console.log('onFailed', file, res);
            },
            onError(file: File, err: any, res: any) {
              alert(err.message);
              console.error('onError', file, err, res);
            },
            // 自定义插入图片
            customInsert(res: any, insertFn: InsertFnType) {
              insertFn(res.data, 'image', res.data);
            },
          },
          ['uploadVideo']: {
            server: getUploadUrl(),
            // 单个文件的最大体积限制,默认为 10M
            maxFileSize: 10 * 1024 * 1024,
            // 最多可上传几个文件,默认为 100
            maxNumberOfFiles: 10,
            // 选择文件时的类型限制,默认为 ['video/*'] 。如不想限制,则设置为 []
            allowedFileTypes: ['video/*'],

            // 自定义增加 http  header
            headers: {
              Accept: '*',
              Authorization: 'Bearer ' + getRefreshToken(), // 使用 getRefreshToken() 方法,而不使用 getAccessToken() 方法的原因:Editor 无法方便的刷新访问令牌
              'tenant-id': getTenantId(),
            },

            // 超时时间,默认为 30 秒
            timeout: 15 * 1000, // 15 秒

            // form-data fieldName,后端接口参数名称,默认值wangeditor-uploaded-image
            fieldName: 'file',

            // 上传之前触发
            onBeforeUpload(file: File) {
              // console.log(file)
              return file;
            },
            // 上传进度的回调函数
            onProgress(progress: number) {
              // progress 是 0-100 的数字
              console.log('progress', progress);
            },
            onSuccess(file: File, res: any) {
              console.log('onSuccess', file, res);
            },
            onFailed(file: File, res: any) {
              alert(res.message);
              console.log('onFailed', file, res);
            },
            onError(file: File, err: any, res: any) {
              alert(err.message);
              console.error('onError', file, err, res);
            },
            // 自定义插入图片
            customInsert(res: any, insertFn: InsertFnType) {
              insertFn(res.data, 'mp4', res.data);
            },
          },
        },
        uploadImgShowBase64: true,
      },
      props.editorConfig || {},
    );
  });

  const editorStyle = computed(() => {
    return {
      height: isNumber(props.height) ? `${props.height}px` : props.height,
    };
  });

  // 回调函数
  const handleChange = (editor: IDomEditor) => {
    emit('change', editor);
  };

  // 组件销毁时,及时销毁编辑器
  onBeforeUnmount(() => {
    const editor = unref(editorRef.value);

    // 销毁,并移除 editor
    editor?.destroy();
  });

  const getEditorRef = async (): Promise<IDomEditor> => {
    await nextTick();
    return unref(editorRef.value) as IDomEditor;
  };

  defineExpose({
    getEditorRef,
  });
</script>

<template>
  <div
    class="border-1 border-solid border-[var(--tags-view-border-color)] z-10"
  >
    <!-- 工具栏 -->
    <Toolbar
      :editor="editorRef"
      :editorId="editorId"
      class="border-0 b-b-1 border-solid border-[var(--tags-view-border-color)]"
    />
    <!-- 编辑器 -->
    <Editor
      v-model="valueHtml"
      :defaultConfig="editorConfig"
      :editorId="editorId"
      :style="editorStyle"
      @on-change="handleChange"
      @on-created="handleCreated"
    />
  </div>
</template>

<style src="@wangeditor/editor/dist/css/style.css"></style>

Edit this page
Last Updated:
Contributors: 袁果锅