JS之我用单img元素实现了图像resize拉伸效果

这篇文章发布于 2022年11月20日,星期日,19:10,归类于 JS实例。 阅读 13208 次, 今日 2 次 6 条评论

 

欢迎光临,效果先行:

上为视频,不动轻戳。

如果您是使用PC机器阅读的本文,也可以点击此页面实际操作感受下。

如果查看源码,会发现只有个 img 元素,并无任何其他辅助:

img源码

如何实现的呢?下面是正文↓

一、背景之工作需求

最近在做富文本编辑器相关的需求,其中就有上传图片后需要对图片进行拉伸的需求。

比方说下图所示的交互就是腾讯文档中的图片缩放效果:

拖拽示意

我以前也多次实现过(图片上传,头像上传,以及一些工具类产品),不过实现方式都是 <img> 元素外面包裹个 DIV,然后定位一些方框框,然后再去拉伸。

如果是非编辑器产品,这么实现并没有多大的问题。

但是如果是需要实时编辑的产品,IMG外面还有其他标签,势必会影响很多编辑操作。当然,还有方法就是JS定位,拖拽层覆盖在图像上,从技术成本上讲,也是一个不错的实现,但如果页面发生了滚动,或者拖拽很快,拖拽的小方块就有可能跟不上(具体要看你的实现)。

所以我就在想,以如今的Web能力,有没有可能无需任何其他借助,单单就一个 <img> 标签,就实现图像的拉伸效果呢?

我脑中迅速遍历了下我所知的技术点,貌似理论上可行。

然后……

二、并没有预想的顺利

原本的设计稿是这样的:

设计效果

四个角四个圆圈圈,比较简洁,凡是这种在元素边框(不包括边角)包含规则图形(没有图形也是一种规律)的效果,一定是使用CSS border-image 属性。

CSS border-image 属性可以无限外扩,不占据布局空间,非常强,具体语法参见 《CSS新世界》对应章节,高级应用参见“被低估的border-image属性”一文。

然而,border-image 属性想要使用顺畅,需要设计师的素材配合,需要按照九宫格布局进行设计,下面就是我在 PS 中给设计师绘制的结构示意:

九宫格分割示意

随后设计师按照此示意结构将图形矢量化(变成 SVG 文件),我再去实现,结果发现了一个棘手的问题,什么问题呢?

直接看图说话吧,下图就是我使用处理后的素材配合border-image 属性实现的效果:

实现的效果问题

大家看出来问题没有?

可能图有些小,看不到细节,我把边角放大 N 倍看下:

边角圈圈

瞧见没有,border-image生成的图形藏在了图像内容的后面。

在Web中,content内容的层级是最高的,outline轮廓、border边框、background背景色等都是比图文内容的层级低的。

因此,border-image的图形在 IMG 元素内容的后面,导致边角的拖拽圈圈显示不全。

有一种解决方法是把 <img> 元素的src地址改为使用 background-image 背景图实现,但这么做会影响浏览器默认的“复制图像地址”,“复制图像”等操作,最终的效果只是有形无实,这样的实现效果一定是没法通过马斯克的代码审查,是会被fire解雇的。

当技术无能为力的时候,可以从源头寻找解决方案,那就是……当当当当,改设计,当然,要和设计师提前沟通好。

至于能否沟通成功,一来看设计师的职业素养,二类看你个人的影响力,三是你自己的沟通能力,能不能把利弊方案等提前讲清楚。

所以,我就给设计师提了个方案(自己做了个图示意了下),能否类似这样的拉伸效果:

拖拽示意

无疑议,直接通过。

变化在于,将拖拽图形全部改造为在图像元素的外部,这样就不会有被内容覆盖的问题了。

相关 CSS代码如下:

img.resizable, img[resizable] {
  border: 3px solid transparent;
  border-image: url(./作者zhangxinxu.svg) 12 / 12px / 0; 
}

OK,至此,最大的技术难度就解决了。

对,这个案例中,最大的技术难度就是 CSS 这一块,JS其实还好,就是手形和拖拽,这个有几年工作经验的前端都可以轻松驾驭。

三、眼见为实、demo与开源

代码码完上线之后,还有很多其他重要的事情要做。

包括撰写详细的文档,包括把项目中比较创新的地方总结梳理出来,包括项目小结文档和邮件等,这些工作很多人并不喜欢做,但对于个人的职业发展却很重要。

因为这些东西,你不讲,你不说,别人是不知道的,毕竟像马斯克这样会review代码的领导可是很罕见的,你不展现自己,说不定就会被浑水摸鱼的半吊子们取而代之,那多可惜啊。

回到这里。

为了总结自己的工作,同时方便自己日后复用,以及希望可以帮到其他遇到类似需求的人,所以我把相关的功能从生产环境剥离,独立成一个小小的开源项目,放在了 gitee 上了。

项目地址

单IMG元素的图像拉伸效果:https://gitee.com/zhangxinxu/only-img-resize

体验地址:https://zhangxinxu.gitee.io/only-img-resize/

使用说明

一开始我是做出直接引入JS就可以使用的那种,后来想想,有些参数还是必须的,所以还是改成了 export/import 模式

