富文本编辑器

Nov 23, 2022

富文本编辑器TinyMce

引用

之前项目中有个需求,需要从word中粘贴内容到富文本编辑器里,但是图片并不能正常的显示

踩过很多坑之后,总结出tinymce + powerpaste 可以完美解决 但是官方的powerpaste需要收费,那我就找来了免费的资源

tinymce 大版本4,对应powerpaste-3.3.3-308,

大版本5对应4.0.1-317 >>> powerpaste-4.0.1-317(兼容tinymce5.2.0) 版本再高还没测试过

附带下载地址:https://www.aliyundrive.com/s/KPmUsuWYk9P

案例为Vue3
  • 将powerpaste放入tinymce模块的public文件夹下。放进去后的tinymce文件夹长这样

文件目录
文件目录

  • 然后再index.html中引入tinymce.min.js
<script type="text/javascript" src="/tinymce/js/tinymce/tinymce.min.js"></script>
  • 将powerpaste文件夹复制到tinymce/js/tinymce/plugins

zn7BwR.png
zn7BwR.png

附带自己封装的组件(Vue3版本)

  • 父组件
<template>
    <tiny-mce :age="contents" @updContent="updContent" style="width: 100%"></tiny-mce>
</template>
<script setup lang="ts">
    import TinyMce from "/@/components/TinyMce/index.vue";
    const contents = ref("")
    const updContent = (e:any) =>{
        contents.value = e.content;
    }
</script>
  • TinyMce/index.vue
<template>
    <div class="tinymce-boxz">
        <Editor v-model="content" :init="init"/>
        <!--   可以绑定APIKey 可以在官网注册 当然 是免费的   -->
        <- <Editor v-model="content" :api-key="apiKey" :init="init" /> ->
    </div>
