vue2中富文本编辑器的使用

251 阅读1分钟

vue-quill-editor

注意: vue-quill-editor不兼容vue3版本

示例代码

<template>
    <div>
    <el-form :model="dynamicValidateForm" ref="dynamicValidateForm" label-width="100px" class="demo-dynamic">
        <el-form-item
              prop="from_official"
              label="官网"
              :rules="[
              { required: true, message: '请选择发布的官网', trigger: 'blur' },
              ]"
          >
            <el-select v-model="dynamicValidateForm.from_official" placeholder="请选择" width="50%">
              <el-option
                v-for="item in FROM_MAP"
                :key="item"
                :label="item"
                :value="item">
              </el-option>
            </el-select>
        </el-form-item>
        <el-form-item
              prop="language"
              label="语言"
              :rules="[
              { required: true, message: '请选择发布的语言', trigger: 'blur' },
              ]"
          >
            <el-select v-model="dynamicValidateForm.language" placeholder="请选择" width="50%">
              <el-option
                v-for="item in languageList"
                :key="item"
                :label="item"
                :value="item">
              </el-option>
            </el-select>
        </el-form-item>
        <el-form-item
            prop="title"
            label="标题"
            :rules="[
            { required: true, message: '请输入文章标题', trigger: 'blur' },
            ]"
        >
            <el-input v-model="dynamicValidateForm.title" placeholder="请输入文章标题"></el-input>
        </el-form-item>
        <el-form-item
            prop="date"
            label="日期"
            :rules="[
            { required: true, message: '请输入文章发布日期', trigger: 'blur' },
            ]"
        >
            <el-input v-model="dynamicValidateForm.date" placeholder="请输入文章发布日期"></el-input>
        </el-form-item>
        <el-form-item
            prop="picture"
            label="封面"
            :rules="[
            { required: true, message: '请输入封面图片url链接或者base64编码', trigger: 'blur' },
            ]"
        >
            <el-input v-model="dynamicValidateForm.picture" placeholder="请输入封面图片链接"></el-input>
            <el-upload action="" :limit="1" :http-request="imgfileChange">上传</el-upload>
        </el-form-item>
        <el-form-item
            prop="content"
            label="正文"
            :rules="[
            { required: true, message: '请编辑正文', trigger: 'blur' },
            ]"
        >
         <quill-editor 
          v-model="dynamicValidateForm.content" 
          :options="editorOption" 
          ref="myQuillEditor" 
          @change="onEditorChange($event)"
          class="news-edit-util"></quill-editor> 
         <el-upload class="avatar-uploader" ref="imgUpload" action="" :limit="1" :http-request="fileChange"></el-upload>
        </el-form-item>
        <el-form-item>
            <el-button @click="reviewEmail"  icon="el-icon-message"  style="margin-top: 20px;">预览</el-button>
            <el-button type="primary" @click="submitForm('dynamicValidateForm')" :disabled="disabled">发布</el-button>
            <el-button @click="resetForm('dynamicValidateForm')">重置</el-button>
            <el-button type="primary" @click="backList">返回发布列表</el-button>
        </el-form-item>
    </el-form>
    <el-drawer
            title="正文预览"
            size="50%"
            :visible.sync="drawer"
            :direction="direction"
    >
        <div v-html="dynamicValidateForm.content" class="previewContainer"></div>
    </el-drawer> 
    <div class="linkDialog">
      <el-input v-model="linkUrl.text" placeholder="请输入链接名称" style="width:200px"></el-input>
      <el-input v-model="linkUrl.href" placeholder="请输入链接url" style="width:200px"></el-input>
      <span slot="footer" class="dialog-footer">
        <el-button @click="handleClose">取 消</el-button>
        <el-button type="primary" @click="linkAdd">确 定</el-button>
      </span>
    </div>
