国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 網(wǎng)站 > WEB開發(fā) > 正文

貼近瀏覽器窗口右側(cè)的jqueryuidialog快速從左側(cè)調(diào)整大小時對話框大小設(shè)置不準(zhǔn)確的問題

2024-04-27 15:01:34
字體:
供稿:網(wǎng)友

之前在做兩個相同的頁面的事件同步時發(fā)現(xiàn)了這個問題,現(xiàn)在把它記錄下來。

一、問題描述

  頁面中的jqueryui對話框,如果把它拖動到靠近瀏覽器窗口右側(cè)邊緣,并快速從對話框左側(cè)調(diào)整對話框窗口大小時,對話框右側(cè)會偏離瀏覽器窗口右側(cè)邊緣,其實就是對話框窗口寬度計算不準(zhǔn)確。為了更好地說明問題,下面給出幾張示意圖。(黑色背景框是瀏覽器窗口)

  圖1、對話框窗口開始放在瀏覽器右側(cè)邊緣,從左側(cè)緩慢調(diào)整窗口大小過程中,對話框窗口右側(cè)會發(fā)生“抖動”

  

  圖2、對話框窗口開始放在瀏覽器右側(cè)邊緣,稍微快一點從左側(cè)調(diào)整窗口大小,對話框右側(cè)跟瀏覽器窗口邊緣出現(xiàn)間距

  

  圖3、對話框窗口開始放在瀏覽器右側(cè)邊緣,快速從左側(cè)調(diào)整窗口大小,對話框右側(cè)的偏離情況更加明顯

  

  圖4、如果對話框窗口的位置沒有靠近瀏覽器窗口右側(cè)邊緣,調(diào)整對話框大小的情況正常

  

  以上幾張圖說明,當(dāng)對話框初始位置放在瀏覽器右側(cè)邊緣時,從左側(cè)調(diào)整對話框大小會出現(xiàn)對話框?qū)挾扔嬎悴徽_的問題。

  你也可以自己試一試:http://jqueryui.com/dialog/ 