</template>
<script>
import Editor from '@tinymce/tinymce-vue';
import { reactive, ref, toRefs, watch } from 'vue';
export default {
    name: 'tinyMce',
    components: {
        Editor,
    },
    props: ["age"],
    setup(props, {emit}) {
        const content = ref(props.age);
        const tiny = reactive({
            // apiKey: "qagffr3pkuv17a8on1afax661irst1hbr4e6tbv888sz91jc", //https://github.com/tinymce/tinymce-vue/blob/main/src/demo/views/Iframe.vue
            init: {
                language: 'zh_CN', //语言类型
                placeholder: '请输入......', //textarea中的提示信息
                auto_focus : true, // 自动获取焦点
                min_height: 220,
                // height: 500, //注:引入autoresize插件时,此属性失效
                resize: 'true', //编辑器宽高是否可变,false-否,true-高可变,'both'-宽高均可,注意引号
                branding: false, //tiny技术支持信息是否显示
                // statusbar: false,  //最下方的元素路径和字数统计那一栏是否显示
                elementpath: false, //元素路径是否显示
                font_formats:
                    '微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;苹果苹方=PingFang SC,Microsoft YaHei,sans-serif;宋体=simsun,serif;仿宋体=FangSong,serif;黑体=SimHei,sans-serif;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;', //字体样式
                plugins:
                    'powerpaste autoresize print preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media template code codesample table charmap hr pagebreak nonbreaking anchor insertdatetime advlist lists wordcount textpattern autosave emoticons', //插件配置 axupimgs indent2em
                /*// 工具栏
                toolbar: [
                    'fullscreen undo redo restoredraft | ' +
                    'cut copy paste pastetext | ' +
                    'forecolor backcolor bold italic underline strikethrough link anchor | ' +
                    'alignleft aligncenter alignright alignjustify outdent indent | ' +
                    'bullist numlist | ' +
                    'blockquote subscript superscript removeformat ',
                    "styleselect formatselect fontselect fontsizeselect |  " +
                    "table image axupimgs media emoticons charmap hr pagebreak insertdatetime  selectall visualblocks searchreplace | " +
                    "code print preview | " +
                    "indent2em lineheight formatpainter",
                ],
                // 工具栏配置,设为false则隐藏
                // menubar: "file edit my1", //菜单栏配置,设为false则隐藏,不配置则默认显示全部菜单,也可自定义配置--查看 http://tinymce.ax-z.cn/configure/editor-appearance.php --搜索“自定义菜单”*/
                menubar: false,
                toolbar: "undo redo | fullscreen | formatselect alignleft aligncenter alignright alignjustify | link unlink | numlist bullist | image media table | fontselect fontsizeselect forecolor backcolor | bold italic underline strikethrough | indent outdent | superscript subscript | removeformat |",
                toolbar_drawer: "sliding",
                // images_upload_url: '/apib/api-upload/uploadimg',  //后端处理程序的url,建议直接自定义上传函数image_upload_handler,这个就可以不用了
                // images_upload_base_path: '/demo',  //相对基本路径--关于图片上传建议查看--http://tinymce.ax-z.cn/general/upload-images.php
                paste_data_images: true, //图片是否可粘贴
                //此处为图片上传处理函数
                images_upload_handler: (blobInfo, success) => {
                    // 这里用base64的图片形式上传图片,
                    let reader = new FileReader(); //本地预览
                    reader.readAsDataURL(blobInfo.blob());
                    reader.onloadend = function () {
                        const imgbase64 = reader.result;
                        success(imgbase64);
                    };
                },
                file_picker_types: 'file image media', //file image media分别对应三个类型文件的上传:link插件,image和axupimgs插件,media插件。想屏蔽某个插件的上传就去掉对应的参数
                // 文件上传处理函数
                file_picker_callback: function (callback, value, meta) {
                    // 使用案例http://tinymce.ax-z.cn/general/upload-images.php
                    // meta.filetype  //根据这个判断点击的是什么file image media
                    let filetype; //限制文件的上传类型,需要什么就添加什么的后缀
                    if (meta.filetype == 'image') {
                        filetype = '.jpg, .jpeg, .png, .gif, .ico, .svg';
                    } else if (meta.filetype == 'media') {
                        filetype = '.mp3, .mp4, .avi, .mov';
                    } else {
                        filetype = '.pdf555, .txt, .zip, .rar, .7z, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .mp3, .mp4, .jpg, .jpeg, .png, .gif, .ico, .svg';
                    }
                    let inputElem = document.createElement('input'); //创建文件选择
                    inputElem.setAttribute('type', 'file');
                    inputElem.setAttribute('accept', filetype);
                    inputElem.click();
                    inputElem.onchange = () => {
                        let file = inputElem.files[0]; //获取文件信息
                        // 所有都转成base64文件流,来自官方文档 https://www.tiny.cloud/docs/configure/file-image-upload/#file_picker_callback
                        let reader = new FileReader();
                        reader.readAsDataURL(file);
                        reader.onload = function () {
                            // Note: Now we need to register the blob in TinyMCEs image blob
                            // registry. In the next release this part hopefully won't be
                            // necessary, as we are looking to handle it internally.
                            let id = 'blobid' + new Date().getTime();
                            let blobCache = tinymce.activeEditor.editorUpload.blobCache;
                            let base64 = reader.result.split(',')[1];
                            let blobInfo = blobCache.create(id, file, base64);
                            blobCache.add(blobInfo);
                            // call the callback and populate the Title field with the file name
                            callback(blobInfo.blobUri(), {title: file.name});
                        };
                    };
                },
                // 添加word复制粘贴扩展插件
                external_plugins: {
                    powerpaste: '/tinymce/js/tinymce/plugins/powerpaste/powerpaste/plugin.min.js'
                },
                powerpaste_word_import: 'merge', // 参数可以是propmt, merge, clear,效果自行切换对比
                powerpaste_html_import: 'merge', // propmt, merge, clear
                powerpaste_allow_local_images: true,
            },
        });
        const toFather = () => {
            emit('updContent', {content: content.value});
        };
        watch(
            () => content.value,
            () => {
                toFather();
            }
        );
        const eliminate = () => {
            content.value = '';
        };
        return {
            content,
            eliminate,
            ...toRefs(tiny),
        };
    },
};
</script>
<style scoped>
.tinymce-boxz > textarea {
    display: none;
}
</style>
<style>
/* 隐藏apikey没有绑定当前域名的提示 */
.tox-notifications-container .tox-notification--warning {
    display: none !important;
}
.tox.tox-tinymce {
    max-width: 100%;
}
</style>
Back