RichText.vue 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. <template>
  2. <Editor
  3. v-bind="$attrs"
  4. :id="id"
  5. ref="richText"
  6. :value="value"
  7. :class="['rich-text', isBorder ? 'is-border' : '']"
  8. :init="init"
  9. @input="updateValue"
  10. v-on="$listeners"
  11. />
  12. </template>
  13. <script>
  14. import tinymce from 'tinymce/tinymce';
  15. import Editor from '@tinymce/tinymce-vue';
  16. import 'tinymce/icons/default/icons';
  17. import 'tinymce/themes/silver';
  18. // 引入富文本编辑器主题的js和css
  19. import 'tinymce/themes/silver/theme.min';
  20. import 'tinymce/skins/ui/oxide/skin.min.css';
  21. // 扩展插件
  22. import 'tinymce/plugins/image';
  23. import 'tinymce/plugins/link';
  24. // import 'tinymce/plugins/code';
  25. // import 'tinymce/plugins/table';
  26. import 'tinymce/plugins/lists';
  27. // import 'tinymce/plugins/wordcount'; // 字数统计插件
  28. import 'tinymce/plugins/media'; // 插入视频插件
  29. // import 'tinymce/plugins/template'; // 模板插件
  30. // import 'tinymce/plugins/fullscreen'; // 全屏插件
  31. // import 'tinymce/plugins/paste';
  32. // import 'tinymce/plugins/preview'; // 预览插件
  33. import 'tinymce/plugins/hr';
  34. import 'tinymce/plugins/autoresize'; // 自动调整大小插件
  35. import 'tinymce/plugins/ax_wordlimit'; // 字数限制插件
  36. import { getRandomNumber } from '@/utils';
  37. export default {
  38. name: 'RichText',
  39. components: {
  40. Editor
  41. },
  42. inheritAttrs: false,
  43. props: {
  44. inline: {
  45. type: Boolean,
  46. default: false
  47. },
  48. placeholder: {
  49. type: String,
  50. default: '输入内容'
  51. },
  52. value: {
  53. type: String,
  54. required: true
  55. },
  56. height: {
  57. type: [Number, String],
  58. default: 110
  59. },
  60. isBorder: {
  61. type: Boolean,
  62. default: false
  63. }
  64. },
  65. data() {
  66. return {
  67. id: getRandomNumber(),
  68. init: {
  69. inline: this.inline,
  70. language_url: `/tinymce/langs/zh_CN.js`,
  71. placeholder: this.placeholder,
  72. language: 'zh_CN',
  73. skin_url: '/tinymce/skins/ui/oxide',
  74. // height: this.height,
  75. content_css: '/tinymce/skins/content/index.css',
  76. min_height: 52,
  77. width: '100%',
  78. autoresize_bottom_margin: 0,
  79. plugins: 'link lists image hr media autoresize ax_wordlimit',
  80. /* eslint-disable max-len */
  81. toolbar:
  82. 'fontselect fontsizeselect forecolor backcolor | underline | bold italic strikethrough alignleft aligncenter alignright | bullist numlist | image media | link blockquote hr',
  83. menubar: false,
  84. branding: false,
  85. statusbar: false,
  86. ax_wordlimit_num: 500,
  87. ax_wordlimit_callback(editor) {
  88. editor.execCommand('undo');
  89. }
  90. }
  91. };
  92. },
  93. mounted() {
  94. this.addWheelEvent();
  95. },
  96. methods: {
  97. addText() {
  98. tinymce.get(this.id).selection?.setContent('<strong>some</strong>');
  99. },
  100. addWheelEvent() {
  101. let richText = this.$refs.richText;
  102. if (!richText?.$el?.nextElementSibling?.getElementsByTagName('iframe')?.length) {
  103. return setTimeout(this.addWheelEvent, 100);
  104. }
  105. richText.$el.nextElementSibling.getElementsByTagName('iframe')[0].contentDocument.addEventListener(
  106. 'wheel',
  107. (e) => {
  108. if (e.ctrlKey) e.preventDefault();
  109. },
  110. { passive: false }
  111. );
  112. },
  113. updateValue(data) {
  114. this.$emit('update:value', data);
  115. }
  116. }
  117. };
  118. </script>
  119. <style lang="scss" scoped>
  120. .rich-text {
  121. :deep + .tox {
  122. .tox-sidebar-wrap {
  123. border: 1px solid $fill-color;
  124. border-radius: 4px;
  125. &:hover {
  126. border-color: #c0c4cc;
  127. }
  128. }
  129. &.tox-tinymce {
  130. border-width: 0;
  131. border-radius: 0;
  132. .tox-edit-area__iframe {
  133. background-color: $fill-color;
  134. }
  135. }
  136. &:not(.tox-tinymce-inline) .tox-editor-header {
  137. box-shadow: none;
  138. }
  139. }
  140. :deep &.is-border + .tox.tox-tinymce {
  141. border-width: 2px;
  142. border-radius: 10px;
  143. }
  144. }
  145. </style>