一步步教你实现弹出窗口(第3部分)

这部分的内容是绑定事件,模拟模态窗口与拖动。先从最简单的说起,弹出窗口现在有三个按钮,反正都是点击事件,我们可以利用事件代理以节省侦听器。侦听器放在顶层容器中就是,然后我们再判定冒泡上来的事件的源对象的标签是否为a元素,再根据其类名添加相应的事件。


      container.onclick = function(){
        var ee = me.getEvent(), node = ee[1],tag = ee[2];
        if(tag == "a" ){
          switch(node.className){
            case "closebtn" :            
              me.hide();
              break;
            case "positive" :
              me.hide();
              //form.submit();
              break;
            case "negative" :
              alert("你点击了取消按钮!");
              break;
          }
        }
      }

其中me即为this,Dialog类的实例,因为就这样简单把this暴露在绑定函数中,它对应的是container这个顶层容器,而不是实例。hide方法的功能很简单,隐藏顶层容器。getEvent方法的具体代码可参见我的另一篇博文,用来快捷取得事件,事件源对象以及源对象的标签名。到此,绑定事件部分讲完了。

再看拖放,我以前有两篇博文专门说这问题,可参见这里这里。现在扼要演实一下如何运用。首先在init()主方法中添加如下代码:


      container.onmousedown = function(e){
        e = e || event;
        container.offset_x = e.clientX - container.offsetLeft;
        container.offset_y = e.clientY - container.offsetTop;
        document.onmousemove = function(e){
          me.drag(e,container)
        }
        document.onmouseup = function(){
          me.dragend(container)
        }
      }

然后再添加两个原型方法,分别为drag与dragend。


    drag:function(e,el){
      e = e || event;//获得事件对象
      var l = e.clientX - el.offset_x  + "px",
      t = e.clientY - el.offset_y  + "px";
      this.incss(el, {cursor:"move",left:l,top:t})
        !+"/v1"? document.selection.empty() : window.getSelection().removeAllRanges();
    },
    dragend:function(el){
      el.style.cursor = "";
      document.onmouseup = document.onmousemove = null;
    },

因为我原来的动态添加样式规则方法css名副其实,就是动态添加,不具备修改能力,因此对于在拖动中频繁修改的CSS属性就无能为力了,于是我又用回内联样式。它的代码很简单,以前我也多次演示过这东西。


    incss:function(node,bag){
      var str = ";"
      for(var i in bag){
        if(bag.hasOwnProperty(i))
          str += i+":"+bag[i]+";"
      }
      node.style.cssText = str;
    },

如果IE6死掉是多么美好了,基本上就是这样简单。我们在IE6中拖啊拖,遇到select标签了!为了掩住了它,我们需要一个iframe标签,并把它放到顶层容器之前(它与顶层容器是兄弟节点)。由于我们的弹出窗口是有阴影的,因此iframe的大小应该为弹出窗口加阴影的大小,并且其z-index比它顶层容器一点。


      if(me.ie6){
        me.iframe = document.createElement("<iframe style='position:absolute;left:"+
          me.left+"px;top:"+me.top+"px;width:"+(me.width+10)+"px;height:"+
          (me.height+10)+"px;z-index:1;display:none;filter:mask()' ></iframe>");
        container.insertAdjacentElement('beforeBegin',me.iframe);
      }

在拖动窗口时也拖动iframe。


    drag:function(e,me){
      e = e || event;//获得事件对象
      var el = me.container,
      l = e.clientX - el.offset_x  + "px",
      t = e.clientY - el.offset_y  + "px";
      this.incss(el, {cursor:"move",left:l,top:t})
      if(this.ie6){
        with(me.iframe.style){//当用cssText设置iframe的样式时,其display变为inline,就无法掩住select
          left=l;                   //另,当设置iframe的allowTransparency="true" ,也不能掩住select
          top=t;
        }
      }
        !+"/v1"? document.selection.empty() : window.getSelection().removeAllRanges();
    },

最看模态窗口的实现。现在所有浏览器都支持showModeDialog方法了,即使是火狐。但在首次使用此方法,IE会有提示是否允许执行。若用户以前做够了弹出广告的骚扰,我们再用这方法来实现,恐怕就行不通了。因此我是使用纯DIV来模拟。首先是冻结窗口,把可视区外部分隐藏掉,阻止滚动条出现。其次阻止弹出窗口外的其他部分的右键事件与选择事件。


    mode:function(w,h){
      var mask = Dialog.mask,me = this;
      //IE6的addRule方法存在bug,不支持联合选择器,即html,body{*********}这种形式,只好分开写!
      this.css("html","margin:0;border:0;width:100%;height:100%;overflow:hidden;");
      this.css("body","margin:0;border:0;width:100%;height:100%;overflow:hidden;");
      this.incss(mask,{position:"absolute",background:"#fff",top:0,left:0,
        width:w +"px",height:h +"px","-moz-user-select":"none"});
        !+"/v1"? (mask.style.filter = "alpha(opacity=0)") : (mask.style.opacity = "0");
      mask.onselectstart = function(e){//不允许选择弹出窗口以外的内容
        me.stopEvent(e);
      }
      mask.oncontextmenu = function(e){//不允许在弹出窗口外弹出右键窗口
        me.stopEvent(e);
      }
    },

mode方法我们在show与hide中调用。


    hide : function(){
      this.container.style.display = "none" ;
      if(this.ie6){
        this.iframe.style.display = "none";
      }
      this.mode(0,0);
      //下面两行目的是生成 html,body{width:auto;height:auto;overflow:auto;}
      this.incss(document.body, {width:"auto",height:"auto",overflow:"auto"});
      this.incss(document.documentElement, {width:"auto",height:"auto",overflow:"auto"});
    },
    show : function(){
      this.container.style.display = "block" ;
      if(this.ie6){
        this.iframe.style.display = "block";
      }
      var size = this.getBrowserWindowSize();
      this.mode(size.width, size.height);
    },

stopEvent方法是用来阻止事件冒泡与浏览器的默认事件,一个非常常用的方法。


    stopEvent:function(e){
      e = e || window.event;
      if(e.preventDefault) {
        e.preventDefault();
        e.stopPropagation();
      }else{
        e.returnValue = false;
        e.cancelBubble = true;
      }
    },

基本上是这样,300多行,为了兼容Opera的圆角与阴影,有30多行分配给它,为了修正IE6的select bug,有10行分配给它,为了让标准浏览器拥有IE风格的设置样式规则的方法,又要20行。其他的兼容代码估计也有二十行左右。因此浏览器这东西还是一家独大好了。我这个弹出窗口其实还有许多改进之处,如把圆角半透明边框独立出来,作为一个接口,那个动态添加样式的也可以再扩展一下,独立出来,做成另一个接口,再把模态化与拖动独立出来,然后像mootools那样实现类好了,超优雅。

下载
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值