知乎文章地址:https://zhuanlan.zhihu.com/p/48168812
以下涉及的demo代码请查看:
yaodebian/ClickableAreagithub.com
这个问题确实从没想过,也是今天前端面试中被问倒的问题之一,接下来做一个简单的总结吧。这个问题确实从没想过,也是今天前端面试中被问倒的问题之一,接下来做一个简单的总结吧。
一.border-radius (css3)
对于圆形,最直接的方法想到的就是css3的圆角属性,这个属性可以将html元素的形状设置为圆形,这之后你想对该圆形区域设置什么事件就设置什么事件(当然包括点击)。(这里就不做具体的test了)
二.通过事件坐标来实现(js)
也就是通过js来进行一个区域判断,进而简介地的形成可点区域,以下给出主要的js测试代码:
// 获取目标元素
var box = document.getElementById('box');
// 对目标元素target的圆形区域进行一个点击事件绑定
function bindClickOnCircleArea(target, callback) {
target.onclick = function (e) {
e = e || window.event;
// target中心点的坐标
var x1 = 100;
var y1 = 100;
// 事件源坐标
var x2 = e.offsetX;
var y2 = e.offsetY;
// 校验是否在圆形点击区,在的话就执行callback回调
// 计算事件触发点与target中心的位置
var len = Math.abs(Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)));
// 通过半径进行校验
if (len <= 100) {
callback();
} else {
alert('死鬼,跑哪去啊,你老婆我是黄皮肤还是白皮肤都分不清了吗');
}
}
}
// 执行
bindClickOnCircleArea(box, function () {
alert('老婆,你让我好找啊,呜呜呜');
});
看看效果图:
详细demo代码请看:
https://github.com/yaodebian/ClickableArea/blob/master/html/index2.htmlgithub.com
三.通过map加area
首先先给出一个小demo(demo1)吧:
<img src="../imgs/test.jpg" width="200" border="0" usemap="#Map" />
<map name="Map" id="Map">
<area shape="circle" coords="100,100,100" href="http://www.baidu.com" target="_blank" />
</map>
其中的效果是这样的:
就是当你点击图片中所标记的圆形区域,会开启一个新的窗口并加载百度页面,同时图片会显示出轮廓。
效果图:
相关demo代码请看:
https://github.com/yaodebian/ClickableArea/blob/master/html/index3.htmlgithub.com
中的test1
1.area是干什么的?
这里copy一下张鑫旭的一张图:
图片和热点区域元素关联是使用图片的usemap属性,其值对应<map>的id或者name值(Chrome浏览器只支持name属性值关联)。
这里出现了两个HTML标签,一个是<area>还有一个是<map>,这些都是从很早就支持的HTML标签,所以不必担心兼容性问题。其中就闭合特性来看,<area>类似<img>,是无法有子元素或其他子内容的。
这里出现了几个属性:
shape
shape表示点击热点区域的形状,支持矩形rect,圆形circle以及多边形poly。
coords
coords表示点击热点区域形状的坐标。坐标点0,0表示图片的左上角。其中矩形rect支持4个数值,2个坐标,分别是矩形左上角坐标和矩形右下角坐标。例如,coords="20,20,80,80"生成的就是一个左上角坐标20,20宽高都是60px的矩形区域。圆形circle支持3个数值,前2个值为圆心坐标,第3个值为圆的半径大小。多边形poly就更简单了,每两个数值组合表示一个坐标点,依次连线形成的区域就是最终的热点区域。
href
href和<a>元素的href是一样的东西,直接跳转地址,或者锚点等。也同样支持target属性和rel属性。也就是说<area>可以看成是半个<a>元素。
alt
alt同<img>元素的alt,表示热点区域图片的描述信息。
如果<area>要想和图片热点关联,祖先元素<map>是不可缺少的,但是不一定非得直接父子关系。<map>和<area>之间再嵌套个<div>什么的功能也是正常的。
另外值得注意的是,area在被点击后会呈现outline,并且对area元素添加的css样式是没有任何效果的。
2.area的相关应用
根据上面提到的,area标签其实和a标签很相似,也就是说,有时候我们可以使用area元素代替a元素。
这时就会想到a元素有什么局限性,导致有时候我们需要使用area来代替a?答案是<a>不支持嵌套。举个栗子:
<a href="#1">11111111111<a href="#2">22222222222</a></a>
浏览器会将上面的代码解析为相邻兄弟关系,而不是父子关系,如下截图示意:
所以,如果我们有链接嵌套的需求,就可以试试使用<area>元素,同样举个栗子:
假设我们现在有这样一个场景,有一个小说目录项,如图:(以下的图片摘自张鑫旭)
图中有小说封面、小说名,以及具体的章节,我们的需求是:当我们点击图片中的封面图片和小说名,会另外开启一个窗口并加载相应小说的主页面,而点击图片中的其他位置则是加载具体的小说章节。
思路:
- 首先的一个思路是在上面的整个布局的根元素绑定一个click事件,并通过判断触发的一个事件源所在的子元素来进行不同的一个回调函数的调用,但是这种方法有点繁琐;
- 实际上直接通过html元素的一个布局就能达到上面的一个要求,就是在<a>元素中嵌套<area>元素;
实现:
我们来看第二个栗子test2:
<div>
<h2>test2</h2>
<!-- 对整个小说项赋予链接 -->
<a class="bookItem" href="https://read.qidian.com/chapter/XOn-GdKVmQjywypLIF-xfQ2/rTEHu3PW9WiaGfXRMrUjdw2" target="_blank">
<!-- 单独给封面赋予点击区域 -->
<img width="90" height="120px" src="../imgs/novel.jpg" class="book-cover" alt="绝对虚构" usemap="#bookCover">
<map name="bookCover" id="bookCover">
<area shape="rect" coords="0, 0, 90, 120" href="https://book.qidian.com/info/1013049039#Catalog" alt="绝对虚构" target="_blank">
</map>
<div class="bookInfo">
<!-- 给小说名赋予点击区域 -->
<h4 class="bookTitle">
<area class="bookTitleArea" href="https://book.qidian.com/info/1013049039#Catalog" target="_blank">
绝对领域
</h4>
<p class="bookDetail">第十章 欢迎来到我的世界</p>
</div>
</a>
</div>
对于上述的标题,我们不涉及到图标,所以没有用map将area包裹,结果如下:
可以看到当我们点击封面和标题时,跳转的是小说的主页面,而点击其他区域就会跳转到具体的章节(第十章)。
详细demo代码请看:
https://github.com/yaodebian/ClickableArea/blob/master/html/index3.htmlgithub.com
中的test2
值得注意的是,area默认是没有宽高的,所以为了使得它能够有宽高用于点击,我们设置它的position为absolute,这种情况下,我们不仅可以设置它的宽高,同时背景色、边框都能进行一个简单的设置。再补充一个之前没有提到的东西,通过按tap键我们可以依次查看页面中的area(会依次显示每个area的outline)。
另外,据说area如果没有被map包裹,在firefox里是无效的,我们可以测试一下:
根据上面的效果图可以看出,在firefox中尽管我们已经设置了absolute,仍然不能给area元素添加样式。另外旭哥的博客中指明firefox中使用tab不能进行查看area,不过经过本人的测试是可以的,应该是版本的问题。
因为上述火狐的问题,我们最后再给出一个小栗子,就是针对小说名,我们用一张透明的图片对小说名的部分进行覆盖,使得可以用map,这样就兼容了火狐,让我们来看看吧:
<div>
<h2>test3</h2>
<!-- 对整个小说项赋予链接 -->
<a class="bookItem" href="https://read.qidian.com/chapter/XOn-GdKVmQjywypLIF-xfQ2/rTEHu3PW9WiaGfXRMrUjdw2" target="_blank">
<!-- 单独给封面赋予点击区域 -->
<img width="90" height="120px" src="../imgs/novel.jpg" class="book-cover" alt="绝对虚构" usemap="#bookCover">
<map name="bookCover" id="bookCover">
<area shape="rect" coords="0, 0, 90, 120" href="https://book.qidian.com/info/1013049039#Catalog" alt="绝对虚构"
target="_blank">
</map>
<div class="bookInfo">
<!-- 给小说名赋予点击区域 -->
<h4 class="bookTitle">
<!-- 用透明图片覆盖小说名,并绑定area -->
<img class="bookTitleArea" src="https://img-blog.csdnimg.cn/2022010614423120254.gif"
usemap="#mapTitle">
绝对领域
</h4>
<map name="mapTitle" id="mapTitle">
<area shape="rect" coords="0, 0, 150, 22" href="https://book.qidian.com/info/1013049039#Catalog" target="_blank">
</map>
<p class="bookDetail">第十章 欢迎来到我的世界</p>
</div>
</a>
</div>
我们直接看一下在firefox中的运行效果:
从上面的效果图中可以看到我们已经兼容了firefox浏览器。
详细的demo代码请看:
https://github.com/yaodebian/ClickableArea/blob/master/html/index3.htmlgithub.com中的test3
最后,上述总结参考以下几篇文章:
HTML <area><map>标签及在实际开发中的应用www.zhangxinxu.com
Web前端面试指导(四十二):如何在页面上实现一个圆形的可点击区域? - 雄领IT的专栏 - CSDN博客blog.csdn.net