index.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. <template>
  2. <div ref="editorRef"></div>
  3. </template>
  4. <script setup lang="ts" name="Editor">
  5. import { PropType, watch, computed, onMounted, onBeforeUnmount, ref, unref } from 'vue'
  6. import E from 'wangeditor'
  7. import hljs from 'highlight.js' // 这个蠢货插件,9以上的版本都不支持IE。辣鸡!!
  8. import 'highlight.js/styles/monokai-sublime.css'
  9. import { oneOf } from '@/utils'
  10. import { EditorConfig } from './types'
  11. import { Message } from '_c/Message'
  12. const props = defineProps({
  13. config: {
  14. type: Object as PropType<EditorConfig>,
  15. default: () => {
  16. return {}
  17. }
  18. },
  19. valueType: {
  20. type: String as PropType<'html' | 'text'>,
  21. default: 'html',
  22. validator: (val: string) => {
  23. return oneOf(val, ['html', 'text'])
  24. }
  25. },
  26. value: {
  27. type: String as PropType<string>,
  28. default: ''
  29. }
  30. })
  31. const emit = defineEmits(['change', 'focus', 'blur'])
  32. defineExpose({
  33. getHtml,
  34. getJSON,
  35. getText
  36. })
  37. let editor: Nullable<E> = null
  38. const value = computed(() => props.value)
  39. const editorRef = ref<Nullable<HTMLElement>>(null)
  40. watch(
  41. value,
  42. (val: string) => {
  43. if (editor) {
  44. editor.txt.html(val)
  45. }
  46. },
  47. {
  48. immediate: true
  49. }
  50. )
  51. function createdEditor() {
  52. editor = new E(unref(editorRef.value) as HTMLElement)
  53. initConfig()
  54. editor.create()
  55. editor.txt.html(value.value)
  56. }
  57. function initConfig() {
  58. const config = props.config as EditorConfig
  59. const editorRef = editor as E
  60. // // 设置编辑区域高度为 500px
  61. editorRef.config.height = config.height || 500
  62. // // 设置zIndex
  63. editorRef.config.zIndex = config.zIndex || 0
  64. // // 设置 placeholder 提示文字
  65. editorRef.config.placeholder = config.placeholder || '请输入文本'
  66. // // 设置是否自动聚焦
  67. editorRef.config.focus = config.focus || false
  68. // 配置菜单
  69. editorRef.config.menus = config.menus || [
  70. 'head',
  71. 'bold',
  72. 'fontSize',
  73. 'fontName',
  74. 'italic',
  75. 'underline',
  76. 'strikeThrough',
  77. 'indent',
  78. 'lineHeight',
  79. 'foreColor',
  80. 'backColor',
  81. 'link',
  82. 'list',
  83. 'justify',
  84. 'quote',
  85. 'emoticon',
  86. 'image',
  87. 'video',
  88. 'table',
  89. 'code',
  90. 'splitLine',
  91. 'undo',
  92. 'redo'
  93. ]
  94. // 配置颜色(文字颜色、背景色)
  95. editorRef.config.colors = config.colors || ['#000000', '#eeece0', '#1c487f', '#4d80bf']
  96. // 配置字体
  97. editorRef.config.fontNames = config.fontNames || [
  98. '黑体',
  99. '仿宋',
  100. '楷体',
  101. '标楷体',
  102. '华文仿宋',
  103. '华文楷体',
  104. '宋体',
  105. '微软雅黑',
  106. 'Arial',
  107. 'Tahoma',
  108. 'Verdana',
  109. 'Times New Roman',
  110. 'Courier New'
  111. ]
  112. // 配置行高
  113. editorRef.config.lineHeights = config.lineHeights || ['1', '1.15', '1.6', '2', '2.5', '3']
  114. // // 代码高亮
  115. editorRef.highlight = hljs
  116. // // 配置全屏
  117. editorRef.config.showFullScreen = config.showFullScreen || true
  118. // 编辑器 customAlert 是对全局的alert做了统一处理,默认为 window.alert。
  119. // 如觉得浏览器自带的alert体验不佳,可自定义 alert,以便于达到与自身项目统一的alert效果。
  120. editorRef.config.customAlert =
  121. config.customAlert ||
  122. function (s: string, t: string) {
  123. switch (t) {
  124. case 'success':
  125. Message.success(s)
  126. break
  127. case 'info':
  128. Message.info(s)
  129. break
  130. case 'warning':
  131. Message.warning(s)
  132. break
  133. case 'error':
  134. Message.error(s)
  135. break
  136. default:
  137. Message.info(s)
  138. break
  139. }
  140. }
  141. // 图片上传默认使用base64
  142. editorRef.config.uploadImgShowBase64 = true
  143. // 配置 onchange 回调函数
  144. editorRef.config.onchange = (html: string) => {
  145. const text = editorRef.txt.text()
  146. emitFun(editor, props.valueType === 'html' ? html : text, 'change')
  147. }
  148. // 配置触发 onchange 的时间频率,默认为 200ms
  149. editorRef.config.onchangeTimeout = config.onchangeTimeout || 1000
  150. // 编辑区域 focus(聚焦)和 blur(失焦)时触发的回调函数。
  151. editorRef.config.onblur = (html: string) => {
  152. emitFun(editor, html, 'blur')
  153. }
  154. editorRef.config.onfocus = (html: string) => {
  155. emitFun(editor, html, 'focus')
  156. }
  157. }
  158. function emitFun(editor: any, _: string, type: 'change' | 'focus' | 'blur'): void {
  159. if (editor) {
  160. emit(type, props.valueType === 'html' ? (editor as E).txt.html() : (editor as E).txt.text())
  161. }
  162. }
  163. function getHtml() {
  164. if (editor) {
  165. return (editor as E).txt.html()
  166. }
  167. }
  168. function getText() {
  169. if (editor) {
  170. return (editor as E).txt.text()
  171. }
  172. }
  173. function getJSON() {
  174. if (editor) {
  175. return (editor as E).txt.getJSON()
  176. }
  177. }
  178. onMounted(() => {
  179. createdEditor()
  180. })
  181. onBeforeUnmount(() => {
  182. if (editor) {
  183. ;(editor as E).destroy()
  184. editor = null
  185. }
  186. })
  187. </script>