index.vue 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. <template>
  2. <div class="flex flex-col border border-br" :style="styles">
  3. <Toolbar class="border-b border-br" :editor="editorRef" :mode="mode" />
  4. <Editor
  5. class="flex-1 overflow-y-auto"
  6. :mode="mode"
  7. :defaultConfig="state.editorConfig"
  8. v-model="state.editorVal"
  9. @onCreated="handleCreated"
  10. @onChange="handleChange"
  11. />
  12. </div>
  13. </template>
  14. <script setup lang="ts" name="wngEditor">
  15. import '@wangeditor-next/editor/dist/css/style.css';
  16. import { reactive, shallowRef, watch, onBeforeUnmount, CSSProperties } from 'vue';
  17. // @ts-ignore
  18. import { IDomEditor } from '@wangeditor-next/editor';
  19. import { Toolbar, Editor } from '@wangeditor-next/editor-for-vue';
  20. import { Session } from '/@/utils/storage';
  21. import other from '/@/utils/other';
  22. const { proxy } = getCurrentInstance();
  23. // 定义父组件传过来的值
  24. const props = defineProps({
  25. // 是否禁用
  26. disable: {
  27. type: Boolean,
  28. default: () => false,
  29. },
  30. // 内容框默认 placeholder
  31. placeholder: {
  32. type: String,
  33. default: () => '请输入内容...',
  34. },
  35. // https://www.wangeditor.com/v5/getting-started.html#mode-%E6%A8%A1%E5%BC%8F
  36. // 模式,可选 <default|simple>,默认 default
  37. mode: {
  38. type: String,
  39. default: () => 'default',
  40. },
  41. // 高度
  42. height: {
  43. type: String,
  44. default: () => '310',
  45. },
  46. // 宽度
  47. width: {
  48. type: String,
  49. default: () => 'auto',
  50. },
  51. // 双向绑定,用于获取 editor.getHtml()
  52. getHtml: String,
  53. // 双向绑定,用于获取 editor.getText()
  54. getText: String,
  55. uploadFileUrl: {
  56. type: String,
  57. default: `/admin/sys-file/upload`,
  58. },
  59. });
  60. // 定义子组件向父组件传值/事件
  61. const emit = defineEmits(['update:getHtml', 'update:getText']);
  62. // 定义上传需要的请求头信息
  63. const headers = computed(() => {
  64. return {
  65. Authorization: 'Bearer ' + Session.get('token'),
  66. 'TENANT-ID': Session.getTenant(),
  67. };
  68. });
  69. // 定义上传需要的字段信息
  70. const uploadAttr = reactive({
  71. fieldName: 'file',
  72. server: proxy.baseURL + props.uploadFileUrl,
  73. headers: headers,
  74. customInsert(res, insertFn) {
  75. insertFn(proxy.baseURL + res.data.url);
  76. },
  77. });
  78. const editorRef = shallowRef();
  79. const state = reactive({
  80. editorConfig: {
  81. placeholder: props.placeholder,
  82. MENU_CONF: {
  83. uploadImage: uploadAttr,
  84. uploadVideo: uploadAttr,
  85. },
  86. },
  87. editorVal: props.getHtml,
  88. });
  89. const styles = computed<CSSProperties>(() => ({
  90. height: other.addUnit(props.height),
  91. width: other.addUnit(props.width),
  92. }));
  93. // 编辑器回调函数
  94. const handleCreated = (editor: IDomEditor) => {
  95. editorRef.value = editor;
  96. };
  97. // 编辑器内容改变时
  98. const handleChange = (editor: IDomEditor) => {
  99. emit('update:getHtml', editor.getHtml());
  100. emit('update:getText', editor.getText());
  101. };
  102. // 页面销毁时
  103. onBeforeUnmount(() => {
  104. const editor = editorRef.value;
  105. if (editor == null) return;
  106. editor.destroy();
  107. });
  108. // 监听是否禁用改变
  109. watch(
  110. () => props.disable,
  111. (bool) => {
  112. const editor = editorRef.value;
  113. if (editor == null) return;
  114. bool ? editor.disable() : editor.enable();
  115. },
  116. {
  117. deep: true,
  118. }
  119. );
  120. // 监听双向绑定值改变,用于回显
  121. watch(
  122. () => props.getHtml,
  123. (val) => {
  124. state.editorVal = val;
  125. },
  126. {
  127. deep: true,
  128. }
  129. );
  130. </script>