關(guān)注技術(shù),關(guān)注生活

          任何事情只要開始去做,永遠(yuǎn)不會太遲。
          posts - 5, comments - 23, trackbacks - 0, articles - 18
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          問題起因:
          在原來產(chǎn)品中實(shí)現(xiàn)的 ajax tree上面添加拖拽效果,為了方便,使用了prototype來簡化開發(fā)。代碼中使用了Poistion.absolutize來改變拖動標(biāo)簽時改變它的坐標(biāo)為絕對坐標(biāo)顯示,拖動結(jié)束后再使用Poistion.relativize變回相對坐標(biāo)。

          解決過程:
          其實(shí)一開始測試時都挺好的,但后來在tree上面使用時就發(fā)生問題了,在拖動過程,標(biāo)簽跟著鼠標(biāo)的移動而改變,沒有問題,但在鼠標(biāo)釋放后,標(biāo)簽并沒有放置在鼠標(biāo)釋放的位置,而是向左和向上偏移了,而這偏移的距離剛好就是tree顯示位置的left和top。在對拖動結(jié)束后的位置計算的代碼,拖動過程坐標(biāo)計算的代碼debug了一天沒有收獲后,突然想到把樣式中的滾動條設(shè)置(overflow-x : "auto", overflow-y: "scroll",)刪掉試下,沒想到就可以了。

          經(jīng)過反復(fù)驗(yàn)證,終于證實(shí)是滾動條惹的禍,接著就跟蹤了prototype中的相關(guān)代碼,在實(shí)現(xiàn)Position.absolutize方法時是這樣寫的:

          Position.absolutize? = ? function (element)? {
          ????element?
          = ?$(element);
          ????
          if ?(element.style.position? == ?'absolute')? return ;
          ????Position.prepare();

          var ?offsets? = ?Position.positionedOffset(element);

          ????
          var ?top????? = ?offsets[ 1 ];
          ????
          var ?left???? = ?offsets[ 0 ];
          ????
          var ?width??? = ?element.clientWidth;
          ????
          var ?height?? = ?element.clientHeight;

          ????element._originalLeft???
          = ?left? - ?parseFloat(element.style.left?? || ? 0 );
          ????element._originalTop????
          = ?top?? - ?parseFloat(element.style.top? || ? 0 );
          ????element._originalWidth??
          = ?element.style.width;
          ????element._originalHeight?
          = ?element.style.height;

          ????element.style.position?
          = ?'absolute';
          ????element.style.top????
          = ?top? + ?'px';
          ????element.style.left???
          = ?left? + ?'px';
          ????element.style.width??
          = ?width? + ?'px';
          ????element.style.height?
          = ?height? + ?'px';
          }
          ;

          其中Position.positionedOffset就是取當(dāng)前標(biāo)簽到body的偏移量,然后將信息存入_original*的相關(guān)屬性中,等到調(diào)用Position.relativize時,再從這些_original*屬性中從新計算出當(dāng)前標(biāo)簽的相對位置。
          再看一下Position.relativize的實(shí)現(xiàn):

          Position.relativize?
          =?function(element)?{
          ????element?
          =?$(element);
          ????
          if?(element.style.position?==?'relative')?{
          ????????
          return;????
          ????}

          ????
          ????Position.prepare();
          ????
          ????element.style.position?
          =?'relative';
          ????
          var?top??=?parseFloat(element.style.top??||?0)?-?(element._originalTop??||?0);
          ????
          var?left?=?parseFloat(element.style.left?||?0)?-?(element._originalLeft?||?0);
          ????element.style.left???
          =?left?+?'px';
          ????element.style.top????
          =?top??+?'px';
          ????element.style.height?
          =?element._originalHeight;
          ????element.style.width??
          =?element._originalWidth;
          }
          ;

          嗯,處理得非常漂亮,沒有存在什么問題,以下是用來測試有html,試下會有什么效果
          <div?style="height:50px"></div>
          <div?style="width:500px;overflow-y:auto;height:300px">
          <div?style="height:200px"></div>
          <div?style="height:300px">
          <div?id="test"?style="height:20px">test</div>
          ????
          <input?type="button"?value="abs"?onclick="Position.absolutize('test');">
          ????
          <input?type="button"?value="rel"?onclick="Position.relativize('test');">
          ????
          </div>
          </div>

          沒錯,按下abs按鈕后,test向下移了50px左右(第二個div的offsetTop),也向右移了一點(diǎn)(第二個div的offsetLeft)。(如果把overflow-y:aut去掉,則沒有此情況出現(xiàn))而再按下rel按鈕后,test能回復(fù)正常的位置,這就表示它在算法上沒有什么問題,問題出在了absolutize后的位置上了,而與位置相關(guān)的信息有 _originalTop 和_originalLeft,而它們的值是與Position.positionedOffset直接相關(guān)的,再查看了Position.positionedOffset的代碼:

          Position.positionedOffset?
          =?function?(element)?{????
          ????
          var?node?=?element.parentElement;????
          ????
          var?valueT?=?0,?valueL?=?0;
          ????
          ????
          do?{
          ????????valueT?
          +=?element.offsetTop?||?0;
          ????????valueL?
          +=?element.offsetLeft?||?0;
          ????????element?
          =?element.offsetParent;
          ????????
          if?(element)?{????????
          ????????????p?
          =?Element.getStyle(element,?"position");
          ????????????
          if?(p?==?"relative"?||?p?==?"absolute"?){
          ????????????????
          break;
          ????????????}

          ????????}

          ????}
          ?while?(element);????????
          ????
          ????
          return?[valueL,?valueT];
          }
          ;

          看起來似乎也無法從中找出什么毛病來。可是,查了一下html的相關(guān)文檔后,發(fā)現(xiàn)這段代碼存在著相當(dāng)嚴(yán)重的bug。html文檔里,當(dāng)樣式position取絕對坐標(biāo)"absolute "時,其內(nèi)容如下:
          absolute :Object is positioned relative to parent element's position—or to the body object if its parent element is not positioned—using the top and left properties.
          結(jié)合文檔內(nèi)容,經(jīng)過測試,如果標(biāo)簽的所有祖先節(jié)點(diǎn)中,有任何一個是可滾動的(overflow,overflow-y,overflow-x其中一個屬性的值為auto或scroll),那標(biāo)簽的絕對定位就是在此標(biāo)簽中的坐標(biāo)位置,而不是對于BODY的。
          所以positionedOffset方法沒有考慮到這種情況而處理,當(dāng)然在一般情況下行得通了,所以代碼更改如下:


          Position.positionedOffset?
          =?function?(element)?{????
          ????
          ????
          ????
          /*
          ?????*?經(jīng)過測試,如果標(biāo)簽的所有祖先節(jié)點(diǎn)中,有任何一個是可滾動的(overflow,overflow-y,overflow-x其中一個屬性的值為auto或scroll),
          ?????*?那標(biāo)簽的絕對定位就是在此標(biāo)簽中的坐標(biāo)位置,而不是對于BODY的。所以在返回時應(yīng)該將此祖先節(jié)點(diǎn)對于body的偏移量減掉.
          ?????
          */

          ????????
          ????
          var?valueT?=?0,?valueL?=?0;
          ????
          ????
          do?{
          ????????valueT?
          +=?element.offsetTop?||?0;
          ????????valueL?
          +=?element.offsetLeft?||?0;
          ????????element?
          =?element.offsetParent;
          ????????
          if?(element)?{
          ????????????
          var?scrollable?=?[element.style.overflow,?element.style.overflowX,?element.style.overflowY];
          ????????????p?
          =?Element.getStyle(element,?"position");
          ????????????
          if?(p?==?"relative"?||?p?==?"absolute"?||?scrollable.include(?"auto"?)?||?scrollable.include(?"scroll"?))?{
          ????????????????
          break;
          ????????????}

          ????????}

          ????}
          ?while?(element);????????
          ????
          ????
          return?[valueL,?valueT];
          }
          ;

          至此,拖動后的標(biāo)簽定位問題終于解決,看來有時候人應(yīng)該相信自己多一點(diǎn),多懷疑一下別人的代碼,正所謂,讀書要善疑,更何況讀別人的程序。

          評論

          # re: [原創(chuàng)]prototype對于標(biāo)簽定位的一些BUG  回復(fù)  更多評論   

          2006-12-10 20:50 by Web 2.0 技術(shù)資源
          Object is positioned relative to parent element's position—or to the body object if its parent element is not positioned—using the top and left properties.

          查文檔才是王道!~

          # re: [原創(chuàng)]prototype對于標(biāo)簽定位的一些BUG  回復(fù)  更多評論   

          2006-12-11 19:41 by errorfun
          蛤查文檔也是得在知道哪里問題才能查啊,呵呵

          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 辽中县| 吴堡县| 安丘市| 双桥区| 镇雄县| 从江县| 阿巴嘎旗| 宣武区| 琼海市| 泸水县| 柳河县| 富平县| 伽师县| 新密市| 山西省| 临江市| 津南区| 邯郸市| 抚顺市| 澎湖县| 健康| 北京市| 赤水市| 南岸区| 资溪县| 建德市| 伊春市| 云龙县| 全州县| 房山区| 禹州市| 鸡西市| 炎陵县| 怀柔区| 湖北省| 巴里| 长乐市| 错那县| 怀来县| 五河县| 越西县|