index.vue 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. <template>
  2. <div :class="{fullscreen:fullscreen}" class="tinymce-container" :style="{width:containerWidth}">
  3. <textarea :id="tinymceId" class="tinymce-textarea"/>
  4. </div>
  5. </template>
  6. <script>
  7. import load from './dynamicLoadScript'
  8. const tinymceCDN = 'https://stacdn.proginn.com/tinymce/tinymce.js'
  9. export default {
  10. name: 'Tinymce',
  11. props: {
  12. id: {
  13. type: String,
  14. default: function() {
  15. return 'vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
  16. }
  17. },
  18. value: {
  19. type: String,
  20. default: ''
  21. },
  22. toolbar: {
  23. type: Array,
  24. required: false,
  25. default() {
  26. return []
  27. }
  28. },
  29. menubar: {
  30. type: String,
  31. default: 'file edit insert view format table'
  32. },
  33. height: {
  34. type: [Number, String],
  35. required: false,
  36. default: 360
  37. },
  38. width: {
  39. type: [Number, String],
  40. required: false,
  41. default: '100%'
  42. }
  43. },
  44. data() {
  45. return {
  46. hasChange: false,
  47. hasInit: false,
  48. tinymceId: this.id,
  49. fullscreen: false,
  50. languageTypeList: {
  51. 'zh': 'zh_CN',
  52. }
  53. }
  54. },
  55. computed: {
  56. containerWidth() {
  57. const width = this.width
  58. if (/^[\d]+(\.[\d]+)?$/.test(width)) { // matches `100`, `'100'`
  59. return `${width}px`
  60. }
  61. return width
  62. }
  63. },
  64. watch: {
  65. value(val) {
  66. if (!this.hasChange && this.hasInit) {
  67. this.$nextTick(() =>
  68. window.tinymce.get(this.tinymceId).setContent(val || ''))
  69. }
  70. }
  71. },
  72. mounted() {
  73. this.init()
  74. },
  75. activated() {
  76. if (window.tinymce) {
  77. this.initTinymce()
  78. }
  79. },
  80. deactivated() {
  81. this.destroyTinymce()
  82. },
  83. destroyed() {
  84. this.destroyTinymce()
  85. },
  86. methods: {
  87. init() {
  88. // dynamic load tinymce from cdn
  89. load(tinymceCDN, (err) => {
  90. if (err) {
  91. this.$message.error(err.message)
  92. return
  93. }
  94. this.initTinymce()
  95. })
  96. },
  97. initTinymce() {
  98. const _this = this
  99. window.tinymce.init({
  100. selector: `#${this.tinymceId}`,
  101. content_style: "img {width:100%}",
  102. language: this.languageTypeList['zh'],
  103. height: this.height,
  104. body_class: 'panel-body ',
  105. object_resizing: false,
  106. plugins:"paste,autoresize",
  107. autoresize_on_init: true,
  108. paste_data_images: true,
  109. images_upload_url: '/uapi/pub/upload_tinymce',
  110. init_instance_callback: editor => {
  111. if (_this.value) {
  112. editor.setContent(_this.value)
  113. }
  114. _this.hasInit = true
  115. editor.on('NodeChange Change KeyUp SetContent', () => {
  116. this.hasChange = true
  117. this.$emit('input', editor.getContent())
  118. })
  119. },
  120. setup(editor) {
  121. editor.on('FullscreenStateChanged', (e) => {
  122. _this.fullscreen = e.state
  123. })
  124. },
  125. convert_urls: false
  126. })
  127. },
  128. set_content(value){
  129. window.tinymce.get(this.tinymceId).setContent(value);
  130. window.tinymce.get(this.tinymceId).focus();
  131. },
  132. set_focus(){
  133. window.tinymce.get(this.tinymceId).focus();
  134. },
  135. destroyTinymce() {
  136. const tinymce = window.tinymce.get(this.tinymceId)
  137. if (this.fullscreen) {
  138. tinymce.execCommand('mceFullScreen')
  139. }
  140. if (tinymce) {
  141. tinymce.destroy()
  142. }
  143. },
  144. setContent(value) {
  145. window.tinymce.get(this.tinymceId).setContent(value)
  146. },
  147. getContent() {
  148. window.tinymce.get(this.tinymceId).getContent()
  149. },
  150. imageSuccessCBK(arr) {
  151. arr.forEach(v => window.tinymce.get(this.tinymceId).insertContent(`<img style="max-width: 100%;" class="wscnph" src="${v.url}" >`))
  152. }
  153. }
  154. }
  155. </script>
  156. <style lang="scss" scoped>
  157. .tinymce-container {
  158. position: relative;
  159. line-height: normal;
  160. }
  161. .tinymce-container {
  162. ::v-deep {
  163. .mce-fullscreen {
  164. z-index: 10000;
  165. }
  166. }
  167. }
  168. .tinymce-textarea {
  169. visibility: hidden;
  170. z-index: -1;
  171. }
  172. .editor-custom-btn-container {
  173. position: absolute;
  174. right: 4px;
  175. top: 4px;
  176. /*z-index: 2005;*/
  177. }
  178. .fullscreen .editor-custom-btn-container {
  179. z-index: 10000;
  180. position: fixed;
  181. }
  182. .editor-upload-btn {
  183. display: inline-block;
  184. }
  185. </style>