• vue使用富文本编辑器vue-quill-editor实现配合后台将图片上传至七牛


    一、全局注册:main.js

    import Vue from 'vue'
    import VueQuillEditor, { Quill } from 'vue-quill-editor'
    import { ImageDrop } from 'quill-image-drop-module'
    import ImageResize from 'quill-image-resize-module'
    import 'quill/dist/quill.core.css'
    import 'quill/dist/quill.snow.css'
    import 'quill/dist/quill.bubble.css'
    Quill.register('modules/imageDrop', ImageDrop)
    Quill.register('modules/imageResize', ImageResize)
     
    Vue.use(VueQuillEditor)

    二、在组件中使用editor.vue

    <template>
      <div class="editor">
        <h3 class="otitle">写文章</h3>
        <!-- 编辑器 -->
        <div class="editor_box">
          <quill-editor v-model="content"
                      ref="myQuillEditor"
                      :options="editorOption"
                      @blur="onEditorBlur($event)"
                      @focus="onEditorFocus($event)"
                      @ready="onEditorReady($event)">
          </quill-editor>
        </div>
        <!-- 保存 -->
        <div class="save_box">
          <el-button type="primary" @click="save()" size="mini">保存</el-button>
        </div>
        <!-- 文件上传组件 -->
        <input type="file" value="" name="image" accept="image/*" @change="uploadImg" ref="uploadInput"       class="uploadInput" />
      </div>
    </template>
    <script>
    import { createAPI, addAccessToken, createImgSrc } from '@/utils/request'
    import qs from 'qs'
    import { unloadImg } from '@/utils/qiniu_unload'
    // 编辑器的参数配置
    const toolbarOptions = [
      ['bold', 'italic', 'underline', 'strike'], // 加粗 斜体 下划线 删除线
      ['blockquote', 'code-block'], // 引用  代码块
      // [{ header: 1 }, { header: 2 }], // 1、2 级标题
      [{ list: 'ordered' }
      //  { list: 'bullet' }
      ], // 有序、无序列表
      [{ script: 'sub' }, { script: 'super' }], // 上标/下标
      [{ indent: '-1' }, { indent: '+1' }], // 缩进
      // [{'direction': 'rtl'}], // 文本方向
      [{ size: ['small', false, 'large', 'huge'] }], // 字体大小
      [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
      [{ color: [] }
      //  { background: [] }
      ], // 字体颜色、字体背景颜色
      [{ font: [] }], // 字体种类
      [{ align: [] }], // 对齐方式
      ['clean'], // 清除文本格式
      ['link',
        'image'
        // 'video'
      ] // 链接、图片、视频
    ]
    let iniCont = ''
    let myvue = {
      name: '',
      data () {
        return {
          content: iniCont, // 编辑器内容
          // 工具栏配置
          editorOption: {
            theme: 'snow', // 主题
            placeholder: '您想说点什么?',
            modules: {
              toolbar: {
                container: toolbarOptions,
                // container: "#toolbar",//也可直接指向元素
                handlers: {
                  image: function (value) {
                    if (value) {
                      document.querySelector('.uploadInput').click()
                    } else {
                      this.quill.format('image', false)
                    }
                  }
                  // link: function(value) {
                  //   if (value) {
                  //     var href = prompt('请输入url');
                  //     this.quill.format("link", href);
                  //   } else {
                  //     this.quill.format("link", false);
                  //   }
                  // },
                }
              },
              imageResize: { //设置图片大小
                displayStyles: {
                  backgroundColor: 'black',
                  border: 'none',
                  color: 'white'
                },
                modules: [ 'Resize', 'DisplaySize', 'Toolbar' ]
              }
            }
          },
          header: {
            // token: sessionStorage.token
          }
        }
      },
      computed: {},
      mounted () {},
      methods: {
        // 保存
        save () {
        },
        // 失去焦点
        onEditorBlur (quill) {
          // console.log('editor blur!', quill)
        },
        // 获得焦点
        onEditorFocus (quill) {
          // console.log('editor focus!', quill)
        },
        // 编辑器已准备完成
        onEditorReady (quill) {
          // console.log('editor ready!', quill)
        },
        // 关闭弹窗
        close () {
          this.$refs.uploadInput.value = ''
          this.$store.commit('changeDialog', false)
        },
        // 获取裁剪后的图片
        getCropBlob () {
          let that = this
          that.$refs.cropper.getCropBlob((data) => {
            let _this = this
            unloadImg(data, function (res) {//上传图片
              // 获取富文本组件实例
              let quill = _this.$refs.myQuillEditor.quill
              // 获取光标所在位置
              let length = quill.getSelection().index
              // 插入图片  res.url为服务器返回的图片地址
              quill.insertEmbed(length, 'image', createImgSrc(res.res))
              // 调整光标到最后
              quill.setSelection(length + 1)
            }, function (res) {
              this.$message.error(res.res)
            })
     
            that.close()
          })
        }
      },
      created () {
        
      }
    }
    export default myvue
    </script>
    <style>
    /* 汉化 */
    .ql-container.ql-snow::-webkit-scrollbar {
      display: none;
    }
    .ql-editor::-webkit-scrollbar{
      display: none;
    }
    .ql-snow .ql-tooltip[data-mode=link]::before {
      content: "请输入链接地址:";
    }
    .ql-snow .ql-tooltip.ql-editing a.ql-action::after {
        border-right: 0px;
        content: '保存';
        padding-right: 0px;
    }
     
    .ql-snow .ql-tooltip[data-mode=video]::before {
        content: "请输入视频地址:";
    }
     
    .ql-snow .ql-picker.ql-size .ql-picker-label::before,
    .ql-snow .ql-picker.ql-size .ql-picker-item::before {
      content: '14px';
    }
    .ql-snow .ql-picker.ql-size .ql-picker-label[data-value=small]::before,
    .ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]::before {
      content: '10px';
    }
    .ql-snow .ql-picker.ql-size .ql-picker-label[data-value=large]::before,
    .ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]::before {
      content: '18px';
    }
    .ql-snow .ql-picker.ql-size .ql-picker-label[data-value=huge]::before,
    .ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]::before {
      content: '32px';
    }
     
    .ql-snow .ql-picker.ql-header .ql-picker-label::before,
    .ql-snow .ql-picker.ql-header .ql-picker-item::before {
      content: '文本';
    }
    .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
    .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
      content: '标题1';
    }
    .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
    .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
      content: '标题2';
    }
    .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
    .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
      content: '标题3';
    }
    .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
    .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
      content: '标题4';
    }
    .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
    .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
      content: '标题5';
    }
    .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
    .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
      content: '标题6';
    }
     
    .ql-snow .ql-picker.ql-font .ql-picker-label::before,
    .ql-snow .ql-picker.ql-font .ql-picker-item::before {
      content: '标准字体';
    }
    .ql-snow .ql-picker.ql-font .ql-picker-label[data-value=serif]::before,
    .ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]::before {
      content: '衬线字体';
    }
    .ql-snow .ql-picker.ql-font .ql-picker-label[data-value=monospace]::before,
    .ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before {
      content: '等宽字体';
    }
    </style>
    <style lang='scss' >
    @import './editor.scss';
    </style>

    以上流程是由<input type="file" value="" name="image" accept="image/*" @change="uploadImg" ref="uploadInput" class="uploadInput" />获取文件对象,然后将文件对象传至事先封装好的unloadImg方法中,如果上传成功,则回调方法中返回图片的key,再将拼接的图片插入vue-quill-editor的光标处。

    三、qiniu_unload.js将图片上传至七牛

    import {createAPI, addAccessToken} from '@/utils/request'
    import storeLocal from 'store'
    // import qs from 'qs'
    let uploadToken = storeLocal.get('imgtoken') || 'abcdefg'// 从本地获取图片上传凭证
    let imgcache = ''
    let f1cache = ''
    let f2cache = ''
    // 上传图片
    function unloadImg (data, f1, f2, boot) {
      imgcache = data
      f1cache = f1
      f2cache = f2
      const formdata = new FormData()
      formdata.append('file', data)
      formdata.append('key', 'img_' + new Date().getTime()) // 文件名
      formdata.append('token', uploadToken)
      addAccessToken('no_check')// 由于七牛云token失效返回401与本地后台token失效code码一致,因此在此处传值申明不验证本地登录
        .post('http://upload-z2.qiniup.com/', formdata, {
          validateStatus: status => status === 200
        })
        .then(reponse => {
          let obj = {
            type: true,
            res: reponse.data.key
          }
          f1(obj)// 成功回调
        })
        .catch((response) => {
          if (boot) { // 拦截,防止死循环
            let obj = {
              type: false,
              res: response.data.error
            }
            f2(obj)// 失败回调
          }
          if (response.status === 401) { // 上传的图片token失效
            getTokenAgain()// 获取新的token
          }
        })
    }
     
    // 重新请求token
    function getTokenAgain () {
      addAccessToken()
        .post(createAPI('files/get_token'), '', {
          validateStatus: status => status === 200
        })
        .then(reponse => {
          uploadToken = reponse.data.data.unload_token
          storeLocal.set('imgtoken', uploadToken)
          unloadImg(imgcache, f1cache, f2cache, 1)
        })
        .catch((response) => {
          return false
        })
    }
     
    export {
      unloadImg
    }

    结果展示:

     裁剪工具用的vue-cropper,本文不做详细介绍。

    注意事项

    1、vue-quill-editor插件quill-image-resize-module 报错解决方法

    解决方式就是修改wabpack配置
    webpack.dev.conf.js
    webpack.prod.conf.js 添加上即可解决问题,webpack.dev.conf.js是解决本地运行的问题,webpack.dev.conf.js是解决打包运行出错。

    new webpack.ProvidePlugin({
          'window.Quill': 'quill/dist/quill.js',
          'Quill': 'quill/dist/quill.js'
        })
  • 相关阅读:
    六、显式锁和AQS
    五、原子操作(CAS)
    四、线程的并发工具类
    BZOJ 2176 Strange string ——最小表示法
    BZOJ 2882 工艺 ——后缀自动机 最小表示法
    Codeforces Round #401 (Div. 2)
    BZOJ 2331 [SCOI2011]地板 ——插头DP
    BZOJ 2005 [Noi2010]能量采集 ——Dirichlet积
    BZOJ 1087 [SCOI2005]互不侵犯King ——状压DP
    BZOJ 1072 [SCOI2007]排列perm ——状压DP
  • 原文地址:https://www.cnblogs.com/linfblog/p/12123599.html
Copyright © 2020-2023  润新知