index.vue 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. <template>
  2. <Editor v-model="contentValue" :init="init" :disabled="disabled" :placeholder="placeholder" @onClick="onClick" />
  3. </template>
  4. <script setup name="Editor">
  5. import Editor from '@tinymce/tinymce-vue'
  6. import tinymce from 'tinymce/tinymce'
  7. import 'tinymce/themes/silver'
  8. import 'tinymce/icons/default'
  9. import 'tinymce/models/dom'
  10. // 引入编辑器插件
  11. import 'tinymce/plugins/code' // 编辑源码
  12. import 'tinymce/plugins/image' // 插入编辑图片
  13. import 'tinymce/plugins/link' // 超链接
  14. import 'tinymce/plugins/preview' // 预览
  15. import 'tinymce/plugins/table' // 表格
  16. import 'tinymce/plugins/lists' // 列表编号
  17. import 'tinymce/plugins/advlist' //高级列表编号
  18. import 'tinymce/plugins/wordcount' // 字数统计插件
  19. import '@/utils/wordlimit' // 字数插件
  20. const emit = defineEmits(['update:modelValue', 'onClick'])
  21. const props = defineProps({
  22. modelValue: {
  23. type: String,
  24. default: ''
  25. },
  26. placeholder: {
  27. type: String,
  28. default: ''
  29. },
  30. height: {
  31. type: Number,
  32. default: 300
  33. },
  34. disabled: {
  35. type: Boolean,
  36. default: false
  37. },
  38. plugins: {
  39. type: [String, Array],
  40. default: 'code image link preview table lists advlist kityformula-editor wordcount wordlimit'
  41. },
  42. toolbar: {
  43. type: [String, Array],
  44. default:
  45. 'undo redo | forecolor backcolor bold italic underline strikethrough link | blocks fontfamily fontsize | \
  46. alignleft aligncenter alignright alignjustify outdent indent lineheight | bullist numlist | \
  47. image table preview | code selectall'
  48. },
  49. fileUploadFunction: {
  50. type: Function,
  51. default: undefined
  52. }
  53. })
  54. const init = ref({
  55. language_url: '/tinymce/langs/zh_CN.js',
  56. language: 'zh_CN',
  57. skin_url: '/tinymce/skins/ui/oxide',
  58. content_css: '/tinymce/skins/content/default/content.css',
  59. menubar: false,
  60. statusbar: true,
  61. plugins: props.plugins,
  62. toolbar: props.toolbar,
  63. fontsize_formats: '12px 14px 16px 18px 20px 22px 24px 28px 32px 36px 48px 56px 72px',
  64. height: props.height,
  65. placeholder: props.placeholder,
  66. branding: false,
  67. resize: true,
  68. elementpath: true,
  69. content_style: '',
  70. toolbar_mode: 'wrap',
  71. wordlimit: {
  72. max: 2147483647
  73. },
  74. external_plugins: {
  75. 'kityformula-editor': '/tinymce/plugins/kityformula-editor/plugin.min.js'
  76. },
  77. automatic_uploads: false,
  78. images_upload_handler(blobInfo, progress) {
  79. return new Promise((resolve, reject) => {
  80. const param = new FormData()
  81. param.append('file', blobInfo.blob(), blobInfo.filename())
  82. props
  83. .fileUploadFunction(param)
  84. .then((data) => {
  85. return resolve(data)
  86. })
  87. .catch((err) => {
  88. return reject('err:' + err)
  89. })
  90. })
  91. },
  92. setup: (editor) => {
  93. editor.on('init', () => {
  94. // getBody().style.fontSize = '14px'
  95. })
  96. editor.ui.registry.addButton('numberedline', {
  97. text: '填空',
  98. onAction: function () {
  99. const count = editor.getBody().querySelectorAll('.gapfilling-span').length
  100. const lineNumber = count + 1
  101. const uuid = 'gapfilling-' + Date.now() + '-' + Math.floor(Math.random() * 10000)
  102. editor.insertContent(
  103. `<span class="gapfilling-span ${uuid}" style="color:red;padding:0 30px;margin:0 5px;border-bottom:3px double red;">${lineNumber}</span>&ZeroWidthSpace;`
  104. )
  105. }
  106. })
  107. }
  108. })
  109. const contentValue = ref(props.modelValue)
  110. watch(props, (newValue) => {
  111. contentValue.value = newValue.modelValue
  112. emit('update:modelValue', newValue.modelValue)
  113. })
  114. watch(contentValue, (newValue) => {
  115. emit('update:modelValue', newValue)
  116. })
  117. const onClick = (e) => {
  118. emit('onClick', e, tinymce)
  119. }
  120. onMounted(() => {
  121. tinymce.init({})
  122. })
  123. </script>
  124. <style>
  125. /* 在el-dialog中tinymce z-index 被太小而被遮挡时要加这两句 */
  126. .tox-tinymce-aux {
  127. z-index: 99999 !important;
  128. }
  129. .tinymce.ui.FloatPanel {
  130. z-index: 99;
  131. }
  132. </style>