|  |  |  | 
|---|
|  |  |  | <template> | 
|---|
|  |  |  | <div style="border: 1px solid #ccc;"> | 
|---|
|  |  |  | <div class="wang_editor"> | 
|---|
|  |  |  | <Toolbar | 
|---|
|  |  |  | style="border-bottom: 1px solid #ccc" | 
|---|
|  |  |  | :editor="editor" | 
|---|
|  |  |  | :defaultConfig="toolbarConfig" | 
|---|
|  |  |  | :default-config="toolbarConfig" | 
|---|
|  |  |  | :mode="mode" | 
|---|
|  |  |  | /> | 
|---|
|  |  |  | <Editor | 
|---|
|  |  |  | style="height: 300px; overflow-y: hidden;" | 
|---|
|  |  |  | :value="content.content" | 
|---|
|  |  |  | v-model="html" | 
|---|
|  |  |  | style="min-height: 200px" | 
|---|
|  |  |  | :default-config="editorConfig" | 
|---|
|  |  |  | :mode="mode" | 
|---|
|  |  |  | :defaultConfig="editorConfig" | 
|---|
|  |  |  | @onCreated="onCreated" | 
|---|
|  |  |  | @onChange="onChange" | 
|---|
|  |  |  | @input="html=$event" | 
|---|
|  |  |  | /> | 
|---|
|  |  |  | </div> | 
|---|
|  |  |  | </template> | 
|---|
|  |  |  |  | 
|---|
|  |  |  | <script> | 
|---|
|  |  |  | import { Editor, Toolbar } from '@wangeditor/editor-for-vue' | 
|---|
|  |  |  | import '@wangeditor/editor/dist/css/style.css' | 
|---|
|  |  |  | import axios from 'axios' | 
|---|
|  |  |  |  | 
|---|
|  |  |  | import { uploadFile } from '@/api' | 
|---|
|  |  |  |  | 
|---|
|  |  |  | const uploadConfig = { | 
|---|
|  |  |  | action: uploadFile, // 必填参数 图片上传地址 | 
|---|
|  |  |  | methods: 'POST', // 必填参数 图片上传方式 | 
|---|
|  |  |  | token: '', // 可选参数 如果需要token验证,假设你的token有存放在sessionStorage | 
|---|
|  |  |  | name: 'file', // 必填参数 文件的参数名 | 
|---|
|  |  |  | size: 500, // 可选参数   图片大小,单位为Kb, 1M = 1024Kb | 
|---|
|  |  |  | accept: 'image/png, image/gif, image/jpeg, image/bmp, image/x-icon' // 可选 可上传的图片格式 | 
|---|
|  |  |  | } | 
|---|
|  |  |  | export default { | 
|---|
|  |  |  | name: 'RichEditor', | 
|---|
|  |  |  | components: { Editor, Toolbar }, | 
|---|
|  |  |  | components: { | 
|---|
|  |  |  | Editor, | 
|---|
|  |  |  | Toolbar | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | props: { | 
|---|
|  |  |  | content: { | 
|---|
|  |  |  | type: Object, | 
|---|
|  |  |  | default: () => {} | 
|---|
|  |  |  | info: { | 
|---|
|  |  |  | type: String, | 
|---|
|  |  |  | default: '' | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | default: { | 
|---|
|  |  |  | type: String, | 
|---|
|  |  |  | default: '' | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | placeholder: { | 
|---|
|  |  |  | type: String, | 
|---|
|  |  |  | default: '请输入内容...' | 
|---|
|  |  |  | } | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | data() { | 
|---|
|  |  |  | data () { | 
|---|
|  |  |  | return { | 
|---|
|  |  |  | editor: null, | 
|---|
|  |  |  | html: '<p><br></p>', | 
|---|
|  |  |  | toolbarConfig: { | 
|---|
|  |  |  | toolbarKeys: [ | 
|---|
|  |  |  | "headerSelect", | 
|---|
|  |  |  | "blockquote", | 
|---|
|  |  |  | "|", | 
|---|
|  |  |  | "bold", | 
|---|
|  |  |  | "underline", | 
|---|
|  |  |  | "italic", | 
|---|
|  |  |  | { | 
|---|
|  |  |  | "key": "group-more-style", | 
|---|
|  |  |  | "title": "更多", | 
|---|
|  |  |  | "iconSvg": "<svg viewBox=\"0 0 1024 1024\"><path d=\"M204.8 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z\"></path><path d=\"M505.6 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z\"></path><path d=\"M806.4 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z\"></path></svg>", | 
|---|
|  |  |  | "menuKeys": [ | 
|---|
|  |  |  | "through", | 
|---|
|  |  |  | "code", | 
|---|
|  |  |  | "sup", | 
|---|
|  |  |  | "sub", | 
|---|
|  |  |  | "clearStyle" | 
|---|
|  |  |  | ] | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | "color", | 
|---|
|  |  |  | "bgColor", | 
|---|
|  |  |  | "|", | 
|---|
|  |  |  | "fontSize", | 
|---|
|  |  |  | "fontFamily", | 
|---|
|  |  |  | "lineHeight", | 
|---|
|  |  |  | "|", | 
|---|
|  |  |  | "bulletedList", | 
|---|
|  |  |  | "numberedList", | 
|---|
|  |  |  | "todo", | 
|---|
|  |  |  | { | 
|---|
|  |  |  | "key": "group-justify", | 
|---|
|  |  |  | "title": "对齐", | 
|---|
|  |  |  | "iconSvg": "<svg viewBox=\"0 0 1024 1024\"><path d=\"M768 793.6v102.4H51.2v-102.4h716.8z m204.8-230.4v102.4H51.2v-102.4h921.6z m-204.8-230.4v102.4H51.2v-102.4h716.8zM972.8 102.4v102.4H51.2V102.4h921.6z\"></path></svg>", | 
|---|
|  |  |  | "menuKeys": [ | 
|---|
|  |  |  | "justifyLeft", | 
|---|
|  |  |  | "justifyRight", | 
|---|
|  |  |  | "justifyCenter", | 
|---|
|  |  |  | "justifyJustify" | 
|---|
|  |  |  | ] | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | { | 
|---|
|  |  |  | "key": "group-indent", | 
|---|
|  |  |  | "title": "缩进", | 
|---|
|  |  |  | "iconSvg": "<svg viewBox=\"0 0 1024 1024\"><path d=\"M0 64h1024v128H0z m384 192h640v128H384z m0 192h640v128H384z m0 192h640v128H384zM0 832h1024v128H0z m0-128V320l256 192z\"></path></svg>", | 
|---|
|  |  |  | "menuKeys": [ | 
|---|
|  |  |  | "indent", | 
|---|
|  |  |  | "delIndent" | 
|---|
|  |  |  | ] | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | // "|", | 
|---|
|  |  |  | "emotion", | 
|---|
|  |  |  | "insertLink", | 
|---|
|  |  |  | { | 
|---|
|  |  |  | "key": "group-image", | 
|---|
|  |  |  | "title": "图片", | 
|---|
|  |  |  | "iconSvg": "<svg viewBox=\"0 0 1024 1024\"><path d=\"M959.877 128l0.123 0.123v767.775l-0.123 0.122H64.102l-0.122-0.122V128.123l0.122-0.123h895.775zM960 64H64C28.795 64 0 92.795 0 128v768c0 35.205 28.795 64 64 64h896c35.205 0 64-28.795 64-64V128c0-35.205-28.795-64-64-64zM832 288.01c0 53.023-42.988 96.01-96.01 96.01s-96.01-42.987-96.01-96.01S682.967 192 735.99 192 832 234.988 832 288.01zM896 832H128V704l224.01-384 256 320h64l224.01-192z\"></path></svg>", | 
|---|
|  |  |  | "menuKeys": [ | 
|---|
|  |  |  | "insertImage", | 
|---|
|  |  |  | "uploadImage" | 
|---|
|  |  |  | ] | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | "insertTable", | 
|---|
|  |  |  | "codeBlock", | 
|---|
|  |  |  | "divider", | 
|---|
|  |  |  | "|", | 
|---|
|  |  |  | "undo", | 
|---|
|  |  |  | "redo", | 
|---|
|  |  |  | "|", | 
|---|
|  |  |  | "fullScreen" | 
|---|
|  |  |  | ] | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | toolbarConfig: {}, | 
|---|
|  |  |  | editorConfig: { | 
|---|
|  |  |  | placeholder: '请输入内容...', | 
|---|
|  |  |  | placeholder: this.placeholder, | 
|---|
|  |  |  | MENU_CONF: { | 
|---|
|  |  |  | uploadImage: { | 
|---|
|  |  |  | // server: '/api/upload', | 
|---|
|  |  |  | name: 'file', | 
|---|
|  |  |  | server: process.env.VUE_APP_API_PREFIX + '/public/uploadLocal', | 
|---|
|  |  |  | html: this.info, | 
|---|
|  |  |  | server: uploadFile, | 
|---|
|  |  |  | // 单个文件的最大体积限制,默认为 2M | 
|---|
|  |  |  | maxFileSize: 5 * 1024 * 1024, // 1M | 
|---|
|  |  |  | // 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 [] | 
|---|
|  |  |  | allowedFileTypes: ['image/*'], | 
|---|
|  |  |  | // 自定义上传参数,例如传递验证的 token 等。参数会被添加到 formData 中,一起上传到服务端 | 
|---|
|  |  |  | meta: { | 
|---|
|  |  |  | folder: 'shop' | 
|---|
|  |  |  | token: '', | 
|---|
|  |  |  | otherKey: '', | 
|---|
|  |  |  | folder: 'COURSE_IMG' | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | onBeforeUpload(file) {    // JS 语法 | 
|---|
|  |  |  | // file 选中的文件,格式如 { key: file } | 
|---|
|  |  |  | // debugger | 
|---|
|  |  |  | return file | 
|---|
|  |  |  | // 自定义增加 http  header | 
|---|
|  |  |  | headers: { | 
|---|
|  |  |  | token: localStorage.getItem('token') || '' | 
|---|
|  |  |  | // Accept: 'text/x-json', | 
|---|
|  |  |  | // otherKey: 'xxx' | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | onSuccess(file, res) { | 
|---|
|  |  |  | console.log(`${file.name} 上传成功`, res) | 
|---|
|  |  |  | // 跨域是否传递 cookie ,默认为 false | 
|---|
|  |  |  | withCredentials: true, | 
|---|
|  |  |  | // 超时时间,默认为 10 秒 | 
|---|
|  |  |  | timeout: 5 * 1000, // 5 秒 | 
|---|
|  |  |  | onSuccess (file, res) { // TS 语法 | 
|---|
|  |  |  | // onSuccess(file, res) {          // JS 语法 | 
|---|
|  |  |  | console.log(`${file.name} 上传成功`, res) | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | onError(file, err, res) { | 
|---|
|  |  |  | console.log(`${file.name} 上传出错`, err, res) | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | customUpload (file, insertFn) { // TS 语法 | 
|---|
|  |  |  | // file 即选中的文件 | 
|---|
|  |  |  | // 自己实现上传,并得到图片 url alt href | 
|---|
|  |  |  | // var form = new FormData() | 
|---|
|  |  |  | // form.append('image', file) | 
|---|
|  |  |  | // form.append('folder', 'COURSE_IMG') | 
|---|
|  |  |  | var formData = new FormData() | 
|---|
|  |  |  | formData.append(file.name, file) | 
|---|
|  |  |  | formData.append('image', file) | 
|---|
|  |  |  | formData.append('folder', 'member') | 
|---|
|  |  |  | // formData.append('type', '') | 
|---|
|  |  |  |  | 
|---|
|  |  |  | var xhr = new XMLHttpRequest() | 
|---|
|  |  |  | xhr.open(uploadConfig.methods, uploadConfig.action, true) | 
|---|
|  |  |  | // 上传数据成功,会触发 | 
|---|
|  |  |  | xhr.send(formData) | 
|---|
|  |  |  | xhr.onreadystatechange = () => { | 
|---|
|  |  |  | // 若响应完成且请求成功 | 
|---|
|  |  |  | if (xhr.readyState === 4 && xhr.status === 200) { | 
|---|
|  |  |  | const result = JSON.parse(xhr.responseText) | 
|---|
|  |  |  | console.log('result', result); | 
|---|
|  |  |  | insertFn(result.data.url, '', result.data.url) | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | customInsert (res, insertFn) { // TS 语法 | 
|---|
|  |  |  | // customInsert(res, insertFn) {                  // JS 语法 | 
|---|
|  |  |  | // res 即服务端的返回结果 | 
|---|
|  |  |  | console.log(res.data.url) | 
|---|
|  |  |  | // 从 res 中找到 url alt href ,然后插入图片 | 
|---|
|  |  |  | insertFn(res.url) | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | mode: 'default', // or 'simple' | 
|---|
|  |  |  | mode: 'default' // or 'simple' | 
|---|
|  |  |  | } | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | beforeDestroy() { | 
|---|
|  |  |  | emits: ['input'], | 
|---|
|  |  |  | computed: { | 
|---|
|  |  |  | html: { | 
|---|
|  |  |  | get () { | 
|---|
|  |  |  | return this.info || '' | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | set (newValue) { | 
|---|
|  |  |  | this.$emit('input', newValue) | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | mounted () { | 
|---|
|  |  |  | setTimeout(() => { | 
|---|
|  |  |  | this.info = this.default | 
|---|
|  |  |  | }, 1200) | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | beforeDestroy () { | 
|---|
|  |  |  | const editor = this.editor | 
|---|
|  |  |  | if (editor == null) return | 
|---|
|  |  |  | editor.destroy() // 组件销毁时,及时销毁编辑器 | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | methods: { | 
|---|
|  |  |  | onCreated (editor) { | 
|---|
|  |  |  | this.editor = Object.seal(editor) | 
|---|
|  |  |  | this.editor = Object.seal(editor) // 一定要用 Object.seal() ,否则会报错 | 
|---|
|  |  |  | this.$emit('input', '123123') | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | onChange (editor) { | 
|---|
|  |  |  | console.log(this.html); | 
|---|
|  |  |  | // debugger | 
|---|
|  |  |  | if (!this.html||this.content.content==this.html) { | 
|---|
|  |  |  | return | 
|---|
|  |  |  | } | 
|---|
|  |  |  | this.$emit('edit', this.html) | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | }, | 
|---|
|  |  |  |  | 
|---|
|  |  |  | test () { | 
|---|
|  |  |  | console.log(this.info) | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | </script> | 
|---|
|  |  |  |  | 
|---|
|  |  |  | <style src="@wangeditor/editor/dist/css/style.css"></style> | 
|---|
|  |  |  | <style lang="scss" scoped> | 
|---|
|  |  |  | .wang_editor { | 
|---|
|  |  |  | border: 1px solid; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | </style> | 
|---|