JS 脚本实战案例 0001

所需要的前置知识基础:

虽然写上了编号,我也不知道下一篇会是什么时候。不过还是先把这一篇写好吧。

最近在论坛上( 浏览器中的图片如何直接旋转角度? )遇到了一个需求,问题也很简单:

工作需要,点击一个包含图片的页面,该图片会呈现在一个单独跳出的标签页中,有什么尽量简单的办法能旋转这个跳出来的标签页中的图片?

就是对页面中的图片进行旋转。

隐含条件:这个页面中只有一张图片。这个隐含条件还是值得注意的,因为这样我们就无需考虑这个旋转操作究竟是针对的哪一张图片。

然后有一个附加的要求:

真正要旋转图片的是我部门员工,一堆大妈,我不能让她们进行这种“高级”操作,她们会杀了我的。

真正使用这个功能的人,计算机操作水平可能不高,所以要尽可能的简便。

隐含条件:是多台电脑,而且因为操作人员的计算机水平不高,可能需要提问者去挨个设置,所以最好这个设置过程也十分简单。


大家的答案中提供了许多的方法,但是并不能够很好的满足上面所有的需求。

无论是扩展还是脚本,它们的安装操作并不简单。

功能强大并不一定总是优势,在这个场景下,功能强大就意味着使用复杂,所以……提问者的人身安全就得不到保证。

所以我思考的方向是小书签,因为它安装简单,只是在浏览器中添加一个书签。而且使用简单,只需要点击一下书签。


然后现在来思考具体的需求,就是对图片进行旋转。那么只需要向图片这个元素添加一条样式设定:transform: rotate(90deg);,这条设定我们只要在网上随便搜索一下旋转元素就可以找到,其中的 90 是旋转过的角度数。

这里开始延伸思考,一个图片的方向不正确,存在三种可能性,那么现在想要把它旋转到正确的方向,需要旋转过的角度数可能是 90 度,180 度或者 270 度。当然最好我们有将这个图片进行不断旋转的能力,毕竟手动调节有可能一不小心调节过头了,那么继续旋转就可以修正这样的操作错误。

所以我们希望每点击一次,让这个图片旋转的角度数增加 90 度。

那么在第一次点击的时候,我们可以不做任何判断,直接给图片添加一个旋转 90 度的设定。

document.body.querySelector('img').style.transform = 'rotate(90deg)';

这非常的简单,以前我们说过 document 是当前页面文档对象,指代的就是当前这个页面。document.body 说的是这个页面中主体的部分,querySelector('img') 是说在前面这个元素中,以后面小括号中的选择器来查找需要的元素,并且选中第一个匹配这个选择器的元素。与之对应的是 querySelectorAll ,会选中所有符合选择器的元素。

回顾我们前面的需求,页面中只有一张图片,所以我们不给自己增加复杂度,只选中一个图片元素直接操作。

这个元素的样式 style,样式中的 transform 属性,然后后面进行一个赋值。你可以通过开发者工具来观察执行这段代码之后,对于页面元素代码的影响。

好了,现在只要加上基本结构,就写好了一个一键让页面中第一张图片旋转 90 度的小书签。


但到这里并没有真正的解决掉问题,因为前面说了,我们希望能够每点击一次小书签,都让页面中的图片,旋转的角度增加 90 度。

那么我们只需要把旋转的度数改成为一个变量,然后去修改这个变量的值。而将样式设定给这个元素的操作并没有发生改变(依然是上面那句代码)。那这里在我们运算之前需要知道一个基础的数值,就是当前这张图片已经被旋转过了多少角度,这样我们才可以计算增加90度以后的角度是多少。

那么用上面的方法不光可以设置这个样式的值,也可以读取这个样式的值。但是读取之后你会发现和我们上面所设置的格式并不相同,这变得不那么容易计算了。当然我们可以通过我们努力的学习去理解他所展示的这种格式。不过这里为了快速的解决问题,我们使用一种简单粗暴的方法:

给这个图片元素上添加一个额外的属性来记录当前图片所旋转过的角度。那么每一次新的角度,就是在这个属性的基础上再增加 90 度。元素上的数据属性都是以 data- 来开头的,后面加上一个数据的名称。对于这样的数据属性,我们可以使用 dataset 来进行设置和读取,具体的格式可以自行查阅文档,我们这里就直接使用了,当然你仔细观察一下,也能够理解它的使用方法。

const oldDeg = +document.body.querySelector('img').dataset.deg;
const newDeg = oldDeg + 90;
document.body.querySelector('img').style.transform = 'rotate('+newDeg+'deg)';
document.body.querySelector('img').dataset.deg = newDeg;