二、問題分析

  我們知道,鼠標(biāo)移動的事件并不是連續(xù)觸發(fā)的,即使兩次鼠標(biāo)移動事件之間的間隔很短。所以如果鼠標(biāo)移動得很快,在兩次鼠標(biāo)移動事件之間鼠標(biāo)移動的距離會比較大。快速調(diào)整對話框大小時,在兩次鼠標(biāo)移動事件觸發(fā)的間隔中鼠標(biāo)移動了較長距離。我們可以通過腳本創(chuàng)建并觸發(fā)事件的方式來模擬快速調(diào)整對話框大小的過程,看看在這個過程中執(zhí)行了什么操作并分析哪里出了問題。

  為了模擬快速從對話框左側(cè)調(diào)整大小,下面會依次創(chuàng)建mouSEOver,mousedown,mousemove事件并在對話框左側(cè)的resize handler上面觸發(fā)(mousedown和mousemove事件的e.pageX相差較大)。

  圖5、對話框的初始寬度和位置

  對話框的初始位置和寬度

  首先在控制臺執(zhí)行下面的代碼,依次創(chuàng)建mouseover、mousedown和mousemove事件并觸發(fā)。

 1 var mouseover_event = new MouseEvent('mouseover', { 2         bubbles: true, 3         clientX: 1389, 4         clientY: 475, 5         layerX: 1389, 6         layerY: 475, 7         pageX: 1389, 8         pageY: 475 9     });10     var mousedown_event = new MouseEvent('mousedown', {11         bubbles: true,12         clientX: 1389,13         clientY: 475,14         layerX: 1389,15         layerY: 475,16         pageX: 1389,17         pageY: 47518     });19     var mousemove_event = new MouseEvent('mousemove', {20         bubbles: true,21         clientX: 1000,22         clientY: 475,23         layerX: 1000,24         layerY: 475,25         pageX: 1000,26         pageY: 47527     });28     var resize_handler = document.querySelector('.ui-resizable-handle.ui-resizable-w');29     resize_handler.dispatchEvent(mouseover_event);30     resize_handler.dispatchEvent(mousedown_event);31     resize_handler.dispatchEvent(mousemove_event);

  接著跟蹤相應(yīng)事件處理程序的執(zhí)行。在jqueryui源代碼中,當(dāng)觸發(fā)mousemove事件時,下面的的代碼片段會執(zhí)行(添加了實時執(zhí)行結(jié)果的注釋):

 1 _mouseDrag: function(event) { 2  3         var data, PRops, 4             smp = this.originalMousePosition,  // 鼠標(biāo)剛按下時的位置(1389, 475) 5             a = this.axis, 6             dx = (event.pageX - smp.left) || 0,  // -389 7             dy = (event.pageY - smp.top) || 0, 8             trigger = this._change[a]; 9 10         this._updatePrevProperties();  // 設(shè)置prevPosition和prevSize,prevPosition.left=1389, prevSize.width=522.611 12         if (!trigger) {13             return false;14         }15 16         data = trigger.apply(this, [ event, dx, dy ]);  // 計算對話框最終應(yīng)設(shè)置的left和width,data={left:1000,width:911.6}17 18         this._updateVirtualBoundaries(event.shiftKey);19         if (this._aspectRatio || event.shiftKey) {20             data = this._updateRatio(data, event);21         }22 23         data = this._respectSize(data, event);24 25         this._updateCache(data);  // 更新對話框最終應(yīng)設(shè)置的position和size,執(zhí)行完之后this.position.left=1000,this.size.width=911.626 27         this._propagate("resize", event);28 29         props = this._applyChanges();30 31         if ( !this._helper && this._proportionallyResizeElements.length ) {32             this._proportionallyResize();33         }34 35         if ( !$.isEmptyObject( props ) ) {36             this._updatePrevProperties();37             this._trigger( "resize", event, this.ui() );38             this._applyChanges();39         }40 41         return false;42     }43             

  當(dāng)執(zhí)行到上面代碼的第27行時(this._propagate("resize", event);),用Chrome開發(fā)者工具跟蹤到以下這段代碼:

 1 resize: function( event ) { 2         var woset, hoset, isParent, isOffsetRelative, 3             that = $( this ).resizable( "instance" ), 4             o = that.options, 5             co = that.containerOffset, 6             cp = that.position, 7             pRatio = that._aspectRatio || event.shiftKey, 8             cop = { 9                 top: 0,10                 left: 011             },12             ce = that.containerElement,13             continueResize = true;14 15         if ( ce[ 0 ] !== document && ( /static/ ).test( ce.CSS( "position" ) ) ) {16             cop = co;17         }18 19         if ( cp.left < ( that._helper ? co.left : 0 ) ) {20             that.size.width = that.size.width +21                 ( that._helper ?22                     ( that.position.left - co.left ) :23                     ( that.position.left - cop.left ) );24 25             if ( pRatio ) {26                 that.size.height = that.size.width / that.aspectRatio;27                 continueResize = false;28             }29             that.position.left = o.helper ? co.left : 0;30         }31 32         if ( cp.top < ( that._helper ? co.top : 0 ) ) {33             that.size.height = that.size.height +34                 ( that._helper ?35                     ( that.position.top - co.top ) :36                     that.position.top );37 38             if ( pRatio ) {39                 that.size.width = that.size.height * that.aspectRatio;40                 continueResize = false;41             }42             that.position.top = that._helper ? co.top : 0;43         }44 45         isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );46         isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );47 48         if ( isParent && isOffsetRelative ) {49             that.offset.left = that.parentData.left + that.position.left;50             that.offset.top = that.parentData.top + that.position.top;51         } else {  // 會執(zhí)行到這里52             that.offset.left = that.element.offset().left;  // 初始狀態(tài)的offset,that.offset.left=138953             that.offset.top = that.element.offset().top;54         }55 56         woset = Math.abs( that.sizeDiff.width +57             (that._helper ?58                 that.offset.left - cop.left :59                 (that.offset.left - co.left)) );  // 加上that.sizeDiff.width(6.4),woset=1395.460 61         hoset = Math.abs( that.sizeDiff.height +62             (that._helper ?63                 that.offset.top - cop.top :64                 (that.offset.top - co.top)) );65 66         if ( woset + that.size.width >= that.parentData.width ) {  // 就是這一段出問題,單獨把這一段拿出來分析67             that.size.width = that.parentData.width - woset;68             if ( pRatio ) {69                 that.size.height = that.size.width / that.aspectRatio;70                 continueResize = false;71             }72         }73 74         if ( hoset + that.size.height >= that.parentData.height ) {75             that.size.height = that.parentData.height - hoset;76             if ( pRatio ) {77                 that.size.width = that.size.height * that.aspectRatio;78                 continueResize = false;79             }80         }81 82         if ( !continueResize ) {83             that.position.left = that.prevPosition.left;84             that.position.top = that.prevPosition.top;85             that.size.width = that.prevSize.width;86             that.size.height = that.prevSize.height;87         }88     }

  再單獨看看上面代碼第66行的條件判斷語句:

1 if ( woset + that.size.width >= that.parentData.width ) {2             that.size.width = that.parentData.width - woset;3             if ( pRatio ) {4                 that.size.height = that.size.width / that.aspectRatio;5                 continueResize = false;6             }7         }

  that.parentData.width=1920,是指對話框父節(jié)點的寬度,也就是document的寬度,

  that.size.width=911.6,前面的代碼也有提過,這個是指對話框最終應(yīng)被設(shè)置的寬度,

  woset=1395.4,這個其實就是鼠標(biāo)一開始按下時鼠標(biāo)的位置,也就是對話框初始狀態(tài)時的left值1389,相差的只是that.sizeDiff.width=6.4(上面的代碼有提到),

  對話框在初始狀態(tài)下,因為對話框貼近瀏覽器右側(cè)邊緣,所以  對話框初始left(1389)+對話框初始width(530)=1919(約等于瀏覽器寬度1920),

  再看看上面條件語句if(woset + that.size.width >= that.parentData.width), that.size.width用的是最新計算出來的對話框最終應(yīng)被設(shè)置的寬度,

  但woset卻用了對話框初始left而不是最新計算出來的對話框最終應(yīng)被設(shè)置的left(1000), 這樣1395.4 + 911.6 = 2307 > 1920,導(dǎo)致最后這條語句被執(zhí)行that.size.width = that.parentData.width - woset=1920 - 1395.4 = 524, 對話框最終應(yīng)被設(shè)置的寬度被重置了!

  對話框的寬度最終被設(shè)置為524(初始寬度是530),相當(dāng)于對話框left值改變了,寬度卻沒有改變,調(diào)整大小的操作變成了拖拽的操作。對話框最終的大小和位置如下圖6(width和left寫反了):

對話框的最終位置和寬度

  所以,引起對話框?qū)挾仍O(shè)置不正確的原因是上面那個判斷語句中,對話框的寬度用了最新計算出來的寬度,left值卻用了之前的值。或者說既然對話框最終應(yīng)被設(shè)置的寬度和位置都已經(jīng)計算出來了,就不用再做判斷和重置對話框?qū)挾攘恕?/span>

  如果慢慢調(diào)整對話框大小的話,最新計算出來的left值和之前的left值相差不大,就算執(zhí)行了寬度重置語句“that.size.width = that.parentData.width - woset;”,最終對話框被設(shè)置的寬度也不會相差太大,而且一般情況下鼠標(biāo)抬起之前的兩次mousemove事件鼠標(biāo)的坐標(biāo)基本一樣或相差很小,也就是說鼠標(biāo)抬起之前的一次鼠標(biāo)移動事件中計算出來的對話框應(yīng)被設(shè)置的left值跟前一次被設(shè)置的left值基本相等,所以鼠標(biāo)抬起之前對話框的寬度又被“修正”了。

  在上面的圖1中也可以看出,再向左調(diào)整對話框大小的過程中,對話框的右側(cè)一直在“抖動”和不斷修正的過程,而且隨著鼠標(biāo)移動速度的增大,這種“抖動”過程會更加明顯。

  而從上面的圖4中我們可以看到,如果對話框的位置不是放在靠近瀏覽器窗口的右側(cè)邊緣,是不會出現(xiàn)寬度設(shè)置不正確的問題的。因為這種情況下這個判斷語句(woset + that.size.width >= that.parentData.width)的結(jié)果不太容易為真,特別是當(dāng)對話框的位置離瀏覽器窗口有邊緣較遠(yuǎn)的時候,下面的對話框?qū)挾戎刂谜Z句也不會執(zhí)行。

  根據(jù)上面的分析,當(dāng)對話框底部貼近瀏覽器窗口底部并從對話框上面調(diào)整大小,或者對話框右下角貼近瀏覽器窗口右下角并從左上角方向調(diào)整大小時,都會出現(xiàn)對話框?qū)挾然蛘吒叨仍O(shè)置不正確的問題。

