JS判断鼠标进入容器的方向与window.open新窗口被拦截的问题

一、鼠标进入容器方向的判定

判断鼠标从哪个方向进入元素容器是一个经常碰到的问题,如何来判断呢?

首先想到的是:获取鼠标的位置,然后经过一大堆的if..else逻辑来确定。这样的做法比较繁琐,下面介绍两种比较方便的方法:

第一种方法,利用圆和反正切三角函数

如下图所示:

以div容器的中心点作为圆心,以高和宽的最小值作为直径画圆,将圆以[π/4,3π/4),[3π/4,5π/4),[5π/4,7π/4),[-π/4,π/4)划分为四个象限。

代码如下:

$(".box").on("mouseenter mouseleave",function(e){

/** 获取容器宽高 **/
var w = $(this).width();
var h = $(this).height();

/** 计算X和Y相对于圆心点的距离,如果不是正方形,按照X,Y谁小按谁进行比例缩放**/
var x = (e.pageX - $(this).offset().left - (w/2)) * ( w > h ? (h/w) : 1 );
var y = (e.pageY - $(this).offset().top - (h/2)) * ( h > w ? (w/h) : 1 );

/** 根据X,Y的值,做反正切atan2计算,返回值在[-π,π]之间 ,这里加上180,剔除负值**/
/** 如果不加180,则0,1,2,3对应下左上右**/
/** 除以90并四舍五入,使得可以以45度为分割线,获取象限**/
/** 加3与4取模,将0,1,2,3对应t,r,b,l既上右下左**/
var direction = Math.round((((Math.atan2(y, x) * (180 / Math.PI)) + 180 ) / 90 )+3)%4;
switch(direction) {
 case 0:
 /** 上 **/
 break;
 case 1:
 /** 右 **/
 break;
 case 2:
 /** 下 **/
 break;
 case 3:
 /** 左 **/
 break;
}});

这个方法中的Math.round((((Math.atan2(y, x) * (180 / Math.PI)) + 180 )/90)+3)% 4公式比较难理解,首先得到鼠标坐标经过换算后的值,然后算出该坐标的弧度,接着换算成度数,加180去掉负数,随后转移象限将0123对应TRBL,如果不加180去掉负数,0123对应BLTR,有点不合CSS的习惯。

第二种方法,利用斜率

如下图所示:

以浏览器左上角做原点,画坐标轴,向下为负,向右为正,和数学坐标系一致。中间的div的左上角坐标(x1,y1),右下角坐标(x2,y2),中心点的坐标(cx,cy)。如图两点的斜率为k(k<0),关于x轴对称的斜率为-k。

需要注意一点的是所有的Y轴坐标都是负数,因为就是将容器置于坐标系的第四象限。

$(".box").on("mouseenter mouseleave", function(e) {
 var w = $(this).width();
 h = $(this).height(),
 x1 = $(this).offset().left,
 y1 = -$(this).offset().top,
 x2 = x1 + w,
 y2 = y1 - h,
 cx = (x1 + x2) / 2,
 cy = (y1 + y2) / 2,
 k = (y2 - y1) / (x2 - x1),
 k1 = (-e.pageY - cy) / (e.pageX - cx),
 direction = -1;
 if ((k1 < -k) && (k < k1)) {
 direction = e.pageX > cx?1:3;
 } else {
 direction = -e.pageY > cy?0:2;//大家理解代码的时候一定记住,Y坐标都是负的
 }
 //0123对应TRBL
});

如上代码所示:当鼠标的位置与容器中心点所形成的斜率在(k,-K)之间,必然是左右移入或移出,如果鼠标的X坐标大于中心点CX,则是右边进入,否则为左边进入;若斜率不在(k,-k)之间,则是上下进入或出去,只要判断鼠标的Y坐标与中心点CY的大小关系即可,大于则是下边,相反就是上边。

二、window.open新窗口被拦截的问题

当我们使用window.open()方法打开一个窗口时,部分浏览器会检测是否是用户主动行为,若不是,则会阻止窗口的打开,例如在异步Ajax的回调函数中调用。

新窗口被拦截检测

窗口被阻止打开,如不给出提示,用户体验将会很不好,那如何检测窗口被阻止?

如下代码所示:

var newWin = null,
 isBlock = !1;
/** 新窗口被某些扩展阻止打开,会抛出错误,因此使用try..catch **/
try {
 newWin = window.open('http://www.baidu.com', '_blank');
 /** 新窗口被阻止时,返回值是undefined或null**/
 (!newWin) && (isBlock = !0);
} catch (ex) {
 isBlock = !0;
}
if (isBlock) alert('您阻止了窗口的打开。');

