TinyMCE富文本编辑器


TinyMCE中文文档

什么是富文本编辑器

在了解TinyMCE富文本编辑器之前,我们先来了解一下什么是富文本编辑器吧。

富文本编辑器是一种用于创建和编辑富文本内容的工具或应用程序。富文本内容是指包含文本、图像、链接、样式和其他格式化元素的内容,允许用户以更具交互性和美观性的方式编辑文档或文本。
人话就是,富文本编辑器允许用户编写文章时,给文字以各种样式,也能进行各种格式化操作和图片链接的插入。可以让一篇文章更加的美观。

vue项目中使用TinyMCE富文本编辑器

1,安装并引入

下载

npm install tinymce @tinymce/tinymce-vue -S

引入
把node_modules/tinymec下的skins文件夹复制到public文件夹下
最后下载中文语言包,把里面的zh_CN.js也放进
中文语言包下载地址
请添加图片描述

2,封装富文本组件

<template>
    <editor v-html="modelValue" v-model="content" tag-name="div" :init="init" placeholder="请输入正文..." />
</template>

<script >
import { upload } from "@/api/ArticleApis.js";
import tinymce from "tinymce/tinymce";
import Editor from "@tinymce/tinymce-vue";
//根据需要引入
import "tinymce/themes/silver/theme"; // 引用主题文件
import "tinymce/icons/default"; // 引用图标文件
import "tinymce/plugins/link";
import "tinymce/plugins/code";
import "tinymce/plugins/table"; //插入表格
import "tinymce/plugins/autoresize";
import "tinymce/plugins/charmap"; //特殊字符
import "tinymce/plugins/code"; //查看源码
import "tinymce/plugins/codesample"; //插入代码1
import "tinymce/plugins/directionality"; //
import "tinymce/plugins/fullscreen"; //全屏
import "tinymce/plugins/image"; //图片
import "tinymce/plugins/imagetools"; //图片工具
import "tinymce/plugins/importcss"; //图片工具
import "tinymce/plugins/media"; //媒体插入
import "tinymce/plugins/preview"; //预览
import "tinymce/plugins/quickbars"; //快捷菜单
import "tinymce/plugins/searchreplace"; //查询替换
import "tinymce/plugins/tabfocus"; //
import "tinymce/plugins/textpattern"; //
import "tinymce/plugins/emoticons"; //
// import "tinymce/plugins/numlist";
import { onMounted, ref, watch } from "vue";

