美文网首页
「面试题」web 实现一个中空的点击区域

「面试题」web 实现一个中空的点击区域

作者: 这名字真不对 | 来源:发表于2019-05-09 16:44 被阅读0次

最近面试遇到了一个没有见过的题,回答的也不好,回来后总结一下该题的实现思路:

题目:

  • 如图,页面密密麻麻的布满A链接,想要你实现一个逻辑的圆,圆对用户不可见,圆心(a,b)半径为R,实现效果:圆内的链接可点击,圆外不可点击。伪代码实现。(css,js都可以):


    题图例子

面试时,阅读完题目,思路是监听全局点击事件,获取点击的坐标,然后计算到圆心的距离是否超过半径R,超过距离时可以触发a链接的点击。

伪代码:

$(body).on('click', (e) => {
  let position = e.position
  let xLen = Math.abs(position.x - a)
  let yLen = Math.abs(position.y - b)
  let length = Math.sqrt(Math.pow(xLen, 2) + Math.pow(yLen, 2))
  if (length > R) {
    // 触发后续的点击
  }
})

面试时有一些细节问题,比如圆的遮罩dom位置会影响事件传播的路径,捕获/冒泡阶段的事件捕获,是否能够触发hover等等。面试时并没有完整的实现,面试回来后,搜索了一下,有一个css属性可以控制某个特定元素能否成为鼠标事件的target,即控制元素是否触发鼠标事件: pointer-events - MDN
接下来尝试用pointer-events解决这题。

解题

完整Demo
思路:

  1. 计算得到圆的位置、半径、宽高等等参数
  2. 监听鼠标移动事件,计算鼠标的位置
  3. 比较半径到鼠标距离,当小于半径时为mask添加 pointer-event: none 属性

html:

<body>
  <div id="app">
    button{click me}*100  <!-- emmet 表示这里有100个button-->
  </div>
  <div class="mask">
    <div class="cycle"></div>
  </div>
</body>

css:

body {
  position: relative;
}

button {
   /*... 样式省略,可以参考demo  */
}

.mask {
  background-color: #000;
  opacity: 0.4;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}

.cycle {
  position: absolute;
  z-index: 10;
  top: 40px;
  left: 300px;
  border: 2px solid #ccc;
  height: 200px;
  width: 200px;
  border-radius: 100%;
}

.pointer-none {
  pointer-events: none;
}

js:

const $body = $('body')
const $mask = $('.mask')
const $cycle = $('.cycle')
const cycleRect = $cycle.get(0).getBoundingClientRect() // 获取圆

// demo 中是一个圆,因此半径固定
const cycleRadius = cycleRect.width / 2

// 圆心坐标 (a, b) 
const cycleLocation = {
  // 获取元素左上角坐标
  absoluteX: window.pageXOffset + cycleRect.x,
  absoluteY: window.pageYOffset + cycleRect.y,
  // 圆心
  a: window.pageXOffset + cycleRect.x + cycleRadius,
  b: window.pageYOffset + cycleRect.y + cycleRadius
}

// 监听鼠标事件,设置遮罩pointer-none属性
$body.on('mousemove', (e) => {
  const x = e.pageX
  const y = e.pageY
  if (isOnCycle(x, y)) {
    $mask.addClass('pointer-none')
  } else {
    $mask.removeClass('pointer-none')
  }
})

// 判断是否在圆内
function isOnCycle (x, y) {
  const xLen = Math.abs(x - cycleLocation.a)
  const yLen = Math.abs(y - cycleLocation.b)
  
  const distance = Math.sqrt(Math.pow(xLen, 2) + Math.pow(yLen, 2))
  return distance <= cycleRadius
}

思考

以上的解答仅能在pc端上实现,原因是实现是通过监听mousemove事件来获取鼠标坐标实现的,移动端上用户可能直接就点击到了圆内,先触发了点击事件再触发移动事件,但就在我的尝试过程当中没有找到实现完全中空的区域的方法,如果解决办法也欢迎大家来讨论。

此外,这次面试的是一家k12在线教育机构,这道实现题其实是一个现实业务场景的简化。如果有玩过手游的经验,一定会知道现在绝大多数手游在刚进入游戏时会有一段新手引导教程,需要用户点击指定的区域,完成教程的指引。这题也新手引导的一种实现,通过在页面上盖上一层遮罩,用户只能点击引导的地方。了解了这点后,我又去搜索了一下社区的一些实践,发现大部分实现都是通过控制点击区域元素z-index属性来解决的,这里不做延伸,一些相关库的链接放到了最后的参考当中,可以用来拓展学习。

最后,虽然本次面试没有通过,不过也提醒了我,面试题有时候也可以是现实场景的简化,通过这类仿真题考验候选人的思考能力和基本能力。因此,学习不能只关注基础,实践上也要踏实,并多做思考,才能更好的将自己的技术用于业务。

参考

pointer-events
driver.js
usablica/intro.js

相关文章

  • 「面试题」web 实现一个中空的点击区域

    最近面试遇到了一个没有见过的题,回答的也不好,回来后总结一下该题的实现思路: 题目: 如图,页面密密麻麻的布满A链...

  • 前端面试每日 3+1 —— 第18天

    今天的面试题 (2019.05.04) —— 第18天 [html] 怎样在页面上实现一个圆形的可点击区域? [c...

  • Vue指令实现区域点击放大

    在H5的项目中,通常有很多区域性的 点击icon ,布局实现比较麻烦,为了放大点击区域,实现区域点击放大的效果,我...

  • js事件处理机制和popover轮子

    在造轮子的时候,需要实现一个简单的点击按钮内容显示/隐藏,点击空白区域内容隐藏,点击内容区域内容不隐藏的功能代码如...

  • UIButton实现区域外点击

    UIButton实现区域外点击 今天项目开发中偶然需要这个功能,一个按钮区域大小外也要能够点击响应 因为项目是很早...

  • android实现不规则区域点击

    定义好一个圆形的path 获取path的边界 生成可点击区域的范围 画path 点击事件 完整代码

  • 点击任意区域隐藏键盘

    #pragma mark - 通过GestureRecognizer实现点击任意区域隐藏键盘 - (void)se...

  • 扩大按钮点击区域

    思路:建一个UIbutton分类,结合runtime更改按钮点击响应区域 实现代码: .h //// UIButt...

  • WKWebView 实现web的图片点击

    在web端进行图片点击,就比较简单的往图片标签里面注册一个onclick方法 1、在didFinish中注册 2、...

  • 进阶任务10-事件应用

    实现Tab切换的功能 实现下图的模态框功能,点击模态框不隐藏,点击关闭以及模态框以外的区域模态框隐藏

网友评论

      本文标题:「面试题」web 实现一个中空的点击区域

      本文链接:https://www.haomeiwen.com/subject/ctvdoqtx.html