vortesnail / blog

:blue_book: 个人技术小文章,旨在对知识的总结,能帮助到别人就更好啦。
551 stars 45 forks source link

如何画一个只能在已显示区域进行事件绑定的三角形 #3

Open vortesnail opened 5 years ago

vortesnail commented 5 years ago

如何画一个只能在已显示区域进行事件绑定的三角形

前言: 这个问题是去一家公司面试的时候,技术经理问到我的,我第一想法是用CSS中的border去画,但是我们现在的要求是在那个三角形区域,才能进行事件的绑定,比如:click事件,那border所用到的transparent仅仅是透明度为0,那个区域还是在的,这就无法完成特定区域的事件绑定。

1.先来试试border方法到底行不行吧!

Html:

<div className="triangle"></div>

Css:

.triangle {
  width: 0px;
  height: 0px;
  border-left: 50px solid yellow;
  border-right: 50px solid blue;
  border-top: 50px solid red;
  border-bottom: 50px solid black;
}

现在我们可以看到如下: image.png 我们就选一个指向右边的箭头吧,修改Css样式: Css:

.triangle {
  width: 0px;
  height: 0px;
  border-left: 50px solid yellow;
  border-right: 50px solid transparent;
  border-top: 50px solid transparent;
  border-bottom: 50px solid transparent;
}

现在我们得到了想要的三角形(具体形状自行调整border-size就行): image.png

接下来,我们给这个 div 添加一个 onmouseover 事件:

const triangle = document.querySelector('.triangle');
triangle.addEventListener('mouseover', () => {
  console.log('你碰到我了!');
})

结果我们去测试的时候,不出所料地,透明的部分也会触发事件,如下所示:

1.gif

那可咋办呢??

2.换个思路,用遮罩!

这个思路很简单,但是面试官坐在面前的时候,却怎么也想不出来。。

step1: 我们先画三个矩形:

Html:

<div class="rectangle-1"></div>
<div class="rectangle-2"></div>
<div class="rectangle-3"></div>

Css:

.reactangle-container {
  position: relative;
}

.rectangle-mask1,
.rectangle-mask2 {
  width: 200px;
  height: 80px;
  position: absolute;
}

.rectangle-mask1 {
  top: 11px;
  left: -5px;
  transform: rotate(50deg);
  background-color: lightblue;
  z-index: 2;
}

.rectangle-mask2 {
  bottom: 11px;
  left: -5px;
  transform: rotate(-50deg);
  background-color: lightgreen;
  z-index: 2;
}

.rectangle-tri {
  width: 100px;
  height: 100px;
  background-color: lightcoral;
  z-index: 1;
}

得到如下图: image.png 其中粉红的区域就是我们要的三角形区域,理论上你可以通过两个或许多个矩形构建出你想要的任何三角形!

step2: 进行绑定

那这个时候,我们怎么绑定事件到这个三角形上呢? 思路:rectangle-tri 这个矩形绑定事件,也给 rectangle-mask1 和 rectangle-mask2 绑定事件,但是不做操作,这样的话,因为rectangle-tri 在最下面,移动非三角形区域的时候,触发的事件监听是另外两个遮罩矩形的事件。

const reactangleContainer = document.querySelector('.reactangle-container');
const rectangleMask1 = reactangleContainer.querySelector('.rectangle-mask1');
const rectangleMask2 = reactangleContainer.querySelector('.rectangle-mask2');
const rectangleTri = reactangleContainer.querySelector('.rectangle-tri');

rectangleTri.addEventListener('mouseover', () => {
  console.log('你碰到我了!');
})

rectangleMask1.addEventListener('mouseover', () => {
    // 不做任何行为
})

rectangleMask2.addEventListener('mouseover', () => {
    // 不做任何行为
})

此时,特定的区域才有事件绑定了: 2.gif

现在,我们怎么把这两个遮罩矩形去掉呢????设置背景色为白色?那就是自欺欺人

step3: 只显示三角形

这里我真的还找不到方法啊,有哪位大佬能来说说吗???

3.用CSS3中的clip-path试试吧!

clip-path CSS 属性可以创建一个只有元素的部分区域可以显示的剪切区域。区域内的部分显示,区域外的隐藏。剪切区域是被引用内嵌的URL定义的路径或者外部svg的路径,或者作为一个形状例如circle().。clip-path属性代替了现在已经弃用的剪切 clip属性。

上看的引用出自MDN,我们只需要知道,这个属性可以让我们裁剪出想要的形状

基本形状裁剪:

.clip-me {
  clip-path: inset();
  clip-path: circle();
  clip-path: ellipse();
  clip-path: polygon();
}

其中inset是矩形的剪切,circle是圆形的剪切,ellipse是椭圆的剪切,polygon是多边形的剪切。对于我们想要把矩形剪切成三角形,应该使用polygon这个语法。 Html:

<div class="triangle"></div>

Css:

.triangle {
  width: 100px;
  height: 100px;
  background-color: lightcoral;
  clip-path: polygon(0px 0px, 0px 100px, 100px 50px);
}

clip-path: polygon(0px 0px, 0px 100px, 100px 50px); 这句话意思是,根据坐标轴上确定的三个点来进行裁剪:(0px, 0px),(0px 100px),(100px, 50px) ,这三个点构成了一个我们如下三角形: image.png

现在我们可以来试试绑定事件好不好用来:

const tri = document.querySelector('.triangle');
tri.addEventListener('mouseover', () => {
  console.log("你碰到我了!");
})

以下为测试结果: 3.gif

我只能说,这个真是太好用了,不过这个属性兼容性会有些不好,酌情使用把!

SlahserZ commented 2 years ago

wonderful!

Linsanshu commented 2 years ago

整挺好👍🏾

Arisguy commented 2 years ago

听我朋友说他 面试的时候碰到过一个这样类似的机试题,然后给我说了 我也想半天想不出来, 长见识了

Brandy2333 commented 2 years ago

牛!

cucurbitboy commented 1 year ago

长见识了