export default {
    props: ["modelValue"],
    components: {
        editor: Editor,
    },
    emits: { "update:modelValue": null },
    // props: {
    //     modelValue: String,
    // },
    setup(props, context) {
        const init = {
            language_url: "/tinymce/langs/zh_CN.js", // 中文语言包路径
            language: "zh_CN",
            skin_url: "/tinymce/skins/ui/oxide", // skin路径
            content_css: "/tinymce/skins/ui/oxide/content.css", //以css文件方式自定义可编辑区域的css样式,css文件需自己创建并引入
            menubar: false, // 隐藏菜单栏
            autoresize_bottom_margin: 50,
            // max_height: 500,
            // min_height: 350,
            skin: 'oxide-dark',
            //   height: 320,
            toolbar_mode: "none",
            plugins:
                "textpattern  tabfocus  searchreplace  quickbars preview   media  importcss imagetools image  fullscreen emoticons  directionality codesample code charmap link code table  autoresize link", // 插件需要import进来
            toolbar:
                "formats  fontsizeselect fontselect media image  aligncenter alignleft alignright alignjustify underline quicklink h2 h3 blockquote numlist bullist table forecolor backcolor bold italic  strikethrough  charmap link codesample code ",//工具栏展示的
            content_style: "p {margin: 5px 0; font-size: 14px} body { color: #fff; } iframe { border: 1px solid #fff; }",
            fontsize_formats: "12px 14px 16px 18px 24px 36px 48px 56px 72px",
            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;",
            branding: false,
            elementpath: false,
            resize: false, // 禁止改变大小
            statusbar: false, // 隐藏底部状态栏
            // paste_data_images: true, // 允许粘贴图像
            content_style: '#515767', // 设置默认文字颜色
            file_picker_types: "file image media",

            //文件上传
            file_picker_callback: function (callback, value, meta) {
                //文件分类
                var filetype =
                    ".pdf, .txt, .zip, .rar, .7z, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .mp3, .mp4";
                //为不同插件指定文件类型
                switch (meta.filetype) {
                    case "image":
                        filetype = ".jpg, .jpeg, .png, .gif";
                        break;
                    case "media":
                        filetype = ".mp3, .mp4";
                        break;
                    case "file":
                    default:
                }
                //模拟出一个input用于添加本地文件
                var input = document.createElement("input");
                input.setAttribute("type", "file");
                input.setAttribute("accept", filetype);
                input.click();
                input.onchange = function (v) {
                    console.log('v', v)
                    var file = v.target.files[0];
                    var formData = new FormData();
                    formData.append("image", file, file.name);
                    upload(formData).then((res) => {
                        callback(res.data.data, { title: file.name });
                        console.log(res.data.data);
                    });
                };
            },

            //   图片上传
            images_upload_handler: async (blobInfo, success) => {
                //改写,通过自己的upload接口,返回的图片时正常的url格式
                const blob = blobInfo.blob();
                const filename = blobInfo.filename();
                var form = new FormData();

                form.append("image", blob, filename);
                console.log('form', form);
                upload(form).then((res) => {
                    success(res.data.data);
                    console.log(res.data.data);
                });
            },
            codesample_languages: [
                { text: 'HTML/XML', value: 'markup' },
                { text: 'JavaScript', value: 'javascript' },
                { text: 'CSS', value: 'css' },
                { text: 'PHP', value: 'php' },
                { text: 'Ruby', value: 'ruby' },
                { text: 'Python', value: 'python' },
                { text: 'Java', value: 'java' },
                { text: 'C', value: 'c' },
                { text: 'C#', value: 'csharp' },
                { text: 'C++', value: 'cpp' }
            ],
            codesample_content_css: '/static/prism.css',
        };

        const content = ref('');

        onMounted(() => {
            // console.log('props.modelValue', props.modelValue);
            // content.value = props.modelValue;
        });
        watch(
            () => content.value,
            () => {
                console.log('变化了');
                imgsize(content.value);
                revert_data(content.value);
            }
        );
        watch(
            () => props.modelValue,
            () => {
                content.value = props.modelValue;
            }
        );

        // 匹配所有img图片,把所有宽度大于750px的图片等比缩小到750px
        const imgsize = function (img) {
            // 使用正则表达式匹配<img>标签
            const regex = /<img[^>]*\b(?:width|height)\s*=\s*["']?(\d{4,}|[1-9][0-4]\d{2,})["']?\s*[^>]*>/g;
            const matchedImages = img.match(regex);
            console.log('matchedImages', matchedImages);
            if (matchedImages) {
                for (const imgTag of matchedImages) {
                    // 匹配width和height属性的值
                    const widthMatch = imgTag.match(/\bwidth\s*=\s*["']?(\d+)/);
                    const heightMatch = imgTag.match(/\bheight\s*=\s*["']?(\d+)/);

                    if (widthMatch && heightMatch) {
                        const width = parseInt(widthMatch[1]);
                        const height = parseInt(heightMatch[1]);

                        if (width > 850) {
                            // 计算等比缩小后的新高度,保持宽度等于750px
                            const aspectRatio = width / height;
                            const newWidth = 850;
                            const newHeight = Math.round(850 / aspectRatio);

                            // 修改width和height属性的值,确保宽度为750px
                            const updatedImgTag = imgTag.replace(`width="${width}"`, `width="${newWidth}"`).replace(`height="${height}"`, `height="${newHeight}"`);

                            // 替换原始的<img>标签
                            content.value = content.value.replace(imgTag, updatedImgTag);
                        }
                    }
                }
            }
        }

        const revert_data = (content) => {
            //实现数据的双向绑定
            context.emit("update:modelValue", content);
        };

        tinymce.init; // 初始化
        return {
            init,
            revert_data,
            content,
        };
    },
};
</script>

2,使用富文本组件

<div class="form_wrapper">
		<form class="form_main" method="post">
				<div class="tit">
				//如果富文本编辑器有标题栏需要多写一个input框,因为富文本编辑器只有内容框
					<input type="text" placeholder="请输入标题……" v-model="form.title" @input="titL"
						@keydown.enter="handleEnterKey" />
				</div>
				
				//引入并使用富文本组件
				<TEditor ref="editor" :modelValue=richTextContent v-model="state.content" />
		</form>
</div>

<script setup>
let state = reactive({
	content: '', //获取TEditor的内容
});

watch(
	() => state.content,

	() => {
		//监控TEditor内容的变化

		console.log(state.content);

		form.content = state.content;
	}
);
</script>

几个使用中的重难点

1,如何进行上传图片的操作

详细请看http://tinymce.ax-z.cn/general/upload-images.php
TinyMCE为我们提供了 images_upload_handler配置项

images_upload_handler是一个用于处理上传图片的回调函数。它接收三个参数:

  1. blobInfo:表示要上传的图片的信息,包括文件名、大小等。
  2. succFun:表示上传成功时的回调函数。
  3. failFun:表示上传失败时的回调函数。

例如

            //   图片上传
            images_upload_handler: async (blobInfo, success) => {
                //改写,通过自己的upload接口,返回的图片时正常的url格式
                const blob = blobInfo.blob();
                const filename = blobInfo.filename();
                var form = new FormData();

                form.append("image", blob, filename);
                console.log('form', form);
                upload(form).then((res) => {
                    success(res.data.data);
                    console.log(res.data.data);
                });
            },

blobInfo表示要上传的图片的信息,包括图片的二进制数据和文件名。
blobInfo.blob()用于获取图片的二进制数据。
blobInfo.filename()用于获取图片的文件名。
然后创建一个FormData对象,将图片的二进制数据和文件名添加到表单中。再调传入上传图片的api接口,调用success函数并传递上传后的图片URL作为参数。这将通知TinyMCE编辑器上传成功,并将图片URL插入到编辑器中。

2,如何自定义上传后的图片大小

TinyMCE上传完图片后,图片的大小默认为原图片的大小
例如
在这里插入图片描述
打开控制台可以看到图片的实际宽高
在这里插入图片描述

可以看到图片已经超过了富文本框的宽度,那么怎么让上传后的图片等比例缩小为符合富文本框宽度的图片呢?

看到控制台我们知道图片之所以那么大,是因为富文本编辑器默认把图片真实大小也就是1920px设置成了这个img标签的宽度。
所以我们只需要改变这个width和height就行了

实现图片等比例缩小的方法,传入一个富文本,它会匹配这个富文本里的img标签,并查看这个img标签的宽度是否超过了850px,如果超过了就会缩小为850px

        // 匹配所有img图片,把所有宽度大于850px的图片等比缩小到850px
        const imgsize = function (img) {
            // 使用正则表达式匹配<img>标签
            const regex = /<img[^>]*\b(?:width|height)\s*=\s*["']?(\d{4,}|[1-9][0-4]\d{2,})["']?\s*[^>]*>/g;
            const matchedImages = img.match(regex);
            console.log('matchedImages', matchedImages);
            if (matchedImages) {
                for (const imgTag of matchedImages) {
                    // 匹配width和height属性的值
                    const widthMatch = imgTag.match(/\bwidth\s*=\s*["']?(\d+)/);
                    const heightMatch = imgTag.match(/\bheight\s*=\s*["']?(\d+)/);

                    if (widthMatch && heightMatch) {
                        const width = parseInt(widthMatch[1]);
                        const height = parseInt(heightMatch[1]);

                        if (width > 850) {
                            // 计算等比缩小后的新高度,保持宽度等于850px
                            const aspectRatio = width / height;
                            const newWidth = 850;
                            const newHeight = Math.round(850 / aspectRatio);

                            // 修改width和height属性的值,确保宽度为850px
                            const updatedImgTag = imgTag.replace(`width="${width}"`, `width="${newWidth}"`).replace(`height="${height}"`, `height="${newHeight}"`);

                            // 替换原始的<img>标签
                            content.value = content.value.replace(imgTag, updatedImgTag);
                        }
                    }
                }
            }
        }

我们监听这个富文本是否改动,改动就调用imgsize方法

      watch(
            () => content.value,
            () => {
                console.log('变化了');
                imgsize(content.value);
            }
        );

在这里插入图片描述
在这里插入图片描述
可以看到图片已经等比例缩小了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值