editor.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. <template>
  2. <div class="my-editor">
  3. <div
  4. class="quill-editor"
  5. :content="content"
  6. :placeholder="placeholder || ''"
  7. @change="handleChange"
  8. v-quill:myQuillEditor="editorOption"
  9. ></div>
  10. <input type="file" id="imgInput" @change="handleContentFileChange" style="display: none;" />
  11. <el-dialog title="提示" :visible.sync="linkDialog" :before-close="handleLinkClose">
  12. <el-form :model="link">
  13. <el-form-item label="标题" :label-width="formLabelWidth">
  14. <el-input v-model="link.title" autocomplete="off"></el-input>
  15. </el-form-item>
  16. <el-form-item label="链接" :label-width="formLabelWidth">
  17. <el-input v-model="link.url" autocomplete="off"></el-input>
  18. </el-form-item>
  19. </el-form>
  20. <span slot="footer" class="dialog-footer">
  21. <el-button @click="handleLinkClose">取 消</el-button>
  22. <el-button type="primary" @click="handleLinkOk">确 定</el-button>
  23. </span>
  24. </el-dialog>
  25. </div>
  26. </template>
  27. <script>
  28. import Vue from "vue";
  29. import "quill/dist/quill.core.css";
  30. import "quill/dist/quill.snow.css";
  31. // import 'quill/dist/quill.bubble.css'
  32. if (process.browser) {
  33. const VueQuillEditor = require("vue-quill-editor/dist/ssr");
  34. Vue.use(VueQuillEditor);
  35. }
  36. import hljs from "hljs";
  37. export default {
  38. props: ["content", "hideImage", "placeholder", "haveVideo"],
  39. components: {
  40. // quillEditor
  41. // Editor
  42. },
  43. data() {
  44. const extra = ["link"];
  45. if (!this.hideImage) {
  46. extra.push("image");
  47. }
  48. if (this.haveVideo) {
  49. extra.push("video");
  50. }
  51. let placeholder = this.placeholder
  52. return {
  53. editorOption: {
  54. theme: "snow",
  55. placeholder: placeholder || "请输入正文...",
  56. modules: {
  57. toolbar: [
  58. ["bold", "italic", "underline", "strike"],
  59. ["blockquote", "code-block"],
  60. [{ header: 1 }, { header: 2 }],
  61. [{ list: "ordered" }, { list: "bullet" }],
  62. [{ script: "sub" }, { script: "super" }],
  63. [{ indent: "-1" }, { indent: "+1" }],
  64. [{ direction: "rtl" }],
  65. [{ size: ["small", false, "large", "huge"] }],
  66. [{ header: [1, 2, 3, 4, 5, 6, false] }],
  67. [{ font: [] }],
  68. [{ color: [] }, { background: [] }],
  69. [{ align: [] }],
  70. ["clean"],
  71. extra
  72. ],
  73. syntax: {
  74. highlight: text => hljs.highlightAuto(text).value
  75. }
  76. }
  77. },
  78. formLabelWidth: "60px",
  79. linkDialog: false,
  80. link: {
  81. title: "",
  82. url: ""
  83. }
  84. };
  85. },
  86. computed: {},
  87. mounted() {
  88. // 为图片ICON绑定事件 getModule 为编辑器的内部属性
  89. this.myQuillEditor
  90. .getModule("toolbar")
  91. .addHandler("image", this.imgHandler);
  92. // this.myQuillEditor
  93. // .getModule("toolbar")
  94. // .addHandler("link", this.linkHandler);
  95. // this.myQuillEditor
  96. // .getModule("toolbar")
  97. // .addHandler("video", this.videoHandler); // 为视频ICON绑定事件
  98. },
  99. methods: {
  100. handleChange(e) {
  101. if (typeof e.html === "undefined") {
  102. return;
  103. }
  104. this.$emit("change", e.html);
  105. },
  106. // 点击图片ICON触发事件
  107. imgHandler(state) {
  108. this.addRange = this.myQuillEditor.getSelection();
  109. if (state) {
  110. let fileInput = document.getElementById("imgInput");
  111. fileInput.click(); // 加一个触发事件
  112. }
  113. this.uploadType = "image";
  114. },
  115. // 点击link触发事件
  116. linkHandler(state) {
  117. const selectedRange = this.myQuillEditor.getSelection();
  118. const selectedText = this.myQuillEditor.getText(
  119. selectedRange.index,
  120. selectedRange.length
  121. );
  122. console.log(state, selectedText);
  123. this.link = {
  124. title: selectedText,
  125. url: selectedText,
  126. ...selectedRange
  127. };
  128. this.linkDialog = true;
  129. },
  130. handleLinkClose() {
  131. this.linkDialog = false;
  132. this.link = {
  133. title: "",
  134. url: ""
  135. };
  136. },
  137. handleLinkOk() {
  138. const link = this.link;
  139. this.myQuillEditor.deleteText(link.index, link.length);
  140. this.myQuillEditor.insertEmbed(link.index, "link", {
  141. href: link.url,
  142. innerText: link.title
  143. });
  144. // this.myQuillEditor.insertText(
  145. // link.index,
  146. // `<a href="${this.link.url}">${this.link.title}</a>`
  147. // );
  148. this.handleLinkClose();
  149. },
  150. // 点击视频ICON触发事件
  151. videoHandler(state) {
  152. this.addRange = this.myQuillEditor.getSelection();
  153. if (state) {
  154. let fileInput = document.getElementById("imgInput");
  155. fileInput.click(); // 加一个触发事件
  156. }
  157. // this.uploadType = "video";
  158. },
  159. handleContentFileChange(e) {
  160. const file = e.target.files[0];
  161. // if (file.size / 1024 > 500) {
  162. // this.$message.error("图片大小不得超过500k,请重新选择");
  163. // return false;
  164. // }
  165. const formData = new FormData();
  166. formData.append("file", file);
  167. formData.append("original_filename", file.name);
  168. this.$axios
  169. .$post(`/upload_image`, formData, {
  170. headers: { "Content-Type": "multipart/form-data" }
  171. })
  172. .then(res => {
  173. const index = this.myQuillEditor.selection.savedRange.index;
  174. this.myQuillEditor.insertEmbed(index, "image", res.filename);
  175. // this.$emit(
  176. // "change",
  177. // this.content + `<img src="${res.filename}" alt="${file.name}"/>`
  178. // );
  179. });
  180. }
  181. }
  182. };
  183. </script>
  184. <style lang="scss">
  185. .my-editor {
  186. position: relative;
  187. width: 100%;
  188. height: 100%;
  189. min-height: 244px;
  190. background: #fff;
  191. .ql-toolbar {
  192. border-width: 0 !important;
  193. }
  194. .ql-editor,
  195. .quill-editor {
  196. min-height: 244px;
  197. border: 0 !important;
  198. font-size: 14px;
  199. line-height: 25px;
  200. }
  201. .ql-snow.ql-toolbar::after {
  202. display: inline-block;
  203. }
  204. }
  205. </style>