</div>
  </template>
  
  <script>
  import 'quill/dist/quill.core.css';
  import 'quill/dist/quill.snow.css';
  import 'quill/dist/quill.bubble.css';
  import { quillEditor } from 'vue-quill-editor';
  import Quill from 'quill';  //引入编辑器;
  import { dashboardApi } from "@/api/index";
  // 源码中是import直接倒入,这里要用Quill.import引入
  const Link = Quill.import("formats/link");
  // 自定义a链接
  class FileBlot extends Link {
    // 继承Link Blot
    static create (value) {
      let node = undefined;
      if (value && !value.href) {
        // 适应原本的Link Blot
        node = super.create(value)
      } else {
        // 自定义Link Blot
        node = super.create(value.href)
        node.href = value.href
        node.innerText = value.innerText
        // node.setAttribute('download', value.innerText);  // 左键点击即下载
      }
      return node;
    }
  }
  FileBlot.blotName = "link" // 这里不用改,如果需要也可以保留原来的,这里用个新的blot
  FileBlot.tagName = "A"
  Quill.register(FileBlot) // 注册link
  export default {
    components: {
      quillEditor
    },
    data() {
      return {
        content_id: this.$route.query.id,
        type: this.$route.query.type,
        FROM_MAP:['官网A','官网B','APP'],
        languageList:['ZH','EN','FR'],
        linkUrl:{
          href:"",
          text:""
        },
        dynamicValidateForm:{
            from_official: '',
            title:'',
            date:'',
            picture:'',
            content:'',
            language:'',
            type:1,
        },
        dialogVisible:false,
        drawer: false,
        disabled:false,
        direction: 'rtl',
        editorOption: {
          // 富文本编辑器选项
          placeholder: '请输入文章正文内容,支持上传图片,视频',
          theme: 'snow', //主题 snow/bubble
          syntax: true, //语法检测
          modules: {
            toolbar: {
              container:[ ['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': ['black'] }], // 文本颜色、背景颜色
                          [{ 'font': [] }], // 字体
                          [{ 'align': [] }], // 对齐方式
                          ['clean'], // 清除格式
                          ['link', 'image', 'video']// 链接、图片、视频
                        ], 
              handlers: {
                'image': function (value) {
                  if (value) {
                    // 触发input框选择图片文件
                    document.querySelector('.avatar-uploader input').click()
                  }
                },
                'link':function (value) {
                  if (value) {
                    document.querySelector('.linkDialog').style.display = 'block'
                  }
                }
              }
            }
          }
        }
      }
    },
    mounted() {
        this.demand();
    },
    methods: {
      // 值发生变化
      onEditorChange(editor) {
            console.log(editor.html);
      },
      fileChange(file) {
            const reader = new FileReader();
            reader.readAsDataURL(file.file)
            reader.addEventListener('load', () => {
                this.fileUpload(file.file.name, reader.result)
            });
      },
      imgfileChange(file){
        const reader = new FileReader();
            reader.readAsDataURL(file.file)
            reader.addEventListener('load', () => {
                this.fileUpload(file.file.name, reader.result,'picture')
            });
      },
      handleClose(){
        document.querySelector('.linkDialog').style.display = 'none'
        this.linkUrl = {}
      },
      linkAdd(){
        const quill = this.$refs.myQuillEditor.quill;
        // 获取光标所在位置
        let length = quill.getSelection(true).index;
        // 插入链接  res.info为服务器返回的图片地址
        quill.insertEmbed(length, 'link',{ href: this.linkUrl.href, innerText:  this.linkUrl.text }, "api" );
        // 调整光标到最后
        quill.setSelection(length + this.linkUrl.text.length);
        this.handleClose()
      },
      async fileUpload(name, file,type) {
            const params = {
                upload_type: 0,
                file: file,
                filename: name
            }
            try {
                let res = await dashboardApi.fileUpload(params)
                if (res.code === 200) {
                   this.$message.success('上传成功!');
                   if(type&&type==='picture'){
                    this.dynamicValidateForm.picture = res.data.head_img
                    return 
                   }
                    console.log(res.data)
                    const quill = this.$refs.myQuillEditor.quill;
                    // 获取光标所在位置
                    let length = quill.getSelection(true).index;
                    // 插入图片  res.info为服务器返回的图片地址
                    quill.insertEmbed(length, 'image', res.data.head_img);
                    // 调整光标到最后
                    quill.setSelection(length + 1)
                } else {
                    this.$message.error(res.msg);
                }
            } catch (e) {
                console.log(e)
                this.$message.error('图片添加异常');
            }
        },
      async demand() {
        if(this.content_id && this.type === 2){
            
            let res = await dashboardApi.getOfficialNewsList(
                {id:this.content_id, current:1, size:1}
            );
            if (res.code === 200) {
                const details = res.data.list[0]
                this.dynamicValidateForm = {
                  from_official: details.from_official,
                  title:details.title,
                  date:details.date,
                  picture:details.picture,
                  content:details.content,
                  language:details.language,
                }
            } else {
                this.$message.error(res.msg);
            }
        }            
      },
      reviewEmail(){
        this.drawer = true; 
      },
      backList(){
        this.$router.push({name: "websiteNewsList",});
      },
      submitForm(formName) {
        this.$refs[formName].validate(async(valid) => {
          if (valid) {
            let params = this.dynamicValidateForm
            if(this.content_id && this.type === 2){
              params = {
                ...params,
                id: this.content_id,
                type: this.type
              }
            }
            this.disabled = true
            let res = await dashboardApi.getOfficialNewsData(params);
            if (res.code === 200) {
              this.$message.success('发布成功!');
            }else{
              this.$message.error(res.msg);
            }
            this.disabled = false
          } else {
            console.log('error submit!!');
            return false;
          }
        });
      },
      resetForm(formName) {
        this.$refs[formName].resetFields();
      }
    } 
  }
</script>
<style scoped>

.linkDialog{
  width: fit-content;
  position: fixed;
  top:50%;
  left:50%;
  transform: translate(-50%,-50%);
  background-color: #fff;
  display: none;
}

</style>