wangEditor.vue 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. <template>
  2. <div id="wangEditor">
  3. <div :id="this.id" style="text-align: left"></div>
  4. </div>
  5. </template>
  6. <script>
  7. import E from 'wangeditor';
  8. import axios from 'axios';
  9. export default {
  10. name: 'wangEditor',
  11. props: {
  12. value: String,
  13. height: { type: Number, default: 300 }, //编辑区域高度
  14. zIndex: { type: Number, default: 200 }, //显示层级优先度
  15. placeholder: { type: String }, //未输入时显示提示
  16. isFocus: { type: Boolean, default: false }, //是否自动焦点(自动切换到富文本上)
  17. url: { type: String }, //上传地址,如果没有下面的两个,或者用的时候缺对应项,也用这个,如果都没有,就提示有问题
  18. imgSize: { type: Number, default: 5 }, //图片大小,单位MB,默认5MB
  19. imgAccept: { type: Array, default: () => ['jpg', 'jpeg', 'png', 'gif', 'bmp'] }, //图片类型
  20. imgOnceNumber: { type: Number, default: 5 }, //一次最多上传几个图片
  21. imgUrl: { type: String }, //图片上传地址
  22. videoSize: { type: Number, default: 1 }, //视频大小限制,单位为G,默认1G
  23. videoUrl: { type: String }, //视频上传地址
  24. imgLimit: { type: Array }, //img标签限制[width,height]
  25. },
  26. model: {
  27. prop: 'value',
  28. event: 'input',
  29. },
  30. data: function () {
  31. const getId = () => {
  32. let id = 'weditor';
  33. let i = 0;
  34. while (i < 20) {
  35. const num = Math.ceil(Math.random() * 10);
  36. id = `${id}${num}`;
  37. i++;
  38. }
  39. return id;
  40. };
  41. return {
  42. id: getId(),
  43. editor: undefined,
  44. imgObject: {},
  45. };
  46. },
  47. created() {},
  48. mounted() {
  49. this.init();
  50. },
  51. methods: {
  52. init() {
  53. const editor = new E(`#${this.id}`);
  54. // 使用设置
  55. editor.config.height = this.height;
  56. editor.config.zIndex = this.zIndex;
  57. editor.config.focus = this.isFocus;
  58. if (this.placeholder) editor.config.placeholder = this.placeholder;
  59. // 图片设置
  60. editor.config.uploadImgMaxSize = this.imgSize * 1024 * 1024;
  61. editor.config.uploadImgAccept = this.imgAccept;
  62. editor.config.uploadImgMaxLength = this.imgOnceNumber;
  63. // 视频
  64. editor.config.uploadVideoMaxSize = this.videoSize * 1024 * 1024 * 1024;
  65. // 默认设置
  66. // 图片-完全自定义上传
  67. editor.config.customUploadImg = async (resultFiles, insertImgFn) => {
  68. let url = this.imgUrl || this.url;
  69. if (!url) {
  70. this.$message.error('未配置上传路径!');
  71. return false;
  72. }
  73. for (const file of resultFiles) {
  74. const res = await this.upload(file);
  75. insertImgFn(res);
  76. }
  77. };
  78. // 视频-完全自定义上传
  79. editor.config.customUploadVideo = async (resultFiles, insertVideoFn) => {
  80. let url = this.videoUrl || this.url;
  81. if (!url) {
  82. this.$message.error('未配置上传路径!');
  83. return false;
  84. }
  85. for (const file of resultFiles) {
  86. const res = await this.upload(file);
  87. insertVideoFn(res);
  88. }
  89. };
  90. editor.config.onchange = (html) => {
  91. this.$emit('input', html);
  92. };
  93. // hooks
  94. editor.txt.eventHooks.clickEvents.push(this.toClick);
  95. editor.create();
  96. this.$set(this, `editor`, editor);
  97. },
  98. toClick(e) {
  99. // const target = e.target;
  100. // if (target.tagName == 'IMG') {
  101. // target.style.width = '150px';
  102. // target.style.height = '150px';
  103. // }
  104. },
  105. async upload(file) {
  106. let formdata = new FormData();
  107. formdata.append('file', file, file.name);
  108. const res = await axios.post(this.url, formdata, { headers: { 'Content-Type': 'multipart/form-data' } });
  109. if (res.status === 200 && res.data.errcode == 0) {
  110. const { id, name, uri } = res.data;
  111. return uri;
  112. } else {
  113. this.$message.error('上传失败');
  114. }
  115. },
  116. },
  117. watch: {
  118. value: {
  119. handler(val, oval) {
  120. this.$nextTick(() => {
  121. // 必须在nextTick下才可以获取this.editor,因为下面用了immediate,在mounted周期之前,但是init是在mounted中进行的.所以必须延迟到下个更新队列中
  122. // 且这个watch只是初始化用,因为上面用的v-model,有自己更新的方式;
  123. if (val && !oval) {
  124. this.editor.txt.html(val);
  125. }
  126. });
  127. },
  128. immediate: true,
  129. },
  130. },
  131. beforeDestroy() {
  132. // 销毁编辑器
  133. this.editor.destroy();
  134. this.editor = null;
  135. },
  136. };
  137. </script>
  138. <style lang="less" scoped></style>