• Vue的富文本插件(vue-quill-editor和tinymce)


    一.使用vue-quill-editor实现富文本编辑器

    Quill官方开发文档:https://www.kancloud.cn/liuwave/quill/1409423

    1.安装依赖:npm install vue-quill-editor –save

    2.在main.js或者需要用到此富文本的页面引入插件和Css:

           import { quillEditor } from "vue-quill-editor";
           import "quill/dist/quill.core.css";
           import "quill/dist/quill.snow.css";
           import "quill/dist/quill.bubble.css";
    3.挂在组件:
          export default { components{ quillEditor }
    4.自定义toolbar菜单
         
          content: '', //富文本的内容
          editorOption: {
            modules: {
            toolbar: [
            [
            "bold",
             "italic",
            "underline",
            "strike",
            "link",
             "image",
             "code-block",
           ], // toggled buttons  
             [{ 'align': [] }],    //对齐方式
            [{ 'header': [1, 2, 3, 4, 5, 6, false] }],     //几级标题
             [{ 'font': [] }],     //字体 
             [{ 'size': ['small', 'normal', 'large', 'huge'] }],
           [{ 'color': [] }, { 'background': [] }],     // 字体颜色,字体背景颜色 
             ],
           },
          },

     也可直接写editorOption:{},即会出现所有的工具栏

     5.在你想要用的位置用即可

    <el-form-item label="内容:"
                          prop="content">
              <quill-editor ref="text"
                            v-model="content"
                            class="myQuillEditor"
                            :options="editorOption" />
            </el-form-item>

    6.最终效果

     总的来说:vue-quill-editor还是比较简单的,用起来很方便,基本功能也有,一般的业务需求用这款富文本编辑器也还是比较合适的

                    注:引入的Css样式,手机端无法解析,无法适配手机端样式,故如需适配手机端样式,还是不要用这个了!

                           我也是因为这个原因不得不换了其他富文本编辑器

                           我这里用到的是Tinymce

    二:使用Tinymce实现富文本编辑器,功能更多,插件丰富,多语言支持

           中文文档:http://tinymce.ax-z.cn/

    1.安装插件:npm install @tinymce/tinymce-vue@3.2.2 tinymce@5.3.1 -S

    2.在项目中的public下新建tinymce文件夹,把node_modules中的skins文件夹,将skins文件夹拷贝到public的tinymce目录下。接着去官网下载语言包,解压,将langs文件夹拷贝到public的tinymce文件夹下(和skins文件夹同级)

    3.在components文件夹下新建tinymce组件的文件夹,新建index.vue文件,复制以下代码进去:

    <template>
     <div class="tinymce-editor">
      <Editor
       :id="editorId"
       v-model="editorValue"
       :init="editorInit"
      />
     </div>
    </template>
     
    <script>
    
    //引入上传图片
    import { getToken } from '../../utils/auth'
    import axios from 'axios'
    // 引入组件
    import tinymce from 'tinymce/tinymce';
    import Editor from '@tinymce/tinymce-vue';
    import 'tinymce/icons/default/icons';
    import 'tinymce/themes/silver';
    // 引入富文本编辑器主题的js和css
    import 'tinymce/themes/silver/theme.min';
    import 'tinymce/skins/ui/oxide/skin.min.css';
    // 扩展插件
    import 'tinymce/plugins/image';
    import 'tinymce/plugins/link';
    import 'tinymce/plugins/code';
    import 'tinymce/plugins/table';
    import 'tinymce/plugins/lists';
    import 'tinymce/plugins/wordcount'; // 字数统计插件
    import 'tinymce/plugins/media';// 插入视频插件
    import 'tinymce/plugins/template';// 模板插件
    import 'tinymce/plugins/fullscreen';
    import 'tinymce/plugins/paste';
    import 'tinymce/plugins/preview';
    import 'tinymce/plugins/contextmenu';
    import 'tinymce/plugins/textcolor';
    
    export default {
     name: 'TinymceEditor',
     components: {Editor},
     props: {
      height: {
       type: Number,
       default: 500
      },
      id: {
       type: String,
       default: 'tinymceEditor'
      },
      value: {
       type: String,
       default: ''
      },
      plugins: {
       type: [String, Array],
       default: 'link lists image code table wordcount media fullscreen preview paste contextmenu textcolor'
      },
      toolbar: {
       type: [String, Array],
       default: 'fontselect| fontsizeselect | bold italic underline strikethrough table fullscreen  | link  image media  | undo redo  | alignleft aligncenter alignright alignjustify | bullist numlist | forecolor backcolor | outdent indent blockquote | code | removeformat'
      }
     },
     data() {
      return {
       editorInit: {
        language_url: `/tinymce/langs/zh_CN.js`,
        language: 'zh_CN',
        skin_url: `/tinymce/skins/ui/oxide`,
        content_css: `/tinymce/skins/content/default/content.css`,
        content_style: '* { padding:0; margin:0; } img {max-100% !important }',
        plugin_preview_ 375, // 预览宽度
        plugin_preview_height: 200,
        lineheight_val: "1 1.1 1.2 1.3 1.35 1.4 1.5 1.55 1.6 1.75 1.8 1.9 1.95 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 3 3.1 3.2 3.3 3.4 4 5",
        fontsize_formats: "8pt 10pt 11pt 12pt 13pt 14pt 15pt 16pt 17pt 18pt 24pt 36pt",
        font_formats:"微软雅黑='微软雅黑';宋体='宋体';黑体='黑体';仿宋='仿宋';楷体='楷体';隶书='隶书';幼圆='幼圆';Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings",
        plugins: this.plugins,
        powerpaste_word_import: 'merge',
        toolbar: this.toolbar,
        height:400,
        media_live_embeds:true,//视频的内嵌代码预览是否开启,为ture时富文本编辑框可实现预览功能
        paste_data_images: true,
        statusbar: true, // 底部的状态栏
        menubar: false, // 最上方的菜单
        branding: false, // 水印“Powered by TinyMCE”
        images_upload_handler: (blobInfo, success, failure) => {
        //  this.$emit('handleImgUpload', blobInfo, success, failure);
        this.handleImgUpload(blobInfo, success, failure)
        },
        //自定义逻辑替换 Tinymce 的默认媒体嵌入逻辑   
       },
       editorId: this.id,
       newValue: ''
      };
     },
     watch: {
      newValue(newValue) {
       this.$emit('input', newValue);
      }
     },
     mounted() {
      tinymce.init({});
     },
     computed: {
      editorValue: {
       get() {
        return this.value;
       },
       set(val) {
        this.newValue = val;
       }
      }
     },
     methods: {
        // 上传本地 图片执行事件
        handleImgUpload(blobInfo, success, failure) {
          console.log('llllllllllllllllllllll');
          let formdata = new FormData()
          // append 方法中的第一个参数就是 我们要上传文件 在后台接收的文件名
          // 这个值要根据后台来定义
          // 第二个参数是我们上传的文件
          formdata.append('file', blobInfo.blob())
          // axios 定义上传方法
          axios({
            method: "post", // post方法
            url: "http://112.156.20.36:18000/manage/manage/file/uploadFile", // 请求上传图片服务器的路径
            headers: {
            'Authorization': 'Bearer ' + getToken(),'Content-Type': 'application/x-www-form-urlencoded', // 采用表单上传的方式,看后台如何接受
            },
            data: formdata // 请求数据formdata
          }).then(res => {
            if (res.data.code != 200) {
              // 上传失败执行此方法,将失败信息填入参数中
              failure('HTTP Error: ' + res.msg);
              return
            }
            // 上传成功之后,将对应完整的图片路径拼接在success的参数中
            success(res.data.msg);
          })
        },
     
      clear() {
       this.editorValue = '';
      }
     }
    };
    </script>

    图片上传,请是根据自己的实际情况做相应的更改

    4.在你需要用到此富文本插件的页面引入插件,和挂载插件

      import TinymceEditor from '@/components/tinymce';

      components: { TinymceEditor},

    5.在使用的位置使用即可

      <el-form-item label="内容:" prop="content">
                  <tinymce-editor
                  id="editor"
                  ref="editor"
                  v-model="formInline.content"
                  style="60%;"
                 />
            </el-form-item>

    此刻,你不需要上传视频文件的需求等那么基本功能就可以实现了

    如果,你要上传视频,就会出现视频无法预览的问题,此刻如果视频是内嵌视频代码地址,只需要

     media_live_embeds:true,//视频的内嵌代码预览是否开启,为ture时富文本编辑框可实现预览功能

    如果不是内嵌视频,是普通视频的话,那就需要

    1.打开node_modules->tinymce->plugins->media文件夹下的plugin.js文件作以下更改

      将此段代码注释

    2.创建一个全局变量来存video的src 

    3.在注释的代码下添加如下代码:

    if(node.name === 'video' && hasLiveEmbeds(editor) && global$8.ceFalse){
                console.log('videoSource===', videoSource)
                videoSource = ''
                if(node.attributes['map'] && node.attributes['map'].src){
                  videoSource = node.attributes['map'].src
                }else{
                  for(var ii=0;ii<node.attributes.length;ii++){
                    if(node.attributes[ii].name == "src"){
                      videoSource = node.map.node.attributes[ii].value
                    }
                  }
                }
                if(node.firstChild && node.firstChild.value){
                  var elel=node.firstChild && node.firstChild.value
                  var objE = document.createElement("div");
                 objE.innerHTML = elel;
                  var dom = objE.getElementsByTagName('source')[0]
                  videoSource = dom.getAttribute('src')
                }
                node.replace(createPreviewIframeNode(editor, node));
              }

    4.修改此文件中createPreviewIframeNode方法(仅两处)

     var createPreviewIframeNode = function (editor, node) {
          var previewWrapper;
          var previewNode;
          var shimNode;
          var name = node.name;
          previewWrapper = new global$7('span', 1);
          previewWrapper.attr({
            'contentEditable': 'false',
            'style': node.attr('style'),
            'data-mce-object': name,
            'class': 'mce-preview-object mce-object-' + name
          });
          retainAttributesAndInnerHtml(editor, node, previewWrapper);
          previewNode = new global$7(name, 1);
          previewNode.attr({
            // src: node.attr('src'),
            src: videoSource || node.attr('src'), // 修改
            controls: 'controls',    // 新增
            allowfullscreen: node.attr('allowfullscreen'),
            style: node.attr('style'),
            class: node.attr('class'),
             node.attr('width'),
            height: node.attr('height'),
            frameborder: '0'
          });
          shimNode = new global$7('span', 1);
          shimNode.attr('class', 'mce-shim');
          previewWrapper.append(previewNode);
          previewWrapper.append(shimNode);
          return previewWrapper;
        };

    此时就显示正确了,内嵌视频和普通视频都可预览了,完美

    参考文章:https://blog.csdn.net/Colourfuljia/article/details/108400662?utm_medium=distribute.pc_relevant.none-task-blog-OPENSEARCH-5.not_use_machine_learn_pai&depth_1-utm_source=distribute.pc_relevant.none-task-blog-OPENSEARCH-5.not_use_machine_learn_pai

  • 相关阅读:
    ThreadLocal垮线程池传递数据解决方案:TransmittableThreadLocal
    java steam 使用指南groupingBy进阶用法
    微言Netty:百万并发基石上的epoll之剑
    ES聚合查询详解(一)
    肝了一个月的Netty知识点(上)
    kafka 如何保证消息不丢失
    IO多路复用
    Java 重入锁
    Kotlin中的协程和多线程比较实验
    mysql性能排查思路
  • 原文地址:https://www.cnblogs.com/qingfengyuan/p/14239754.html
Copyright © 2020-2023  润新知