【VUE+Element】vue-quill-editor的使用,上傳圖片+音頻+視頻+自定義上傳方式

效果:

1、引入vue-quill-editor

cnpm install vue-quill-editor

2、使用vue-quill-editor

template:

<!-- 上傳組件輔助-->
        <el-upload class="avatar-uploader-editor" :action="serverUrl" name="img" :headers="header" :show-file-list="false"
          :on-success="uploadSuccess" :on-error="uploadError"> </el-upload>
        <el-upload class="avatar-uploader-editor-video" :action="serverUrl" name="video" :headers="header" :show-file-list="false"
          :on-success="uploadSuccessVideo" :on-error="uploadError"> </el-upload>
        <el-upload class="avatar-uploader-editor-voice" :action="serverUrl" name="voice" :headers="header" :show-file-list="false"
          :on-success="uploadSuccessVoice" :on-error="uploadError"> </el-upload>

<quill-editor v-model="content" ref="myQuillEditor" style="height: 500px;margin-top: -22px;" :options="editorOption">
          <div id="toolbar" slot="toolbar"> 
            <button class="ql-bold" title="加粗">Bold</button>
            <button class="ql-italic" title="斜體">Italic</button>
            <button class="ql-underline" title="下劃線">underline</button>
            <button class="ql-strike" title="刪除線">strike</button>
            <button class="ql-blockquote" title="引用"></button>
            <button class="ql-code-block" title="代碼"></button>
            <button class="ql-header" value="1" title="標題1"></button>
            <button class="ql-header" value="2" title="標題2"></button>
            <button class="ql-list" value="ordered" title="有序列表"></button>
            <button class="ql-list" value="bullet" title="無序列表"></button>
            <select class="ql-header" title="段落格式">
              <option selected>段落</option>
              <option value="1">標題1</option>
              <option value="2">標題2</option>
              <option value="3">標題3</option>
              <option value="4">標題4</option>
              <option value="5">標題5</option>
              <option value="6">標題6</option>
            </select>
            <select class="ql-size" title="字體大小">
              <option value="10px">10px</option>
              <option value="12px">12px</option>
              <option value="14px">14px</option>
              <option value="16px" selected>16px</option>
              <option value="18px">18px</option>
              <option value="20px">20px</option>
              <option value="30px">30px</option>
            </select>
            <select class="ql-font" title="字體">                                        
              <option value="SimSun">宋體</option>
              <option value="SimHei">黑體</option>
              <option value="Microsoft-YaHei">微軟雅黑</option>
              <option value="KaiTi">楷體</option>
              <option value="FangSong">仿宋</option>
              <option value="Arial">Arial</option>
            </select>
            <select class="ql-color" value="color" title="字體顏色"></select>
            <select class="ql-background" value="background" title="背景顏色"></select>
            <select class="ql-align" value="align" title="對齊"></select> 
            <button class="ql-clean" title="清除字體樣式"></button> 
            <button class="ql-image" title="圖片"></button> 
            <button class="ql-video" title="視頻"></button> 
            <button class="ql-audio" title="音頻"><i class="el-icon-headset"></i></button> 
          </div>  
        </quill-editor>

注意1:

<button class="ql-audio" title="音頻"><i class="el-icon-headset"></i></button>

此行爲新加的標籤,以此方式引用,簡單又有頁面效果!

注意2:

在上傳視頻、音頻、圖片時,用到了element上傳文件組件

  • 先引入上傳文件組件,再對組件進行隱藏
  • 對上傳文件組件添加class,方便後期引用!
  • 對三個組件的上傳成功的方法分別寫,因爲處理方式不同

 

script:

import {
    Quill,quillEditor
  } from 'vue-quill-editor'
  import 'quill/dist/quill.core.css'
  import 'quill/dist/quill.snow.css'
  import 'quill/dist/quill.bubble.css'

  // 自定義字體大小
  let Size = Quill.import('attributors/style/size')
  Size.whitelist = ['10px', '12px', '14px', '16px', '18px', '20px', '30px']
  Quill.register(Size, true)

  // 自定義字體類型
  var fonts = ['SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong', 'Arial', 'Times-New-Roman', 'sans-serif',
    '宋體', '黑體'] 
  var Font = Quill.import('formats/font')
  Font.whitelist = fonts
  Quill.register(Font, true) 

//視頻標籤插入(樣式保持寬度100%)
import Video from './video.js'
Quill.register(Video, true)

  //音頻標籤插入
  import Audio from './audio.js'
  Quill.register(Audio, true) 