<script type="module">
    import onlyImgResize from './src/onlyImgResize.js';

    onlyImgResize({
        // 参数在这里
    });
</script>

此时,页面中所有设置了类名 resizable,或者设置了 HTML 属性 resizable 的元素都可以四象拉伸。

使用很Easy~

语法和参数

语法如下:

onlyImgResize(options);

options 为可选参数,包括:

selector
字符串值。默认值是 '.resizable, [resizable]',表示识别为可拉伸图片的选择器。
maxWidth
数值或布尔值。默认是 true,表示有最大宽度限制,最大宽度值是第一个非内联祖先元素的宽度。支持设置为数值,指定最大宽度值。如果设置为false,则表示图片尺寸的拉伸没有最大范围限制。需要注意的是,由于图片设置了透明边框,因为,100%宽度实际上会超出,实际最大宽度应该是 calc(100% - 4px)
whenDisabled
函数值,如果返回 true,表示禁用图像的拉伸,如果是 false,则拉伸执行。默认值是:

function () {
    return window.imgResizable === false || document.imgResizable === false;
}

表示,如果 window.imgResizable 或者 document.imgResizable 的值是 false,则禁用拉伸。

此参数用在希望某些情况下,图片不被拉伸的时候。

onFinish
函数值,默认是空函数,拖拽结束的时候触发。如果大家希望在其他事件,例如拖拽之中也有回调方法,fork该项目,然后自己添加即可。

其他

欢迎 Star,也欢迎关注我的 gitee 账户,会不定期更新一些自己的小玩具。

四、大浪淘沙始见金

好了,至此,正文内容就结束了。

其实深究起来,本文内容略“水”,还是多以自我展示为目的,真要说多少人会看到此文,多少人会学到这个小技巧,或者说受到启发,我并不抱多大的希望。

精力有限,我的公众号又不同步,掘金粉丝也不少,也懒得转一份(我做一件事情,一定是长期的,临时磨一枪,不如不做),更是让受众下降了不少。

可转念一想,写了快800篇原创技术文章了,哪一篇没有自我展示的目的呢?虽然当下,连我自己都没意识到这一点,但回过头看,实际上已经展示了自己。

也正因为有了这份展示,才能收获影响力,才能继续有动力坚持,纯粹的无人知晓的无私奉献注定是无法持久的,就好比在企业中默默干活却不去表达自己的老黄牛,老好人们。

这类人平时自我感觉不错,我对得起我自己,但遇到晋升绩效这样的事情的时候,因为结果不如意,又会感叹不公。

我称这类人为沉浸在让自己舒适的精神世界中的懒惰者,看起来干活勤勉,实际上是个懒人。

即使苦口婆心地反复强调,一定要花点功夫让同事和leader知道你做的工作,无论是量多,活苦,或者亮点都可以,但就是不做,宁可多接几个需求,就是不愿意做这样的事情,为什么呢?

因为做这种事情,跟他的个人作风,跟他的精神世界不符合,如果没有强迫的压力(如KPI之类的),绝对不会去打破这种精神舒适区的,会觉得不安全,直接躺平。

哎呀,这样冒头会不会不好啊?同事会怎样看我啊?项目没什么亮点,还发出去,会不会掉逼格啊?领导怎么看我啊?算了算了,同事都不发,我也懒得弄,做人要低调。

小说中有个桥段经典不衰,就是平时默默无闻,关键时候一鸣惊人,惊诧众人。

为何这样的桥段多呢?因为大多数的人平时就是默默无闻的,同时希望自己关键时候技惊四方。

喂喂喂,诸位,小说看多了吧,真以为是金字总会发光啊,那要需要有大浪淘沙的环境啊!

我们所处的时代,我们所在的团队,大多都是稳定状态的呀,是死水,是缓流,金字由于比重大,沉得更快啊,亲们!

平时不努力,关键时候想要让别人对你知根知底,是很危险的。

算了,不多扯了,家里领导喊我吃晚饭了。

总结下吧,平时多装逼,装着装着,你说不定真就牛逼了,平时少扮猪,装着装着,别人就真认为你是猪了。

对了,记得将此文到朋友圈,让你的leader知道你平时是爱学习的。

(本篇完)

分享到:


发表评论(目前6 条评论)

  1. 凌览说道:

    学习了,并且已写了篇文章

    https://juejin.cn/post/7227986137457229885

  2. 小杨说道:

    平时都是按照已经有的思路,直接复制,最多理解之后自己重写,也是一种复制, 都没有自己原创独特的思维,好惭愧

  3. 某某某说道:

    (纯当瞎说,既然都上JS了,

    object-position: -9999px -9999px;

    xxx.style.background = “url(” + yyy + “)”;

    (不过编辑器仍然有可能鸽掉)

    不过博主NB!

  4. Lee说道:

    拉伸的最小宽度是不是也应该做一下限制,拖到最小图片就没了

  5. DeathGhost说道:

    “平时多装逼,装着装着,你说不定真就牛逼了,平时少扮猪,装着装着,别人就真认为你是猪了。”
    — 哈哈,经典,但也得像你有实力才行!