quillEditorComponent.vue 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. <template>
  2. <div class="quillEditorComponent">
  3. <quill-editor
  4. class="editor"
  5. ref="myTextEditor"
  6. v-model="currentcontent"
  7. :options="editorOption"
  8. @blur="onEditorBlur($event)"
  9. @focus="onEditorFocus($event)"
  10. @ready="onEditorReady($event)"
  11. @change="onEditorChange"
  12. ></quill-editor>
  13. <!-- 文件上传input 将它隐藏-->
  14. <a-upload
  15. style="display:none"
  16. :action="UploadUrl()"
  17. :show-file-list="false"
  18. :before-upload="newEditorbeforeupload"
  19. :customRequest="fileUpload"
  20. ref="uniqueId"
  21. >
  22. </a-upload>
  23. </div>
  24. </template>
  25. <script>
  26. import { quillEditor } from 'vue-quill-editor'
  27. import 'quill/dist/quill.core.css'
  28. import 'quill/dist/quill.snow.css'
  29. import 'quill/dist/quill.bubble.css'
  30. import homeApi from '@/api/homeApi'
  31. import { setArticleContent, imgUrlDel, setImgUrl } from '@/utils/img'
  32. export default {
  33. name: 'QuillEditorComponent',
  34. components: {
  35. quillEditor
  36. },
  37. props: [],
  38. data () {
  39. return {
  40. content: '',
  41. currentcontent: '',
  42. editorOption: {
  43. theme: 'snow',
  44. boundary: document.body,
  45. modules: {
  46. toolbar: [
  47. ['bold', 'italic', 'underline', 'strike'],
  48. ['blockquote', 'code-block'],
  49. [
  50. {
  51. header: 1
  52. },
  53. {
  54. header: 2
  55. }
  56. ],
  57. [
  58. {
  59. list: 'ordered'
  60. },
  61. {
  62. list: 'bullet'
  63. }
  64. ],
  65. [
  66. {
  67. script: 'sub'
  68. },
  69. {
  70. script: 'super'
  71. }
  72. ],
  73. [
  74. {
  75. indent: '-1'
  76. },
  77. {
  78. indent: '+1'
  79. }
  80. ],
  81. [
  82. {
  83. direction: 'rtl'
  84. }
  85. ],
  86. [
  87. {
  88. size: ['small', false, 'large', 'huge']
  89. }
  90. ],
  91. [
  92. {
  93. header: [1, 2, 3, 4, 5, 6, false]
  94. }
  95. ],
  96. [
  97. {
  98. color: []
  99. },
  100. {
  101. background: []
  102. }
  103. ],
  104. [
  105. {
  106. font: []
  107. }
  108. ],
  109. [
  110. {
  111. align: []
  112. }
  113. ],
  114. ['clean'],
  115. ['link', 'image', 'video']
  116. ]
  117. },
  118. placeholder: '请在这里开始输入...',
  119. readOnly: false
  120. }
  121. }
  122. },
  123. mounted () {
  124. var vm = this
  125. var imgHandler = async function (state) {
  126. if (state) {
  127. var fileInput = vm.$refs.uniqueId.$el.querySelector('input') // 隐藏的file元素
  128. fileInput.click() // 触发事件
  129. }
  130. }
  131. this.$refs.myTextEditor.quill.getModule('toolbar').addHandler('image', imgHandler)
  132. },
  133. computed: {
  134. editor () {
  135. return this.$refs.myTextEditor.quillEditor
  136. }
  137. },
  138. methods: {
  139. onEditorBlur (editor) {
  140. console.log('editor blur!', editor)
  141. },
  142. onEditorFocus (editor) {
  143. console.log('editor focus!', editor)
  144. },
  145. onEditorReady (editor) {
  146. // this.currentcontent=this.content
  147. console.log('editor ready!', editor)
  148. },
  149. initEditorContent (content) {
  150. this.content = setArticleContent(content)
  151. this.currentcontent = this.content
  152. },
  153. onEditorChange ({ editor, html, text }) {
  154. // console.log('editor change!', editor, html, text)
  155. this.currentcontent = html
  156. this.$emit('contentGet', html)
  157. },
  158. newEditorbeforeupload (file) {
  159. var $uptypes = ['image/jpg', 'image/png', 'image/jpeg']
  160. const isJPG = $uptypes.indexOf(file.type) > -1
  161. const isLt1M = file.size / 1024 / 1024 < 5
  162. if (!isJPG) {
  163. this.$message.error('上传头像图片只能是 JPG/PNG 格式!')
  164. }
  165. if (!isLt1M) {
  166. this.$message.error('上传头像图片大小不能超过 5MB!')
  167. }
  168. return isJPG && isLt1M
  169. },
  170. UploadUrl () {
  171. return (
  172. process.env.VUE_APP_API_BASE_URL + '/zjxl/banner/file'
  173. )
  174. },
  175. fileUpload (file) {
  176. const formData = new FormData()
  177. formData.append('file', file.file)
  178. homeApi.fileUpload(formData).then(res => {
  179. if (res.status === 10000) {
  180. var picUrl = setImgUrl(res.result.fullUri)
  181. var addImgRange = this.$refs.myTextEditor.quill.getSelection()
  182. this.$refs.myTextEditor.quill.insertEmbed(addImgRange != null ? addImgRange.index : 0, 'image', picUrl, res.result.fileName)
  183. } else {
  184. this.$message.error(res.msg)
  185. }
  186. })
  187. },
  188. imgUrlDel () {
  189. var content = imgUrlDel(this.currentcontent)
  190. return content
  191. }
  192. }
  193. }
  194. </script>
  195. <style lang="less">
  196. .quillEditorComponent {
  197. .editor {
  198. line-height: normal !important;
  199. height: 300px;
  200. width: 100%;
  201. }
  202. .ql-container {
  203. height: 70%;
  204. }
  205. .ql-toolbar.ql-snow {
  206. border: 1px solid #e1e1e1;
  207. }
  208. .ql-container.ql-snow {
  209. border: 1px solid #e1e1e1;
  210. }
  211. .ql-snow .ql-tooltip[data-mode='link']::before {
  212. content: '请输入链接地址:';
  213. }
  214. .ql-snow .ql-tooltip.ql-editing a.ql-action::after {
  215. border-right: 0px;
  216. content: '保存';
  217. padding-right: 0px;
  218. }
  219. .ql-snow .ql-tooltip[data-mode='video']::before {
  220. content: '请输入视频地址:';
  221. }
  222. .ql-snow .ql-picker.ql-size .ql-picker-label::before,
  223. .ql-snow .ql-picker.ql-size .ql-picker-item::before {
  224. content: '14px';
  225. }
  226. .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='small']::before,
  227. .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='small']::before {
  228. content: '10px';
  229. }
  230. .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='large']::before,
  231. .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='large']::before {
  232. content: '18px';
  233. }
  234. .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='huge']::before,
  235. .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='huge']::before {
  236. content: '32px';
  237. }
  238. .ql-snow .ql-picker.ql-header .ql-picker-label::before,
  239. .ql-snow .ql-picker.ql-header .ql-picker-item::before {
  240. content: '文本';
  241. }
  242. .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='1']::before,
  243. .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='1']::before {
  244. content: '标题1';
  245. }
  246. .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='2']::before,
  247. .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='2']::before {
  248. content: '标题2';
  249. }
  250. .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='3']::before,
  251. .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='3']::before {
  252. content: '标题3';
  253. }
  254. .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='4']::before,
  255. .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='4']::before {
  256. content: '标题4';
  257. }
  258. .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='5']::before,
  259. .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='5']::before {
  260. content: '标题5';
  261. }
  262. .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='6']::before,
  263. .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='6']::before {
  264. content: '标题6';
  265. }
  266. .ql-snow .ql-picker.ql-font .ql-picker-label::before,
  267. .ql-snow .ql-picker.ql-font .ql-picker-item::before {
  268. content: '标准字体';
  269. }
  270. .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='serif']::before,
  271. .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='serif']::before {
  272. content: '衬线字体';
  273. }
  274. .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='monospace']::before,
  275. .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='monospace']::before {
  276. content: '等宽字体';
  277. }
  278. }
  279. </style>