ckEditor5富文本编译器Classic版本插入图片后平铺过大:调整

1,122 阅读6分钟

一、前言

ckEditor5插件,上传图片的时候,大图会默认铺满整个编辑框,就需要用户手动调整。 图片边缘的手柄在大图上并不显眼,非开发人员可能不知道拖动手柄可以自定义图片大小,就有了这个需求-用户希望图片一上传/插入就缩放到一个合适的图片尺寸。

这个问题在2023年6月就有人在github官方提出了,#issue15148,标题是Inserting images should default to 50% of the editable, 链接🔗 github.com/ckeditor/ck…

问题描述具体现象如下图所示:⬇️

1.图片上传/插入的默认效果:

image.png

2.期望的图片上传/插入效果:

image.png

官方考虑到多种兼容因素没有修改,issue一直处于open状态,只能自己再看看了~

在查看文档的过程中,我发现官方提供了ImageResize来一键控制图片大小。但是遇到两个问题:

问题1.classic版本中并不支持ImageResize

image.png

image.png 除了Document和Superbuild,其它类型都是❌,天姥爷😭;

问题2.用ImageResize也不能做到图片一上传/插入,就缩放到合适的大小,只是提供了一键缩放的按钮

二、实现思路

根据imageResize的实现效果,自定义了两个按钮样式,可以将图片一键缩放到原图的25%50%大小,分别用于处理高比宽大的图(比如手机截图)和比较方正的图片(根据实践,高比宽大的图缩放至25%、方正的图缩放到50%比较合适)。

宽比高大的长方形的图不缩放,因为这种长方形的图铺满编译器展示刚好合适。尺寸比较小的图片,也不需要缩放的。所以拿到图片的宽高后,需要自定义判断是否是否符合缩放条件。

与此同时,图片上传后点击通栏显示还能恢复到平铺的效果;

总结:预先设置自定义图片和图片按钮样式->捕获图片上传/插入/粘贴事件->拿到图片的宽和高,判断该图片是否满足缩放条件;

三、涉及到的插件源文件改动

文件1:ckeditor.js配置文件,路径:src->ckeditor.js

文件2:imageuploadui.js图片上传文件,路径:node_modules>@ckeditor>ckeditor5-image>src>imageupload>imageuploadui.js

文件3:clipboard.js 复制粘贴图片插入文件,路径:node_modules>@ckeditor>ckeditor5-clipboard>src>clipboard.js

文件4:imagestyle.css 图片应用类样式文件,路径:node_modules>@ckeditor>ckeditor5-image>theme>imgestyle.css

文件5:utils.js 图片按钮配置文件,路径:node_modules>@ckeditor>ckeditor5-image>src>imagestyle>utils.js

注:不同版本可能文件位置会有点区别

四、修改

1.ckeditor.js

配置上25%和50%的自定义按钮

 image: {
    toolbar: ['imageStyle:selfConfigQuarter', 'imageStyle:selfConfigHalf', '|', 'imageStyle:alignLeft', 'imageStyle:full', 'imageStyle:alignRight'],
    styles: ['selfConfigQuarter', 'selfConfigHalf', 'full', 'alignLeft', 'alignRight'],
  },

其中,imageStyle:selfConfigQuarter和imageStyle:selfConfigHalf是两个自定义的按钮。

2.imageuploadui.js

修改view.on(‘done’)函数,在图片上传成功后,通过官方提供的editor.execute( 'imageStyle', { value: 'xxx' } ); 这个commonAPI对图片应用自定义的样式;因为ckEditor中上传的图片是FILE资源,不是image,只有图片的size属性,没有宽高,所以要读取FILE文件,创建一个新的Image对象,用于显示读取到的图像数据;

image.png

	view.on( 'done', ( evt, files ) => {
				const imagesToUpload = Array.from( files ).filter( file => imageTypesRegExp.test( file.type ) );

				if ( imagesToUpload.length ) {
					editor.execute( 'imageUpload', { file: imagesToUpload } );
					if( imagesToUpload.length === 1){
						const firstFile = imagesToUpload[0];
						const reader = new FileReader();
						reader.onload = function( event ) {
							const img = new Image();
							img.onload = function() {
								if(img.width > 380 && img.width < 2500 && img.height/img.width > 1.5 ){
									// 长图
									editor.execute( 'imageStyle', { value: 'selfConfigQuarter' } );
								}else if(img.width >= 2500 || (img.width/img.height < 1.8) ){
									// 宽图
									editor.execute( 'imageStyle', { value: 'selfConfigHalf' } );
								}
							};
						img.src = event.target.result; 
					};
						reader.readAsDataURL( firstFile );
					}
				}
			} );

3.clipboard.js

