editor.vue 5.7 KB

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