index.vue 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. <script setup>
  2. import { onBeforeUnmount, onMounted, ref, watch } from 'vue';
  3. import tinymce from "tinymce"
  4. import request from '~/utils/request';
  5. const props = defineProps({
  6. 'id': {
  7. type: String,
  8. default: `tiny-${Date.now()}-${~~(Math.random() * 10000)}`
  9. },
  10. 'htmlClass': { default: '', type: String },
  11. 'modelValue': { default: '' },
  12. 'plugins': {
  13. default: function () {
  14. return [
  15. 'advlist autolink lists link image charmap preview anchor pagebreak',
  16. 'searchreplace wordcount visualblocks visualchars code fullscreen',
  17. 'insertdatetime media nonbreaking save table directionality',
  18. 'template help emoticons'
  19. ];
  20. }, type: Array
  21. },
  22. toolbar1: { default: 'formatselect | bold italic strikethrough forecolor backcolor | link | alignleft aligncenter alignright alignjustify | numlist bullist outdent indent | removeformat', type: String },
  23. toolbar2: { default: '', type: String },
  24. other_options: {
  25. default: function () {
  26. return {};
  27. }, type: Object
  28. }
  29. })
  30. const emits = defineEmits(['update:modelValue'])
  31. const content = ref('')
  32. watch(
  33. () => props.modelValue,
  34. (newVal, oldVal) => {
  35. content.value = newVal;
  36. init()
  37. },
  38. { immediate: true }
  39. );
  40. let editor = null
  41. let checkerTimeout = null
  42. let isTyping = false
  43. function init() {
  44. let options = {
  45. selector: '#' + props.id,
  46. base_url: '/tiny',
  47. language: 'zh-Hans',
  48. // skin: false,
  49. toolbar1: props.toolbar1,
  50. toolbar2: props.toolbar2,
  51. plugins: props.plugins.join(' '),
  52. autosave_restore_when_empty: true,
  53. init_instance_callback: (_editor) => {
  54. _editor.on('KeyUp', (e) => {
  55. submitNewContent();
  56. });
  57. _editor.on('Change', (e) => {
  58. if (_editor.getContent() !== props.modelValue) {
  59. submitNewContent();
  60. }
  61. });
  62. _editor.on('init', (e) => {
  63. _editor.setContent(content.value);
  64. // emits('input', content.value);
  65. });
  66. editor = _editor;
  67. },
  68. images_upload_handler: (blobInfo, progress) => {
  69. const file = blobInfo.blob();
  70. return request({
  71. $type: 'upload',
  72. url: 'upload/main/file',
  73. data: {
  74. filedata: file
  75. },
  76. timeout: 1000 * 60,
  77. onUploadProgress(progressEvent) {
  78. progress(~~(progressEvent.loaded / progressEvent.total * 100 | 0))
  79. },
  80. }).then(res => {
  81. if (res.code === '1') {
  82. return window.GLOBAL_CONFIG.oss + (res.data.url)
  83. } else {
  84. return ('')
  85. }
  86. })
  87. },
  88. // to solve a third party URL
  89. // paste_preprocess: (editor, args) => {
  90. // if (/^https?\:\/\/.+(png|jpg)$/.test(args.content)) {
  91. // args.content = uploadByThirdPartyUrl(args.content);
  92. // }
  93. // }
  94. };
  95. tinymce.init(Object.assign(options, props.other_options));
  96. }
  97. function submitNewContent() {
  98. isTyping = true;
  99. if (checkerTimeout !== null) { clearTimeout(checkerTimeout); }
  100. checkerTimeout = setTimeout(() => {
  101. isTyping = false;
  102. }, 300);
  103. emits('update:modelValue', editor.getContent());
  104. }
  105. onMounted(() => {
  106. content.value = props.modelValue
  107. init()
  108. })
  109. onBeforeUnmount(() => {
  110. editor.destroy();
  111. })
  112. </script>
  113. <template>
  114. <div>
  115. <textarea :id="id">{{ content }}</textarea>
  116. </div>
  117. </template>