ElEditor.vue 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. <script setup lang="ts">
  2. import '@wangeditor/editor/dist/css/style.css'
  3. import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
  4. import type { IToolbarConfig, IEditorConfig } from '@wangeditor/editor'
  5. import { ACCESS_TOKEN, TOKEN_PREFIX } from '@/utils/constants'
  6. import { isAbsolutePath } from '@/utils/utils'
  7. import { useUserStore } from '@/stores/user'
  8. import config from '@/config/defaultSetting'
  9. interface Props {
  10. modelValue: string
  11. mode?: string
  12. height?: string
  13. uploadApi?: string
  14. fieldName?: string
  15. toolbarConfig?: Partial<IToolbarConfig>
  16. editorConfig?: Partial<IEditorConfig>
  17. }
  18. const props = withDefaults(defineProps<Props>(), {
  19. mode: 'simple',
  20. height: '300px',
  21. uploadApi: config.uploadApi,
  22. fieldName: 'file'
  23. })
  24. const emits = defineEmits(['update:modelValue', 'change'])
  25. // 编辑器实例,必须用 shallowRef
  26. const editorRef = shallowRef()
  27. // 内容 HTML
  28. const valueHtml = computed({
  29. get: () => props.modelValue,
  30. set: value => emits('update:modelValue', value)
  31. })
  32. const userStore = useUserStore()
  33. const editorConfig = {
  34. placeholder: '请输入内容...',
  35. MENU_CONF: {
  36. uploadImage: {
  37. server: isAbsolutePath(props.uploadApi) ? props.uploadApi : import.meta.env.VITE_BASE_API + props.uploadApi,
  38. headers: { [ACCESS_TOKEN]: TOKEN_PREFIX + userStore.token },
  39. fieldName: props.fieldName,
  40. // 自定义插入图片
  41. customInsert(res: any, insertFn: Function) {
  42. const file = res?.data
  43. insertFn(import.meta.env.VITE_BASE_PATH + file)
  44. }
  45. }
  46. },
  47. ...props.editorConfig
  48. }
  49. // 组件销毁时,也及时销毁编辑器
  50. onBeforeUnmount(() => {
  51. const editor = editorRef.value
  52. if (editor == null) return
  53. editor.destroy()
  54. })
  55. const handleCreated = (editor: any) => {
  56. editorRef.value = editor // 记录 editor 实例,重要!
  57. }
  58. const handleChange = (editor: any) => {
  59. emits('change', editor.getHtml())
  60. }
  61. defineExpose({
  62. editorRef
  63. })
  64. </script>
  65. <template>
  66. <div style="border: 1px solid var(--el-border-color); z-index: 2" class="w-full">
  67. <Toolbar
  68. style="border-bottom: 1px solid var(--el-border-color)"
  69. :editor="editorRef"
  70. :defaultConfig="toolbarConfig"
  71. :mode="mode"
  72. />
  73. <Editor
  74. style="overflow-y: hidden"
  75. :style="{ height: height }"
  76. v-model="valueHtml"
  77. :defaultConfig="editorConfig"
  78. :mode="mode"
  79. @onCreated="handleCreated"
  80. @onChange="handleChange"
  81. />
  82. </div>
  83. </template>
  84. <style lang="scss" scoped></style>