我把每一个步骤都写成了单独的语句来方便理解。

  • 第 1 句获取储存在数据属性中的度数,注意前面的正号是为了把读取到的字符串转换成为数字
  • 第 2 句给旧度数增加 90 度,这是我们的新度数
  • 第 3 句把新度树设置给图片对象
  • 第 4 句别忘了,把新度数也储存到数据属性之中,供下一次使用

这样一切就都联系起来了。但是还有一种特殊情况没有考虑——我们第一次执行这个小书签的时候,页面中图片并没有这个数据属性来记录当前图片的旋转度数。当然这种情况下图片必然是没有被旋转的,所以它当前的旋转度数应该是 0。

如果这个图片没有对应的数据属性,那么我们读取到的就是 undefined,我们有一定的方法去对此进行判断,最简单的就是判断这个数据是真还是假。如果数据没有被定义,那么判断的结果就是这个数据为假。当然你也应该知道如果这个数据的值为 0,那么判断它真假,得到的结果也是假。

if(oldDeg){
    const newDeg = oldDeg + 90;
}else{
    const newDeg = 0 + 90;
}

如果这个数据为真,那么给它加上 90 储存为新的度数;如果这个数据为假证明图片还没有被旋转过,所以它的度数是 0,然后给它加上 90 就是新的度数。当然这里其实并不需要进行计算,直接写90就可以了,我是为了方便大家理解,所以把这个步骤写出来。

但是上面这段代码本身就是为了让大家能够理解才这样书写的,而其实它是不能够使用的。因为这里使用的变量声明方法(const),它的作用域只是它所在的那个大括号。也就是在大括号之外,别人是不认识它的。你看上面这段代码中的两个声明都是在大括号之内,那么离开这个判断过程,也就都离开了它们对应的大括号,于是后面的代码并不认识这个变量。当然我们还有一些方法去解决,不过这里最简单直接的就是使用三元运算符,然后回避使用判断语句:

const newDeg = (oldDeg ? oldDeg : 0) + 90;

有许多同学表示对于三元运算符难以理解,这只是因为我们以前没有接触过。所谓三元就是有三个数据来参与运算。看上面的代码,如果把小括号这部分看作一个整体,那么这个代码你是很容易读懂的。那现在我们只看小括号里面的内容:

  • 问号前面的是条件,我们要判断它的真假
  • 如果条件为真,就使用冒号前面的这个数据作为最终结果
  • 如果条件为假,就使用冒号后面的这个数据作为最终结果

所以其实就是一个简化了的判断语句,你可以对照着上面的代码去逐步的分析,看一看它是不是达到了我们所期望的效果。


如果上面这些都理解了,那么你的小书签已经可以很好的工作了。

但其实还有一个细节可以进一步的优化,虽然必要性并不太大吧。

随着我们不断的旋转,这个度数是累加的,就是它会不断的变大。当然程序很聪明,完全可以超过360度,只不过旋转更多圈罢了。但是数据的大小永远是存在一个极限的,有没有可能被无聊的人不断的旋转,然后超越了这个极限,使得程序出错呢?这个可能性很小,大概真的没有人会这么无聊。或者说这种低概率的情况可以几乎忽略不计。但是如果不麻烦,为什么我们不让自己的程序更加严谨一点呢?

这里介绍一个新的运算符 %,看起来这是一个百分号,但它并不是百分号。你可以把它当做一个除号来看待,它所进行的运算也是除法,只不过最后所得到的结果并不是商,而是余数。余数这个概念好像只有在小学用过,后来几乎就不再提起了,所以大概我们还要回忆一下。

那么我们需要对图片旋转过的度数,无论它多大,其实等效的效果都是这个度数除以 360 度,然后得到的余数。因为每增加 360 度,只不过是多旋转了一圈,对于图片的真正朝向并没有影响。所以我们在上面的计算中,再加上这样的处理就会变得更加严谨。好了,现在来看一下完整的代码:

javascript:(function(){
    const oldDeg = +document.body.querySelector('img').dataset.deg;
    const newDeg = ((oldDeg ? oldDeg : 0) + 90)%360;
    document.body.querySelector('img').style.transform = 'rotate('+newDeg+'deg)';
    document.body.querySelector('img').dataset.deg = newDeg;
})()

如果去掉第一行和最后一行,只是中间的 4 行,在浏览器的控制台中输入运行是没有任何问题的,但是如果作为小书签去使用,会发现这段代码不起作用,仔细排查报错会发现百分号那里的代码出现了问题。

这是由小书签这种特定的形式而导致的,因为代码保存在网址之中,所以会受到一些限制。总之将百分号替换为:%25 即可.


如果你说为什么帖子中我所给出的代码和这个不一样,因为当时我在思考着其他问题随便写的代码,走了另外的思路,都能解决问题,不过那个代码比较冗长了。


如果读完了记得请我喝杯咖啡:

老鼠爱发电

3 个赞

dataset
我一般用setAttribute()及getAttribute()