基於nuxt和iview搭建OM後臺管理系統實踐(2)-quill富文本組件的封裝

封面圖,使用創客貼製做.png

目錄結構

這是《基於nuxt和iview搭建OM後臺管理系統實踐》這一個系列文章的目錄,大體思路以下:css

前言

上一篇簡要介紹了一下這個項目的項目背景,從這一篇開始我會寫開發公共組件的過程,這一篇講解一下富文本編輯器quill的集成吧。html

少廢話,看東西

如動圖所示,爲後臺管理系統添加內容的功能頁面,能夠看到已經集成了上傳圖片組件和富文本編輯器組件。
富文本編輯器和上傳組件的結合使用前端

富文本編輯器

這個富文本集成了quill這個開源庫 [[quill中文文檔]](https://github.com/BingKui/Qu...。在vue-cli構建的項目中直接引用quill的包一點問題都沒有,可是我用的nuxt.js是基於服務端渲染的,多數狀況下會報下面這個錯誤:vue

window is not defined

這是由於window對象只存在於瀏覽器端,服務端渲染的時候是不存在window對象的。那麼我應該怎麼作呢??ios

報錯信息展現

我仍是直接上代碼吧:git

  • 第一步在plugins下新建quill插件文件nuxt-quill-plugins.js
// 文件plugins/nuxt-quill-plugins.js
import Vue from 'vue'
// import VueQuillEditor from 'vue-quill-editor'
// Vue.use(VueQuillEditor) 直接引用會報錯

if (process.browser) {
//加一個瀏覽器端判斷,只在瀏覽器端才渲染就不會報錯了
  const VueQuillEditor = require('vue-quill-editor/dist/ssr')
  Vue.use(VueQuillEditor)
}
  • 第二步以插件形式配置quill
//文件nuxt.config.js,省略其餘代碼
plugins: [
    '~plugins/iview-ui',
    '~plugins/qs',
    '~plugins/urlencode',
    {src: '~plugins/nuxt-quill-plugin.js',ssr: false}
],
  • 第三步開始封裝組件
//文件 components/full-editor.vue
<template>
  <section class="container">
    <!-- <form id="uploadForm"> -->
    <input class="file" type="file" style="display:none" id="file" ref="input" @change="doUpload">
    <!-- </form> -->
    <div class="quill-editor"
        ref="myQuillEditor" 
         :content="content"
         @change="onEditorChange($event)"
         @blur="onEditorBlur($event)"
         @focus="onEditorFocus($event)"
         @ready="onEditorReady($event)"
         v-quill:myQuillEditor="editorOption">
    </div>
  </section>
</template>

<script>
import {qiniuConfig,quillEditorConfig} from '~/config';//七牛上傳和富文本toolbar配置文件
const QiniuUPToken = require('qiniu-uptoken');//前端生成七牛上傳token
import axios from '~/plugins/axios';

export default {
  name: "full-editor",
  head() {
    return {
      link: [
        {
          href: "/full-editor/quill.core.css",
          rel: "stylesheet"
        },
        {
          href: "/full-editor/quill.snow.css",
          rel: "stylesheet"
        },
        {
          href: "/full-editor/quill.bubble.css",
          rel: "stylesheet"
        }
      ]
    };
  },
  data() {
    const self = this;
    return {
      content: "",
      editorOption: {
        // some quill options
        modules: {
          toolbar: {
            container:quillEditorConfig.toolbarOptions,
            handlers:{
              'image':function(){
                // console.log(this)
                this.quill.format('image', false);//禁用quill內部上傳圖片方法
                self.imgHandler(this)
              }
            }
          },
        },
        placeholder: '請輸入信息',
        theme: "snow",
        quill:''
      }
    };
  },
  mounted() {
    // console.log("app init");
  },
  methods: {
    onEditorBlur(editor) {
      // console.log("editor blur!", editor);
    },
    onEditorFocus(editor) {
      // console.log("editor focus!", editor);
    },
    onEditorReady(editor) {
      // console.log("editor ready!", editor);
    },
    onEditorChange({ editor, html, text }) {
      // console.log("editor change!", editor, html, text);
      this.content = html;
      this.$emit('editorContent',html)
      // console.log(this.content);
    },
    imgHandler(handle){
      this.quill = handle.quill;
      var inputfile = document.getElementById('file');
      inputfile.click();
    },
    doUpload(){
      let files = document.getElementById('file');
      // console.log(files.files[0]);
      let uptoken = QiniuUPToken(qiniuConfig.access_key,qiniuConfig.secret_key,qiniuConfig.bucketname)
      // console.log(uptoken);   
      this.qiniuUpload(files.files[0],uptoken);
    },
    qiniuUpload(file, token){
      let param = new FormData(); //建立form對象
      param.append('file',file,file.name);//經過append向form對象添加數據
      param.append('token',token);//添加form表單中其餘數據
      // console.log(param. `get('file')); //FormData私有類對象,訪問不到,能夠經過get判斷值是否傳進去
      let config = {
        headers:{'Content-Type':'multipart/form-data'}
      }; //添加請求頭
      axios.post(qiniuConfig.action_url,param,config)
      .then(res=>{
        // console.log(res);
        // console.log(this.quill);
        let length = this.quill.getSelection().index;
        const imgUrl = qiniuConfig.pic_hostname+res.key;//插入上傳的圖片
        this.quill.insertEmbed(length, 'image', imgUrl);
        // this.quill.insertEmbed(index, 'image', imgUrl);//插入上傳的圖片
        // console.log(res.data);
      })
      .then((err)=>{
        // console.log(err)
      })

    }
  }
};
</script>

<style  scoped>
.container {
  width: 100%;
  margin: 0 auto;
  /* padding: 10px 0; */
}
.quill-editor {
  min-height: 200px;
  max-height: 400px;
  overflow-y: auto;
}
</style>

封裝組件須要注意的幾個點:github

  • 在組件頁面(head方法)引用css樣式,不要全局引用,head方法的配置具體參考nuxt官方文檔,這裏不作過多贅述
<script>
export default {
    head() {
        return {
          link: [
            {
              href: "/full-editor/quill.core.css",
              rel: "stylesheet"
            },
            {
              href: "/full-editor/quill.snow.css",
              rel: "stylesheet"
            },
            {
              href: "/full-editor/quill.bubble.css",
              rel: "stylesheet"
            }
          ]
        };
     },
}
</script>
  • 爲了保持代碼的簡介,我這裏把quill工具欄的配置文件放到了config/index.js文件裏了
//  文件config/index.js

/**
 * @description 富文本編輯器quill的配置文件
 * @argument 參考文檔https://sheweifan.github.io/2018/01/07/nuxt-quill-qiniu/
 * @argument quill中文文檔https://github.com/BingKui/QuillChineseDoc/blob/master/SUMMARY.md
 */
export const quillEditorConfig = {
  toolbarOptions:[
    ["bold", "italic", "underline", "strike"], // 切換按鈕
    ["blockquote", "code-block"],
    // [{ header: 1 }, { header: 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: [] }],
    ['image'],//上傳圖片
    ['video'],//視頻
    ["clean"] // 清除格式
  ]
}
  • 組件原生圖片上傳是直接把圖片處理成base64位的存儲,我這裏爲了存儲方便,會把圖片上傳到七牛上,這裏也遇到了一點小坑。首先要禁用quill內部上傳圖片方法,而後用一個隱藏的input[type=file]實現選擇圖片,而後模擬七牛表單提交不刷新的操做,最終實現圖片上傳七牛(還得在前端應用一個庫生成token),以上完整代碼裏有呈現。

實現的邏輯

  • 編輯時須要傳遞content到子組件我這裏用的ref
// 父組件
<template>
  <div class="body">
    <full-editor
        ref="myFullEditor"
        v-model="formItem.body"
        @editorContent="editorContent"
        >
    </full-editor>
  </div>
</template>
<script>
const fullEditor = () => import("@/components/full-editor");
export default {
  layout: "nav",
  components: {
    fullEditor
  },
  mounted() {
    this.loadData();//加載數據
    this.$refs.myFullEditor.content = this.body;//父組件給富文本編輯器傳遞值
  }
}
</script>

總結

封裝一個富文本組件,開始作以前覺得會蠻容易的,覺得就引用一下就就能夠了,沒想到會遇到以上的那些坑,最終在百度和翻閱github後很好的解決了問題,最終也封裝完成也知足了需求,後續我會找個時間剔除一些業務代碼把組件放到github上。vue-cli

相關文章
相關標籤/搜索