对于 Vditor 动态修改图片大小的个人解决方案
为什么要解决这个问题?
最近在准备毕业设计,想做个交流平台,在找 MD 编辑器的时候有幸找到 Vditor
能够边渲染边编辑的优秀编辑器。但是在处理图片时发现它不能让用户自定义图片的大小,所以对此寻找解决方案。
可惜的是,想白嫖的方案但没有搜到,在该论坛也发现过有这个需求的开发者,作者也提供了个比较简单的方案,就是通过 css
控制。但是这个并不满足我自定义的需求。
偶然发现点击图片的框框
在点击图片时,我偶然发现有个输入框提供用户进行自定义修改地址等信息。于是我突发奇想往上面添加个修改高度宽度的输入框不就 OK 了嘛~
虽然有点粗糙,【但是本人审美感觉过得去,hhhh】。
框框加上去了,那么如何自定义高度宽度呢?我尝试了各种方式,比如正则匹配将属性然后附加到图片上,又或者直接添加元素。【在测试过程中,MD 的隐藏更新给了我很大的麻烦,但是后面是发现自己脑子 CPU 烧坏了】。
通过记录 md
的同时,修改 HTML
的 display
将高度宽度隐藏起来,那么用户在修改高度和宽度的同时编辑文字不会收到数据的影响。【至于为什么要记录 md,这是因为我后端保存的是 markdown 的语法而不是 html……而且不太想改后端,这很尴尬……不然其实这功能的实现还是比较简单的。】
至于代码我这里直接贴上,希望可以给有想法的人参考下。
let currentImgCount = 0;
// 监听点击事件,监听点击 img
document.onclick = function (event) {
if (event?.target?.nodeName === 'IMG') {
// 追加输入框
let target: HTMLAnchorElement = event.target as HTMLAnchorElement;
let vditorPanel = document.getElementsByClassName('vditor-panel vditor-panel--none');
let imgPanel = vditorPanel[0];
// 创建 span
let heightAndWidthSpan = document.createElement('span');
heightAndWidthSpan.setAttribute('class', 'vditor-tooltipped vditor-tooltipped__n');
heightAndWidthSpan.setAttribute('aria-label', '宽x高');
// 创建 input
let heightAndWidthInput = document.createElement('input');
heightAndWidthInput.setAttribute('class', 'vditor-input');
heightAndWidthInput.setAttribute('placeholder', '输入宽x高');
// 判断是否有过值
let imgId = target.getAttribute('id');
if (imgId) {
let oldPosition = document.getElementById(imgId.replace('img', 'position'));
if (oldPosition) {
let oldInnerText = oldPosition.innerText, oldInnerStr = oldInnerText.replace('{{', '').replace('}}', '');
let oldInnerArr = oldInnerStr.split(','), height = oldInnerArr[0], width = oldInnerArr[1];
heightAndWidthInput.value = `${height}x${width}`.trim();
}
}
// span 追加 input
heightAndWidthSpan.appendChild(heightAndWidthInput);
// imgPanel 追加 heightAndWidthSpan
imgPanel.appendChild(heightAndWidthSpan);
// 回车更新
heightAndWidthInput.onchange = () => {
let val = heightAndWidthInput.value;
let hw = val.split('x');
let tempHeight = Number(hw[0]), tempWidth = Number(hw[1]);
if (tempHeight <= 0 || tempWidth <= 0) {
toast.error('提示提示', '长度和宽度最少要大于0哦~', 1000)
} else if (target) {
let parentEle = target.parentElement;
target.style.height = `${tempHeight}px`;
target.style.width = `${tempWidth}px`;
let alt = target.getAttribute('alt'), positionId = `position-${alt}-${currentImgCount}`;
target.setAttribute('id', `img-${alt}-${currentImgCount}`);
if (parentEle) {
let positionSpan = document.getElementById(positionId);
if (positionSpan) {
parentEle.removeChild(positionSpan);
}
parentEle.innerHTML += `<span id="${positionId}" style="display: none;">{{${tempHeight}, ${tempWidth}}}</span>`;
// 更新值
md.value = editor.getValue();
html.value = editor.getHTML();
// 更新计数器
currentImgCount++;
}
}
}
}
}
数据的渲染怎么办?
这里其实是我自己埋下的坑,因为我后端保存的是
markdown
语法【因为本人觉得markdown
语法存储的字符串比html
少。
因为我们存储时 markdown
的 img
跟随有 {{height, width}}
的数据,那么我们拿回来时,再通过正则匹配筛选带有 {{height, width}}
的 img
标签。而后再更改高度、宽度,最后重新赋值 innertHTML
就 OK 了。
效果就不用展示啦~这里就直接贴代码了。
// 更新图片大小的细节
let imgs = document.getElementsByTagName('img');
let pattern = /{{\d+,(\s)*\d+}}/;
if (imgs && imgs.length > 0) {
for (let img of imgs) {
let imgParentEle = img.parentElement;
if (imgParentEle) {
let innerHtml = imgParentEle.innerHTML
if (pattern.test(innerHtml)) {
let matchs = innerHtml.match(pattern);
if (matchs) {
for (let match of matchs) {
if (match.trim() !== '') {
// 获取高度进行筛选过滤
let matchStr = match.replace('{{', '').replace('}}', ''), matchArr = matchStr.split(',');
let height = matchArr[0], width = matchArr[1];
// 赋值 style
img.style.height = `${height}px`;
img.style.width = `${width}px`;
// 清除 {{number, number}}
imgParentEle.innerHTML = imgParentEle.innerHTML.replace(match, '');
}
}
}
}
}
}
}
希望对有这需求的人有帮助~
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于