Vditor 动态修改图片大小的个人解决方案

本贴最后更新于 774 天前,其中的信息可能已经时移俗易

对于 Vditor 动态修改图片大小的个人解决方案

为什么要解决这个问题?

最近在准备毕业设计,想做个交流平台,在找 MD 编辑器的时候有幸找到 Vditor 能够边渲染边编辑的优秀编辑器。但是在处理图片时发现它不能让用户自定义图片的大小,所以对此寻找解决方案。

可惜的是,想白嫖的方案但没有搜到,在该论坛也发现过有这个需求的开发者,作者也提供了个比较简单的方案,就是通过 css 控制。但是这个并不满足我自定义的需求。

偶然发现点击图片的框框

在点击图片时,我偶然发现有个输入框提供用户进行自定义修改地址等信息。于是我突发奇想往上面添加个修改高度宽度的输入框不就 OK 了嘛~

image.png

虽然有点粗糙,【但是本人审美感觉过得去,hhhh】。

框框加上去了,那么如何自定义高度宽度呢?我尝试了各种方式,比如正则匹配将属性然后附加到图片上,又或者直接添加元素。【在测试过程中,MD 的隐藏更新给了我很大的麻烦,但是后面是发现自己脑子 CPU 烧坏了】

image.png

通过记录 md 的同时,修改 HTMLdisplay 将高度宽度隐藏起来,那么用户在修改高度和宽度的同时编辑文字不会收到数据的影响。【至于为什么要记录 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 少。

因为我们存储时 markdownimg 跟随有 {{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, '');
                  }
                }
              }

            }
          }
        }
      }

希望对有这需求的人有帮助~

  • Vditor

    Vditor 是一款浏览器端的 Markdown 编辑器,支持所见即所得、即时渲染(类似 Typora)和分屏预览模式。它使用 TypeScript 实现,支持原生 JavaScript、Vue、React 和 Angular。

    352 引用 • 1815 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • huangtao

    我觉得可以修改宽度就行,宽高度同时修改有可能使图标比例失调, 希望官方能考虑加上修改图片宽度的功能

  • 其他回帖
  • huangtao

    最后有解决办法吗?支持针对某个图片单独设置尺寸,并且导出 md 和 html 也是带尺寸属性的。