为何新窗口被拦截

浏览器设计者出于安全的考虑,window.open 命令在用户操作(trusted events)时, 才会正常的打开应该页面而不会被浏览器拦截。什么是trusted events?

The isTrusted read-only property of the Event interface is a boolean that is true when the event was generated by a user action, and false when the event was created or modified by a script or dispatched via dispatchEvent.

当前事件是由用户行为触发(例如鼠标点击按钮触发操作),便是trusted events,而用自定义事件dispatchEvent触发的事件则不是trusted events。

因此使用JS代码自动触发window.open() ,第二个参数不为_self,打开新窗口在大部分浏览器中会被拦截。如果第二个参数为_self,则不会被拦截,如window.open("http://www.baidu.com","_self")

如何Ajax回调中避免被拦截

很多人的需求是点击按钮发送Ajax请求,请求数据回来后,再使用window.open来打开新的窗口,由于是异步操作,直接window.open ,肯定会被拦截。这时我们可以变通以下,先打开一个空窗口,然后等数据回来后替换为需要的地址

如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>弹窗拦截测试</title>
 <style type="text/css">
 #btn{ width:100px; height: 30px; line-height: 30px; text-align:center; background-color:#0087dc; transition:all .2s; color:#fff; border-radius:3px;cursor:pointer; }
 #btn:hover{ background-color:#0060b2; }
 </style>
</head>
<body>
 <div id="btn">打开新窗口</div>
 <script type="text/javascript">
 btn.addEventListener('click',(e)=>{
  var xhr = new XMLHttpRequest();
  var newWin = window.open('about:blank');
  xhr.onreadystatechange = ()=>{
  if(xhr.readyState == 4){
   if(xhr.status == 200){
   newWin.location.href="http://www.baidu.com";
   }
  }
  };
  xhr.open('post','/dnslookup',!1);//异步方式
  xhr.setRequestHeader('content-type','application/x-www-form-urlencoded');
  xhr.send('host=www.baidu.com&rrtype=A');
 },!0);
 </script>
</body>
</html>

服务端代码如下:

var http = require('http'),
 url = require('url'),
 dns = require('dns'),
 qs = require('querystring'),
 fs = require('fs');

function router(req,res,pathname){
 switch(pathname){
 case '/dnslookup':
  lookup(req,res);
  break;
 default:
  showIndex(req,res);
 }
}
function showIndex(req,res){
 var pagePath = __dirname+'/'+'block.html';
 var html = fs.readFileSync(pagePath);
 res.end(html);
}
function lookup(req,res){
 var postData = '';
 req.on('data',function(data){
 postData+=data;
 });
 req.on('end',function(data){
 var json = qs.parse(postData);
 var hostname = json.host;
 var rrtype = json.rrtype;
 dns.resolve(hostname,rrtype,function(err,adresses){
  if(err){
  res.end(JSON.stringify({errcode:1,ips:[]}));
  }
  res.end(JSON.stringify({errcode:0,ips:adresses}));
 });

 });
}
http.createServer(function(req,res){
 var pathname = url.parse(req.url).pathname;
 req.setEncoding("utf8");
 res.writeHead(200,{'Content-Type':'text/html'});
 router(req,res,pathname);
}).listen(3000);

如上所示便可解决在Ajax回调中新窗口被拦截的问题。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

(0)