处理了图片上传,要继续处理文件粘贴/插入/剪切的情况,在clipboard.js文件中,粘贴、插入都会执行 { priority: 'highest' },所以修改输入为(evt,data)从data中拿到当前输入的数据,后续同上传图片操作一样,读取FILE文件的。

当一个文件被选择并且它是一个图像文件时,代码使用FileReader对象的readAsDataURL方法来读取文件内容。这个方法将文件读取为一个DataURL,这是一个包含文件的Base64编码的字符串。

一旦文件读取完成,FileReader的onload事件被触发,这时event.target.result将包含图像的DataURL。然后,这个DataURL被设置为Image对象的src属性,这将导致图像开始加载。

当图像加载完成时,Image对象的onload事件被触发。在这个事件处理器中,你可以访问Image对象的width和height属性,这两个属性分别表示图像的原始宽度和高度(以像素为单位)

	this.listenTo( viewDocument, 'clipboardInput', ( evt, data ) => {
			
			if( data.dataTransfer.files.length === 1 ){
				const img = data.dataTransfer.files[0]
				var reader = new FileReader();
				reader.onload = function( evt ){
					img.src = evt.target.result
					var image = new Image()
					image.src = evt.target.result
					image.onload = function() {
						if( this.width > 380 && this.width < 2500 && this.height/this.width > 1.5 ){
							editor.execute( 'imageStyle', { value: 'selfConfigQuarter' } );
						}else if( this.width >= 2500 || (this.width/this.height < 1.8)){
							editor.execute( 'imageStyle', { value: 'selfConfigHalf' } );
						}
					}
				}
			reader.readAsDataURL( img );
		}

			if ( editor.isReadOnly ) {
				evt.stop();
			}
		}, { priority: 'highest' } );

4.imagestyle.css

首先,因为用户觉得图片过大,所以我将源插件中图片居左、居右...对其,改成了25%。同时,对50%大小的缩放图片,使用该操作的时候,也可以看到50%->25%的明显效果(此时的小图片,用户再用图片四周的手柄调整宽高较于铺满屏幕的大图也会更加方便)

.ck-content {
	& .image-style-side,
	& .image-style-align-left,
	& .image-style-align-center,
	& .image-style-align-right {
		max-width: 25%;
	}

然后,添加了两个按钮的自定义样式,分别是25%和50%,居中对齐!

	& .self-config-half {
		margin-left: auto;
		margin-right: auto;
		max-width: 50%;
	}

	& .self-config-quarter{
		margin-left: auto;
		margin-right: auto;
		max-width: 25%;
	}

5.utils.js

step1:引入自定义按钮的图片

import quarterSize from '@ckeditor/ckeditor5-core/theme/icons/object-size-quarter.svg'
import halfSize from '@ckeditor/ckeditor5-core/theme/icons/object-size-half.svg'

step2:Icons注册

const defaultIcons = {
	full: fullWidthIcon,
	left: leftIcon,
	right: rightIcon,
	center: centerIcon,
	quater: quarterSize, // 25%
	half: halfSize // 50%
};

step3:设置按钮 在defaultStyles={...}中添加

selfConfigQuarter: {
		name: 'selfConfigQuarter',
		title: '图片调整为25%',
		icon: quarterSize,
		className: 'self-config-quarter'
	},
	selfConfigHalf: {
		name: 'selfConfigHalf',
		title: '图片调整为50%',
		icon: halfSize,
		className: 'self-config-half'
	},

五、实现效果

而且用户点通栏展示的时候还可以恢复到原图大小~

1.之前~大图上传后默认铺满,大到放不下

image.png

### 2.现在~图片上传后默认采用自定义样式,对应按钮生效👇

image.png

image.png

3.点原来的通栏设置,还能恢复到原图铺满的效果

image.png

六、一些尝试:

1.改全局样式

修改全局样式是不行的,我尝试修改了image.css文件内部的max-width,100%->50%。结果是图片初始化的时候,外层的方框线与图片大小对不上,且拖动手柄放大只能到50%,想继续放大就会被外层的方框线顶住编译器,继续放大失败...所以这样肯定是不行的啦~

image.png

2.设置isDefault为true

读官方文档的时候,看到图片默认的是full 通栏展示,有一个isDefault:true 的设置,后来发现这个设置并不是默认应用哪个样式,而是用来标记该样式是否配置中的默认选项。用了之后,对应的图片栏的按钮,和通栏展示是同样的效果(这个按钮没用咯)~

image.png

3.暂时无法兼容批量操作

因为editor.execute( 'imageStyle', { value: 'xxx' } ); 只对当前选中的图片生效!批量操作会默认选中最后一张🙄️🙄️🙄️