当前位置:   article > 正文

vue-quill-editor 实现上传图片 视频 图片拖拽 文本对齐等功能_quill 如何让文本和图片放在同一行

quill 如何让文本和图片放在同一行

1. 需要安装的插件

npm install quill  vue-quill-editor  quill-image-drop-module quill-image-resize-module -s

 

 

实现的源码在下面,可直接封装成组件使用

  1. <template>
  2. <div class="ql-container">
  3. <quill-editor
  4. v-model="content"
  5. ref="myquillEditor"
  6. :options="editorOption"
  7. ></quill-editor>
  8. <input
  9. id="uploadImg"
  10. type="file"
  11. style="display:none"
  12. accept="image/png, image/jpeg, image/gif"
  13. @change="uploadImage"
  14. />
  15. <input
  16. id="uploadVideo"
  17. type="file"
  18. style="display:none"
  19. accept="video/*"
  20. @change="uploadVideo"
  21. />
  22. </div>
  23. </template>
  24. <script>
  25. import "quill/dist/quill.core.css";
  26. import "quill/dist/quill.snow.css";
  27. import "quill/dist/quill.bubble.css";
  28. import Vue from "vue";
  29. import * as quill from "quill"; //引入编辑器
  30. import VueQuillEditor from "vue-quill-editor";
  31. import { ImageDrop } from "quill-image-drop-module";
  32. import ImageResize from "quill-image-resize-module";
  33. Vue.use(VueQuillEditor /* { default global options } */);
  34. quill.register("modules/imageDrop", ImageDrop);
  35. quill.register("modules/imageResize", ImageResize);
  36. const BlockEmbed = quill.import("blots/block/embed");
  37. // 处理视频显示,video兼容小程序中显示
  38. class VideoBlot extends BlockEmbed {
  39. static create(value) {
  40. let node = super.create();
  41. node.setAttribute("src", value.url);
  42. node.setAttribute("controls", value.controls);
  43. node.setAttribute("width", value.width);
  44. node.setAttribute("height", value.height);
  45. node.setAttribute("webkit-playsinline", true);
  46. node.setAttribute("playsinline", true);
  47. node.setAttribute("x5-playsinline", true);
  48. return node;
  49. }
  50. static value(node) {
  51. return {
  52. url: node.getAttribute("src"),
  53. controls: node.getAttribute("controls"),
  54. width: node.getAttribute("width"),
  55. height: node.getAttribute("height")
  56. };
  57. }
  58. }
  59. VideoBlot.blotName = "simpleVideo";
  60. VideoBlot.tagName = "video";
  61. quill.register(VideoBlot);
  62. //quill编辑器的字体
  63. let fonts = [
  64. "SimSun",
  65. "SimHei",
  66. "Microsoft-YaHei",
  67. "KaiTi",
  68. "FangSong",
  69. "Arial",
  70. "sans-serif"
  71. ];
  72. let Font = quill.import("formats/font");
  73. Font.whitelist = fonts; //将字体加入到白名单
  74. quill.register(Font, true);
  75. // let fontSizeStyle = quill.import('attributors/style/size');
  76. // fontSizeStyle.whitelist = ['10px', '12px', '14px', '16px', '20px', '24px', '36px', false];
  77. //处理文本对齐
  78. let Align = quill.import("attributors/style/align");
  79. let aligns = [false, "right", "center", "justify"];
  80. Align.whitelist = aligns;
  81. quill.register(Align, true);
  82. export default {
  83. data() {
  84. return {
  85. content: "",
  86. editorOption: {
  87. modules: {
  88. toolbar: [
  89. ["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线
  90. // [{ font: [] }], // 字体种类
  91. [{ font: fonts }],
  92. [{ align: aligns }], // 对齐方式
  93. [{ size: ["small", false, "large", "huge"] }], // 字体大小
  94. // [{ 'size': fontSizeStyle.whitelist }],
  95. [{ header: 1 }, { header: 2 }], // 1、2 级标题
  96. [{ list: "ordered" }, { list: "bullet" }], // 有序、无序列表
  97. ["blockquote", "code-block"], // 引用 代码块
  98. // [{ script: "sub" }, { script: "super" }], // 上标/下标
  99. // [{ indent: "-1" }, { indent: "+1" }], // 缩进
  100. // [{'direction': 'rtl'}], // 文本方向
  101. // [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
  102. [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
  103. // ["clean"], // 清除文本格式
  104. ["image", "video"]
  105. // ["link", "image", "video"] // 链接、图片、视频
  106. ],
  107. //实现拖拽,缩放的重要代码片段
  108. history: {
  109. delay: 1000,
  110. maxStack: 50,
  111. userOnly: false
  112. },
  113. imageDrop: true,
  114. imageResize: {
  115. displayStyles: {
  116. backgroundColor: "black",
  117. border: "none",
  118. color: "white"
  119. },
  120. modules: ["Resize", "DisplaySize", "Toolbar"]
  121. }
  122. },
  123. placeholder: "请填写..."
  124. }
  125. };
  126. },
  127. props: ["editorContent", "status"],
  128. mounted() {
  129. this.$refs.myquillEditor.quill.enable(this.status);
  130. this.$refs.myquillEditor.quill
  131. .getModule("toolbar")
  132. .addHandler("image", this.uploadImageHandler);
  133. this.$refs.myquillEditor.quill
  134. .getModule("toolbar")
  135. .addHandler("video", this.uploadVideoHandler);
  136. },
  137. methods: {
  138. uploadImageHandler() {
  139. const input = document.querySelector("#uploadImg");
  140. input.value = "";
  141. input.click();
  142. },
  143. uploadImage(event) {
  144. const form = new FormData();
  145. form.append("data", event.target.files[0]);
  146. this.$api.upload.uploadImg(form).then(res => {
  147. const addImageRange = this.$refs.myquillEditor.quill.getSelection();
  148. const newRange =
  149. 0 + (addImageRange !== null ? addImageRange.index : 0);
  150. this.$refs.myquillEditor.quill.insertEmbed(
  151. newRange,
  152. "image",
  153. res.data.data
  154. );
  155. this.$refs.myquillEditor.quill.setSelection(1 + newRange);
  156. });
  157. },
  158. uploadVideoHandler() {
  159. const input = document.querySelector("#uploadVideo");
  160. input.value = "";
  161. input.click();
  162. },
  163. uploadVideo(event) {
  164. const form = new FormData();
  165. form.append("data", event.target.files[0]);
  166. this.$api.upload.uploadVideo(form).then(res => {
  167. const addImageRange = this.$refs.myquillEditor.quill.getSelection();
  168. const newRange =
  169. 0 + (addImageRange !== null ? addImageRange.index : 0);
  170. this.$refs.myquillEditor.quill.insertEmbed(
  171. newRange,
  172. "simpleVideo",
  173. {
  174. url: res.data.data,
  175. controls: "controls",
  176. width: "100%",
  177. height: "100%"
  178. }
  179. );
  180. this.$refs.myquillEditor.quill.setSelection(1 + newRange);
  181. });
  182. }
  183. },
  184. watch: {
  185. editorContent: {
  186. handler: function(o, n) {
  187. this.content = this.editorContent;
  188. },
  189. immediate: true
  190. },
  191. // 控制编辑是否可输入
  192. status() {
  193. this.$refs.myquillEditor.quill.enable(this.status);
  194. }
  195. }
  196. };
  197. </script>
  198. <style lang="less" scoped>
  199. /deep/.ql-container {
  200. min-height: 200px;
  201. font-size: 13px;
  202. }
  203. /deep/.ql-toolbar.ql-snow .ql-picker-label {
  204. display: flex;
  205. }
  206. /deep/.ql-snow .ql-picker.ql-align {
  207. width: 80px;
  208. svg {
  209. padding: 0 5px;
  210. width: 28px;
  211. height: 18px;
  212. }
  213. }
  214. /deep/.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="SimSun"]::before,
  215. /deep/.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="SimSun"]::before {
  216. content: "宋体";
  217. font-family: "SimSun";
  218. }
  219. /deep/.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="SimHei"]::before,
  220. /deep/.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="SimHei"]::before {
  221. content: "黑体";
  222. font-family: "SimHei";
  223. }
  224. /deep/.ql-snow
  225. .ql-picker.ql-font
  226. .ql-picker-label[data-value="Microsoft-YaHei"]::before,
  227. /deep/.ql-snow
  228. .ql-picker.ql-font
  229. .ql-picker-item[data-value="Microsoft-YaHei"]::before {
  230. content: "微软雅黑";
  231. font-family: "Microsoft YaHei";
  232. }
  233. /deep/.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="KaiTi"]::before,
  234. /deep/.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="KaiTi"]::before {
  235. content: "楷体";
  236. font-family: "KaiTi";
  237. }
  238. /deep/.ql-snow
  239. .ql-picker.ql-font
  240. .ql-picker-label[data-value="FangSong"]::before,
  241. /deep/.ql-snow
  242. .ql-picker.ql-font
  243. .ql-picker-item[data-value="FangSong"]::before {
  244. content: "仿宋";
  245. font-family: "FangSong";
  246. }
  247. /deep/.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="Arial"]::before,
  248. /deep/.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="Arial"]::before {
  249. content: "Arial";
  250. font-family: "Arial";
  251. }
  252. /deep/.ql-snow
  253. .ql-picker.ql-font
  254. .ql-picker-label[data-value="Times-New-Roman"]::before,
  255. /deep/.ql-snow
  256. .ql-picker.ql-font
  257. .ql-picker-item[data-value="Times-New-Roman"]::before {
  258. content: "Times New Roman";
  259. font-family: "Times New Roman";
  260. }
  261. /deep/.ql-snow
  262. .ql-picker.ql-font
  263. .ql-picker-label[data-value="sans-serif"]::before,
  264. /deep/.ql-snow
  265. .ql-picker.ql-font
  266. .ql-picker-item[data-value="sans-serif"]::before {
  267. content: "sans-serif";
  268. font-family: "sans-serif";
  269. }
  270. /deep/.ql-font-SimSun {
  271. font-family: "SimSun";
  272. }
  273. /deep/.ql-font-SimHei {
  274. font-family: "SimHei";
  275. }
  276. /deep/.ql-font-Microsoft-YaHei {
  277. font-family: "Microsoft YaHei";
  278. }
  279. /deep/.ql-font-KaiTi {
  280. font-family: "KaiTi";
  281. }
  282. /deep/.ql-font-FangSong {
  283. font-family: "FangSong";
  284. }
  285. /deep/.ql-font-Arial {
  286. font-family: "Arial";
  287. }
  288. /deep/.ql-font-Times-New-Roman {
  289. font-family: "Times New Roman";
  290. }
  291. /deep/.ql-font-sans-serif {
  292. font-family: "sans-serif";
  293. }
  294. /deep/.ql-snow .ql-picker.ql-size .ql-picker-label::before,
  295. /deep/.ql-snow .ql-picker.ql-size .ql-picker-item::before {
  296. content: "14px";
  297. }
  298. /deep/.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
  299. /deep/.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
  300. content: "10px";
  301. }
  302. /deep/.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
  303. /deep/.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
  304. content: "18px";
  305. }
  306. /deep/.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
  307. /deep/.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
  308. content: "32px";
  309. }
  310. /deep/.ql-snow .ql-picker.ql-align .ql-picker-label::before,
  311. /deep/.ql-snow .ql-picker.ql-align .ql-picker-item::before {
  312. content: "left";
  313. text-align: left;
  314. }
  315. /deep/.ql-snow
  316. .ql-picker.ql-align
  317. .ql-picker-label[data-value="center"]::before,
  318. /deep/.ql-snow
  319. .ql-picker.ql-align
  320. .ql-picker-item[data-value="center"]::before {
  321. content: "center";
  322. text-align: center;
  323. }
  324. /deep/.ql-snow .ql-picker.ql-align .ql-picker-label[data-value="right"]::before,
  325. /deep/.ql-snow .ql-picker.ql-align .ql-picker-item[data-value="right"]::before {
  326. content: "right";
  327. text-align: right;
  328. }
  329. /deep/.ql-snow
  330. .ql-picker.ql-align
  331. .ql-picker-label[data-value="justify"]::before,
  332. /deep/.ql-snow
  333. .ql-picker.ql-align
  334. .ql-picker-item[data-value="justify"]::before {
  335. content: "justify";
  336. text-align: justify;
  337. }
  338. </style>

此段代码可直接封装成组件

父组件引用富文本组件参考代码:

<editor ref="myEditor" :editorContent="editorContent" :status="editorStatus"></editor>

父组件中获取富文本的值 参考代码:  this.editorContent = this.$refs.myEditor.content;

备注: 代码中监听status 是用来控制编辑器是否可读, 监听editorContent 是用来回显文本内容

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/91202
推荐阅读
相关标签
  

闽ICP备14008679号