export default {
    components: {
      quillEditor
    },
    data() {
      return {
        content: '',
        editorOption: {
          placeholder: "請輸入", //文章初始化提示語
          theme: "snow", // or 'bubble' 
          modules: {
            toolbar: {
              container: '#toolbar',
              handlers: {
                'image': function (value) {
                  if (value) {
                    // 觸發input框選擇圖片文件                    
                    document.querySelector('.avatar-uploader-editor input').click()
                  } else {
                    this.quill.format('image', false);
                  }
                },
                'video': function (value) {
                  if (value) {
                    // 觸發input框選擇視頻文件                    
                    document.querySelector('.avatar-uploader-editor-video input').click()
                  } else {
                    this.quill.format('video', false);
                  }
                },
                'audio': function (value) {
                  if (value) {
                    // 觸發input框選擇音頻文件                    
                    document.querySelector('.avatar-uploader-editor-voice input').click()
                  } else {
                    this.quill.format('audio', false);
                  }
                },
              }
            }
          }
        },
        serverUrl: '/api/files/headUpload', //上傳的圖片服務器地址
      }
    },
methods: {
      // 富文本圖片上傳成功
      uploadSuccess(res,file) {
        // console.log(res)
        let quill = this.$refs.myQuillEditor.quill
        // 如果上傳成功        
        if (res.code == 0) {
          // 獲取光標所在位置          
          let length = quill.getSelection().index;
          // 插入圖片res.url爲服務器返回的圖片地址
          quill.insertEmbed(length, 'image', res.data.url)
          // 調整光標到最後         
          quill.setSelection(length + 1)
        } else {
          this.$message.error('圖片插入失敗')
        }
      },
//上傳視頻
      uploadSuccessVideo(res,file) {
        let quill = this.$refs.myQuillEditor.quill
        // 如果上傳成功        
        if (res.code == 0) {
          // 獲取光標所在位置          
          let length = quill.getSelection().index;
          // 插入圖片res.url爲服務器返回的地址  
          quill.insertEmbed(length, 'video', res.data.url) 
          // 調整光標到最後            
          quill.setSelection(length + 1) 
        } else {
          this.$message.error('視頻插入失敗')
        }
      },
//上傳音頻-處理很重要!!!!
      uploadSuccessVoice(res,file) {
          let quill = this.$refs.myQuillEditor.quill
        // 如果上傳成功        
        if (res.code == 0) {
          // 獲取光標所在位置          
          let length = quill.getSelection().index;
          let BlockEmbed = Quill.import('blots/block/embed');
          class AudioBlot extends BlockEmbed {
            static create(value) {
                let node = super.create();
                node.setAttribute('src', res.data.url);      //設置audio的src屬性
                node.setAttribute('controls', true);      //設置audio的controls,否則他將不會顯示
                node.setAttribute('controlsList', 'nodownload');      //設置audio的下載功能爲不能下載
                node.setAttribute('id', 'voice');         //設置一個id
                return node;
            }
          }
        AudioBlot.blotName = 'audio';
        AudioBlot.tagName = 'audio';      //自定義的標籤爲audio
        Quill.register(AudioBlot);
        
        // insertEmbed(index: Number(插入的位置), type: String(標籤類型), value: any(參數,將傳入到create的方法中去), source: String = 'api')
        quill.insertEmbed(length, 'audio', res.data.url);
        quill.setSelection(length + 1);  //光標位置向後移動一位
        
        } else {
          this.$message.error('音頻插入失敗')
        }
      },
      // 富文本圖片/視頻/音頻上傳失敗   
      uploadError() {
        this.$message.error('插入失敗')
      },
}
}

style:

.avatar-uploader-editor{
    display: inline-block;
  }
  .avatar-uploader-editor-video{
    display: inline-block;
  }
  .avatar-uploader-editor-voice{
    display: inline-block;
  }

引入資源:video.js

import { Quill } from 'vue-quill-editor'

// 源碼中是import直接倒入,這裏要用Quill.import引入
const BlockEmbed = Quill.import('blots/block/embed')
const Link = Quill.import('formats/link')

const ATTRIBUTES = ['height', 'width']

class Video extends BlockEmbed {
  static create (value) {
    const node = super.create(value)
    // 添加video標籤所需的屬性
    node.setAttribute('controls', 'controls') // 控制播放器
    //刪除原生video的控制條的下載或者全屏按鈕的方法
    //<video controls controlsList='nofullscreen nodownload noremote footbar' ></video>
    //不用哪個在下面加上哪個
    node.setAttribute('controlsList', 'nofullscreen') // 控制刪除
    node.setAttribute('type', 'video/mp4')
    node.setAttribute('style', 'object-fit:fill;width: 100%;')
    node.setAttribute('preload', 'auto')    // auto - 當頁面加載後載入整個視頻  meta - 當頁面加載後只載入元數據  none - 當頁面加載後不載入視頻
    node.setAttribute('playsinline', 'true')
    node.setAttribute('x-webkit-airplay', 'allow')
    // node.setAttribute('x5-video-player-type', 'h5') // 啓用H5播放器,是wechat安卓版特性
    node.setAttribute('x5-video-orientation', 'portraint') // 豎屏播放 聲明瞭h5才能使用  播放器支付的方向,landscape橫屏,portraint豎屏,默認值爲豎屏
    node.setAttribute('x5-playsinline', 'true') // 兼容安卓 不全屏播放
    node.setAttribute('x5-video-player-fullscreen', 'true')    // 全屏設置,設置爲 true 是防止橫屏
    node.setAttribute('src', this.sanitize(value))
    return node
  }