相关推荐

  • js获取鼠标点击的位置实现思路及代码

    copy来的,但是原页面的代码还是需要修改,下面是修改可用的 常用的是 event.clientX和event.clientY分别获取横向的和纵向的位置,但仅使用这个方法是不够的,因为event.clientX和event.clientY获取的鼠标位置是相对于当前屏幕的,而不考虑页面的滚动条所滚动的距离. 复制代码 代码如下: function pointerX(event) { return event.pageX || (event.clientX + (document.documentE

  • JS获得鼠标位置(兼容多浏览器ie,firefox)脚本之家修正版

    JS获得鼠标位置(兼容多浏览器ie,firefox)我们修正版 function mouseMove(ev) { ev= ev || window.event; var mousePos = mouseCoords(ev); //alert(ev.pageX); document.getElementById("xxx").value = mousePos.x; document.getElementById("yyy").value = mousePos.y; }

  • 基于JavaScript实现 获取鼠标点击位置坐标的方法

    在一些DOM操作中我们经常会跟元素的位置打交道,鼠标交互式一个经常用到的方面,令人失望的是不同的浏览器下会有不同的结果甚至是有的浏览器下没结果,这篇文章就上鼠标点击位置坐标获取做一些简单的总结,没特殊声明代码在IE8,FireFox,Chrome下进行测试兼容 鼠标点击位置坐标相对于屏幕 如果是涉及到鼠标点击确定位置相对比较简单,获取到鼠标点击事件后,事件screenX,screenY获取的是点击位置相对于屏幕的左边距与上边距,不考虑iframe因素,不同浏览器下表现的还算一致. 复制代码 代码

  • JS获取鼠标位置距浏览器窗口距离的方法示例

    本文实例讲述了JS获取鼠标位置距浏览器窗口距离的方法.分享给大家供大家参考,具体如下: 先来看看运行效果图: 代码如下: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style type="text/css"> #test_div { width:400px; height: 400px;

  • firefox中用javascript实现鼠标位置的定位

    /**  * 取得鼠标坐标  * @return Position  */  function getMouseLocation(){  if(ns4||ns6){  mouseX = e.pageX;  mouseY = e.pageY;  }  else{  mouseX = event.x + document.body.scrollLeft;  mouseY = event.y + document.body.scrollTop;  }  return {x:mouseX,y:mouse

  • JavaScript中获取鼠标位置相关属性总结

    javascript并没有mouse对象,获取鼠标坐标要靠强大的event对象. 我们通过监听document的mousemove,就可以实时获得鼠标位置. 但是!!event中和鼠标相关的属性太多了,很让人头大!如下: event.layerX event.layerY event.clientX event.clientY event.pageX event.pageY event.offsetX event.offsetY event.screenX event.screenY event

  • JS实现窗口加载时模拟鼠标移动的方法

    本文实例讲述了JS实现窗口加载时模拟鼠标移动的方法.分享给大家供大家参考.具体实现方法如下: function judge(){ alert("mousemove"); document.onmousemove = null;//撤销鼠标移动模拟 } function simulateMouseMove(){//模拟鼠标移动 document.onmousemove = judge; } window.onload=simulateMouseMove;//窗口加载 希望本文所述对大家的

  • js获取鼠标位置杂谈附多浏览器兼容代码

    其实获得鼠标位置就是一句话的事情,但是要是不了解浏览器间的区别,整个过程就会让人很郁闷,区别在与: 1.IE下获得x和y轴的距离分别用event.x和event.y: FF下获得x和y轴的距离分别用event.pageX和event.pageY: 2.IE下用此方法获得的位置是不算滚动条滚过的位置的,即它只会算到浏览器边缘: FF则会算进滚过去的那些位置: (这个地方很让我崩溃,为这么点小区别我把所有用到的程序全部重写了一遍,囧死--) 解决1的办法,无非是判断一下浏览器,然后用什么方式: 解决

  • javascript窗口宽高,鼠标位置,滚动高度(详细解析)

    网页可见区域宽:document.body.clientWidth 网页可见区域高:document.body.clientHeight 网页可见区域宽:document.body.offsetWidth (包括边线的宽) 网页可见区域高:document.body.offsetHeight (包括边线的宽) 网页正文全文宽:document.body.scrollWidth 网页正文全文高:document.body.scrollHeight 网页被卷去的高:document.body.scr

  • JavaScript取得鼠标绝对位置程序代码介绍

    首先不同浏览器中event位置属性的分析: 1. IE的event.x,event.y是以事件触发元素的父元素外界为参考点(不包括滚动距离) 2. Firefox的event.pageX,event.pageY是以body元素为参考点(包括滚动距离) 3. event.clientX,event.clientY以浏览器左上角为参考点(不包括滚动距离) 4. IE的event.offsetX,event.offsetY和Firefox的event.layerX,event.layerY以事件触发元

  • js获取鼠标位置实例详解

    本文实例讲述了js获取鼠标位置的方法.分享给大家供大家参考,具体如下: 用 javascript 获取当前页面上鼠标(光标)位置在许多情况下都会用到,比如拖放,悬停提示(tooltip) 等等.当然,这里我们依然要面对浏览器的兼容问题,在不同的浏览器下,对这些相关的属性处理方式也不同,这里详细介绍了浏览器在处理这些属性时的差异和最终的解决方法. Javascript代码如下: <script type="text/javascript"> // 说明:获取鼠标位置 // 整

  • javascript之鼠标拖动位置互换效果代码

    鼠标拖动,位置互换效果,主要用于div,提高用户体验等方面 div.box{ position:relative; padding:5px; background-color:#000; width:300px; height:300px; overflow:hidden; } div.box div.item{ float:left; width:90px; height:90px; background-color:#ccc; margin:5px; position:relative; c

随机推荐