JS判斷鼠標(biāo)進(jìn)入容器的方向與window.open新窗口被攔截的問題
一、鼠標(biāo)進(jìn)入容器方向的判定
判斷鼠標(biāo)從哪個方向進(jìn)入元素容器是一個經(jīng)常碰到的問題,如何來判斷呢?
首先想到的是:獲取鼠標(biāo)的位置,然后經(jīng)過一大堆的if..else
邏輯來確定。這樣的做法比較繁瑣,下面介紹兩種比較方便的方法:
第一種方法,利用圓和反正切三角函數(shù)
如下圖所示:
以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誰小按誰進(jìn)行比例縮放**/ 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 ); /** 根據(jù)X,Y的值,做反正切atan2計算,返回值在[-π,π]之間 ,這里加上180,剔除負(fù)值**/ /** 如果不加180,則0,1,2,3對應(yīng)下左上右**/ /** 除以90并四舍五入,使得可以以45度為分割線,獲取象限**/ /** 加3與4取模,將0,1,2,3對應(yīng)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
公式比較難理解,首先得到鼠標(biāo)坐標(biāo)經(jīng)過換算后的值,然后算出該坐標(biāo)的弧度,接著換算成度數(shù),加180去掉負(fù)數(shù),隨后轉(zhuǎn)移象限將0123對應(yīng)TRBL,如果不加180去掉負(fù)數(shù),0123對應(yīng)BLTR,有點不合CSS的習(xí)慣。
第二種方法,利用斜率
如下圖所示:
以瀏覽器左上角做原點,畫坐標(biāo)軸,向下為負(fù),向右為正,和數(shù)學(xué)坐標(biāo)系一致。中間的div的左上角坐標(biāo)(x1,y1),右下角坐標(biāo)(x2,y2),中心點的坐標(biāo)(cx,cy)。如圖兩點的斜率為k(k<0),關(guān)于x軸對稱的斜率為-k。
需要注意一點的是所有的Y軸坐標(biāo)都是負(fù)數(shù),因為就是將容器置于坐標(biāo)系的第四象限。
$(".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坐標(biāo)都是負(fù)的 } //0123對應(yīng)TRBL });
如上代碼所示:當(dāng)鼠標(biāo)的位置與容器中心點所形成的斜率在(k,-K)之間,必然是左右移入或移出,如果鼠標(biāo)的X坐標(biāo)大于中心點CX,則是右邊進(jìn)入,否則為左邊進(jìn)入;若斜率不在(k,-k)之間,則是上下進(jìn)入或出去,只要判斷鼠標(biāo)的Y坐標(biāo)與中心點CY的大小關(guān)系即可,大于則是下邊,相反就是上邊。
二、window.open新窗口被攔截的問題
當(dāng)我們使用window.open()
方法打開一個窗口時,部分瀏覽器會檢測是否是用戶主動行為,若不是,則會阻止窗口的打開,例如在異步Ajax的回調(diào)函數(shù)中調(diào)用。
新窗口被攔截檢測
窗口被阻止打開,如不給出提示,用戶體驗將會很不好,那如何檢測窗口被阻止?
如下代碼所示:
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('您阻止了窗口的打開。');
為何新窗口被攔截
瀏覽器設(shè)計者出于安全的考慮,window.open
命令在用戶操作(trusted events)時, 才會正常的打開應(yīng)該頁面而不會被瀏覽器攔截。什么是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.
當(dāng)前事件是由用戶行為觸發(fā)(例如鼠標(biāo)點擊按鈕觸發(fā)操作),便是trusted events,而用自定義事件dispatchEvent觸發(fā)的事件則不是trusted events。
因此使用JS代碼自動觸發(fā)window.open()
,第二個參數(shù)不為_self,打開新窗口在大部分瀏覽器中會被攔截。如果第二個參數(shù)為_self,則不會被攔截,如window.open(" 。
如何Ajax回調(diào)中避免被攔截
很多人的需求是點擊按鈕發(fā)送Ajax請求,請求數(shù)據(jù)回來后,再使用window.open來打開新的窗口,由于是異步操作,直接window.open
,肯定會被攔截。這時我們可以變通以下,先打開一個空窗口,然后等數(shù)據(jù)回來后替換為需要的地址
如下所示:
<!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.; } } }; 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>
服務(wù)端代碼如下:
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回調(diào)中新窗口被攔截的問題。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流。
相關(guān)文章
JavaScript-RegExp對象只能使用一次問題解決方法
RegExp對象執(zhí)行了一次后就廢掉了,所以每次用RegExp都需要重新new一個,下面有個示例,需要的朋友可以參考下2014-06-06網(wǎng)頁開發(fā)中的容易忽略的問題 javascript HTML中的table
最近在搞在線電子表格這個東西,下面的是使用中的一些知識技巧。2009-04-04JS導(dǎo)出PDF插件的方法(支持中文、圖片使用路徑)
下面小編就為大家?guī)硪黄狫S導(dǎo)出PDF插件的方法(支持中文、圖片使用路徑)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-07-07HTML+CSS+JavaScript做女朋友版的刮刮樂(一看就會)
這篇文章主要介紹了HTML+CSS+JavaScript做女朋友版的刮刮樂(一看就會)本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-08-08關(guān)于UTF-8的客戶端用AJAX方式獲取GB2312的服務(wù)器端亂碼問題的解決辦法
客戶端是UTF-8編碼,這也是現(xiàn)在大家公認(rèn)的標(biāo)準(zhǔn)編碼在這種情況下,實用AJAX異步獲取GB2312編碼的服務(wù)器端信息時,不可避免的要遇到漢字亂碼問題2010-11-11