  static formats (domNode) {
    return ATTRIBUTES.reduce((formats, attribute) => {
      if (domNode.hasAttribute(attribute)) {
        formats[attribute] = domNode.getAttribute(attribute)
      }
      return formats
    }, {})
  }

  static sanitize (url) {
    return Link.sanitize(url) // eslint-disable-line import/no-named-as-default-member
  }

  static value (domNode) {
    return domNode.getAttribute('src')
  }

  format (name, value) {
    if (ATTRIBUTES.indexOf(name) > -1) {
      if (value) {
        this.domNode.setAttribute(name, value)
      } else {
        this.domNode.removeAttribute(name)
      }
    } else {
      super.format(name, value)
    }
  }

  html () {
    const { video } = this.value()
    return `<a href="${video}">${video}</a>`
  }
}
Video.blotName = 'video' // 這裏不用改,樓主不用iframe,直接替換掉原來,如果需要也可以保留原來的,這裏用個新的blot
Video.className = 'ql-video'
Video.tagName = 'video' // 用video標籤替換iframe

export default Video

audio.js

import { Quill } from 'vue-quill-editor'

// 源碼中是import直接倒入,這裏要用Quill.import引入
const BlockEmbed = Quill.import('blots/block/embed')
const Link = Quill.import('formats/link')

const ATTRIBUTES = ['height', 'width']

class audio extends BlockEmbed {
  static create (value) {
    const node = super.create(value)
    // 添加audio標籤所需的屬性
    node.setAttribute('controls', 'controls')
    node.setAttribute('type', 'audio/mp4')
    node.setAttribute('src', this.sanitize(value))
    return node
  }

  static formats (domNode) {
    return ATTRIBUTES.reduce((formats, attribute) => {
      if (domNode.hasAttribute(attribute)) {
        formats[attribute] = domNode.getAttribute(attribute)
      }
      return formats
    }, {})
  }

  static sanitize (url) {
    return Link.sanitize(url) // eslint-disable-line import/no-named-as-default-member
  }

  static value (domNode) {
    return domNode.getAttribute('src')
  }

  format (name, value) {
    if (ATTRIBUTES.indexOf(name) > -1) {
      if (value) {
        this.domNode.setAttribute(name, value)
      } else {
        this.domNode.removeAttribute(name)
      }
    } else {
      super.format(name, value)
    }
  }

  html () {
    const { audio } = this.value()
    return `<a href="${audio}">${audio}</a>`
  }
}
audio.blotName = 'audio' // 這裏不用改,樓主不用iframe,直接替換掉原來,如果需要也可以保留原來的,這裏用個新的blot
audio.className = 'ql-audio'
audio.tagName = 'audio' // 用audio標籤替換iframe

export default audio

font.css(此文件爲修改編輯器的樣式,必引!)

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=SimSun]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=SimSun]::before {
  content: "宋體";
  font-family: "SimSun";
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=SimHei]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=SimHei]::before {
  content: "黑體";
  font-family: "SimHei";
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Microsoft-YaHei]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Microsoft-YaHei]::before {
  content: "微軟雅黑";
  font-family: "Microsoft YaHei";
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=KaiTi]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=KaiTi]::before {
  content: "楷體";
  font-family: "KaiTi";
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=FangSong]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=FangSong]::before {
  content: "仿宋";
  font-family: "FangSong";
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Arial]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Arial]::before {
  content: "Arial";
  font-family: "Arial";
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Times-New-Roman]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Times-New-Roman]::before {
  content: "Times New Roman";
  font-family: "Times New Roman";
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=sans-serif]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=sans-serif]::before {
  content: "sans-serif";
  font-family: "sans-serif";
}

.ql-font-SimSun {
  font-family: "SimSun";
}

.ql-font-SimHei {
  font-family: "SimHei";
}

.ql-font-Microsoft-YaHei {
  font-family: "Microsoft YaHei";
}

.ql-font-KaiTi {
  font-family: "KaiTi";
}

.ql-font-FangSong {
  font-family: "FangSong";
}

.ql-font-Arial {
  font-family: "Arial";
}

.ql-font-Times-New-Roman {
  font-family: "Times New Roman";
}

.ql-font-sans-serif {
  font-family: "sans-serif";
}

複製粘貼即可實現!調研N久,拿走不謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章