三、問題修復(fù)

  如果把上面的對話框?qū)挾戎刂谜Z句去掉,或者把woset的值改為用最新的計算出來的對話框left值,就不會出現(xiàn)對話框?qū)挾然蛘吒叨仍O(shè)置不正確的問題。如下:

1 woset = event.pageX;  // 添加這一句,或者woset = cp2 if ( woset + that.size.width >= that.parentData.width ) {3      that.size.width = that.parentData.width - woset;  // 或者把這一句注釋,二選一4      if ( pRatio ) {5          that.size.height = that.size.width / that.aspectRatio;6          continueResize = false;7      }8 }

  圖7、修改了代碼之后,無論怎么拖動調(diào)整大小,對話框窗口右側(cè)不會發(fā)生偏離。

  

  圖8、快速調(diào)整大小也正常

  

  圖9、用腳本觸發(fā)的方式也正常

  用腳本模擬快速調(diào)整對話框的大小,對話框表現(xiàn)正常

  至于jqueryui源代碼里面為什么要把對話框?qū)挾戎刂茫约盀槭裁磁袛鄷r使用“之前的left值”,還沒想明白。

四、其他說明

  使用的jqueryui的版本為1.11.4 。

  可能大家會有這樣的疑問,即使jqueryui dialog有這樣的問題,但是這根本不影響使用,可以說這根本就不算是什么問題,而且有誰會像我這樣快速地對對話框進(jìn)行拖拽?

  但考慮一下下面的場景,我也是在這種情況下發(fā)現(xiàn)的這個問題。

  最近我在做兩個相同頁面之間的事件同步,例如小屏端和大屏端運行同一個頁面,我在小屏上做的操作需要同步到大屏上,其實這也是某個項目的需求。這時候我在小屏調(diào)整某個對話框的大小,如果實時同步到大屏的話,將會發(fā)送大量的請求。為了避免這個問題,就只把鼠標(biāo)抬起之前的那次mousemove事件發(fā)送過去。所以在小屏端完成一次調(diào)整大小的操作,會把mouseover,mousedown,mousemove和mouseup事件的信息各發(fā)送一次到大屏端,大屏端收到消息之后再觸發(fā)一次這些事件。這就跟我上面用事件模擬的過程一樣,因為jqueryui對話框的重置寬度的問題,小屏端對對話框的調(diào)整大小操作,同步到大屏端之后就像是對話框的拖拽操作一樣,只是對話框位置改變而大小沒有改變。

  在這種情況下,jqueryui對話框的這個問題就會造成比較大的影響。

  


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 长顺县| 卓资县| 壶关县| 峨眉山市| 当雄县| 平塘县| 曲沃县| 共和县| 宁城县| 腾冲县| 肃宁县| 鱼台县| 楚雄市| 攀枝花市| 正宁县| 原平市| 乌鲁木齐县| 仲巴县| 深圳市| 法库县| 蓬安县| 凤城市| 许昌市| 阿克陶县| 苍山县| 达孜县| 黄浦区| 随州市| 安塞县| 榆中县| 广河县| 濮阳市| 靖宇县| 普兰店市| 锦州市| 雷山县| 游戏| 石台县| 渭源县| 莱州市| 彭山县|