lgwebdream / FE-Interview

🔥🔥🔥 前端面试,独有前端面试题详解,前端面试刷题必备,1000+前端面试真题,Html、Css、JavaScript、Vue、React、Node、TypeScript、Webpack、算法、网络与安全、浏览器
https://lgwebdream.github.io/FE-Interview/
Other
6.82k stars 896 forks source link

Day224:多种方式实现圆形可点击区域(至少三种) #1043

Open Genzhen opened 3 years ago

Genzhen commented 3 years ago

每日一题会在下午四点在交流群集中讨论,五点小程序中更新答案 欢迎大家在下方发表自己的优质见解 二维码加载失败可点击 小程序二维码

扫描下方二维码,收藏关注,及时获取答案以及详细解析,同时可解锁800+道前端面试题。


参考实现

<style>
  #circle {
    background: red;
    width: 100px;
    height: 100px;
    border-radius: 50%;
  }
</style>
<div id="circle"></div>
<script>
  document.querySelector("#circle").onclick = function () {
    alert("ok");
  };
</script>
<img src="xxxxx.png" usemap="#Map" />
<map name="Map" id="Map">
  <area
    shape="circle"
    coords="100,100,50"
    href="https://www.yidengxuetang.com/"
    rel="external nofollow"
    target="_blank"
  />
</map>

area 属性

  • shape:表示热点区域的形状,支持 rect(矩形),circle(圆形),poly(多边形)
  • coords:表示热点区域的坐标,(0,0)表示图片左上角。rect 四个值分别表示左上角坐标和右下角坐标。circle 三个值分别表示圆心坐标和半径。poly 有若干个值,每两个表示一个坐标点。
  • href:表示链接到某个地址,和<a>标签差不多
  • alt:对该区域描述,类似于<img>的 alt
document.onclick = function (e) {
  let [x, y, r] = [100, 100, 100], // x,y 坐标原点,r半径
    x1 = e.clientX, // 获取x坐标
    y1 = e.clientY, // 获取y坐标
    dis = Math.abs(Math.sqrt(Math.pow(x - x1, 2) + Math.pow(y - y1, 2)));
  if (dis < r) {
    alert("ok");
  }
};

canvas 是 HTML5 提供的,用来在浏览器中创建图形,它可以通过 JavaScript 绘制 2D 图形。

因此我们可以通过用 canvas 在浏览器中绘制一个圆形,然后给这个圆形添加区域内点击事件即可实现。

<canvas id="drawing" width="400" height="400"></canvas>
<script>
  window.onload = () => {
    let drawing = document.querySelector("#drawing"),
      ctx = drawing.getContext("2d");
    circle = new Shape(100, 100, 50);
    circle.click = () => {
      alert("ok");
    };
    drawing.onmousedown = function (event) {
      let { clientX, clientY } = event || window.event,
        point = {
          x: clientX - drawing.offsetLeft,
          y: clientY - drawing.offsetTop,
        };
      circle.reDraw(point);
    };

    function Shape(x, y, r) {
      this.x = x;
      this.y = y;
      this.r = r;
      ctx.fillStyle = "red";
      ctx.beginPath();
      ctx.arc(this.x, this.y, this.r, 2 * Math.PI, false);
      ctx.closePath();
      ctx.fill();
    }
    Shape.prototype.reDraw = function (point) {
      ctx.fillStyle = "red";
      ctx.beginPath();
      ctx.arc(this.x, this.y, this.r, 2 * Math.PI, false);
      ctx.closePath();
      ctx.fill();
      //   判断点击是否在圆形区域内
      if (ctx.isPointInPath(point.x, point.y)) {
        this.click();
      }
    };
  };
</script>
chensiguo commented 3 years ago

clip-path 会不会更好呢, css 和 svg 都有

Genzhen commented 3 years ago

clip-path 会不会更好呢, css 和 svg 都有

@chensiguo 也是可以的

<style>
  .circle {
    width: 10vw;
    height: 10vw;
    background: gray;
    clip-path: circle();
  }
</style>
<div class="circle"></div>
<script>
  document.querySelector(".circle").onclick = function () {
    alert("ok");
  };
</script>
<style>
  .circle {
    width: 10vw;
    height: 10vw;
    background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='50%25' cy='50%25' r='50%25' fill='gray'/%3E%3C/svg%3E");
  }
</style>
<div class="circle"></div>
<script>
  document.querySelector(".circle").onclick = function () {
    alert("ok");
  };
</script>