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

本文介绍了一个自定义的弹出窗口组件实现过程,包括结构层、表现层和行为层的详细设计,兼容多种浏览器,并实现了圆角、半透明及阴影效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上部分已给出主要辅助方法css了,有了它我们就可以实现类的实例的样式共享。另外,我们的类的实现模式是基于prototype,这样就实现方法共享。现在我们来看看如何渲染它,首先呈上它大体的结构层代码:


<div id="" class="popups" >
  <div class="caption"></div>
  <form>
    <div class="replaceable"></div>
    <div class="submitable">
      <a class="negative" href="javascript:void(0)">取消</a>
      <a class="positive" href="javascript:void(0)">确认</a>
    </div>
  </form>
  <a class="closebtn" href="javascript:void(0)"></a>
</div>

这结构层代码比腾讯那个简单得多了,而且没用到table来布局,全凭CSS来处理。虽然元素很少,但如果用W3C那一套操作DOM的API来干活,也要十多行。我们不想一味地createElement然后appendChild的话,就要派innerHTML上场了。一个常识是,当DOM超过十个时,就要考察用字符串拼接实现,这样代码看起来也直观一点。我们再来分析一下这结构层。顶层是一个DIV,不用说,它是弹出层,其他东西都直接构筑在它的上面。考察到一个页面可能存在多个动态生成的弹出窗口,因此我赋给他们一个独一无二的标识,也就是ID。ID在我的样式蓝图中没有用,要实现共享就要用class,我给它一个popups值。接着是标题栏,看上去空荡荡,然后它有一个文本节点,与一张背景图片做icon,还有一个关闭按钮(我把它放到最底层了class="closebtn")。这里要用绝对定位。然后是一个表单,表单分两部分,一是替换区(replaceable),为什么这样叫?因为它视alert,prompt,confirm等功能而重写。一个是提交区,有两个按钮。你们可能奇怪了,为什么不用语义化更强、制定性更好的button标签来实现呢?这都怪IE6在拖后腿,只有带href属性的a标签才支持hover伪类。之所以用hover伪类,是因为我不想在它们上面多绑定两个事件(mouseover与mouseout)。而为什么确认按钮放在取消按钮之后呢?因为我们稍后要用到向右浮动。整个提交区是位于form的底部的,这个我们可以用bottom:0来实现。


  Dialog.prototype = {
    constructor: Dialog,
    init: function() {
      var container = this.container,width = this.width, height = this.height,
      id = this.id,builder = [],
      document.body.insertBefore(container,null);
      container.id = id;
      container.className = "popups";
      builder.push('<div class="caption">'+this.title+'</div>');
      builder.push('<form><div class="replaceable"></div>');
      builder.push('<div class="submitable">');
      builder.push('<a class="negative" href="javascript:void(0)">取消</a>');
      builder.push('<a class="positive" href="javascript:void(0)">确认</a>');
      builder.push('</div></form>');
      builder.push('<a class="closebtn" href="javascript:void(0)"></a>');
      container.innerHTML = builder.join('');
   }
}

这样就创建完成了,比腾讯的垃圾代码精简多了。我们来看表现层。要做得好看,得花一些功夫。自已用IE8开发人员工具看生成后的CSS代码吧。它已经使用到CCS3的圆角特征(这在IE8中看不到)。有的人想去掉按下按钮时出现的虚线框,这里给出一个简捷方法:outline:0。

接着看如何实现圆角与半透明效果与盒阴影。如果不考虑IE与Opera,只需要多添加三行代码:


this.css(".popups","background:rgba(104,223,251,.8)");
this.css(".popups","-moz-border-radius:5px;-moz-box-shadow:10px 10px 5px #c0c0c0;");
this.css(".popups","-webkit-border-radius:5px;-webkit-box-shadow:10px 10px 5px #c0c0c0;");

不过要实现兼容IE也不难,就是利用VML生成一个圆角矩形,然后利用二级标记fill与shadow轻易实现上述功能。由于VML元素与HTML元素是位于同一个层的,因此我们插入这些VML时肯定会影响原来的文档流,因此我的弹出层的大多数对象都是定位元素,这样谁都影响不了谁。标准浏览器就有点麻烦了,本来我费了很大劲用canvas实现圆角矩形,但回头发现它不住阴影fillShadow等方法。于是改用SVG。我们可以比较一下动态生成后VML与SVG的代码。


//利用canvas实现圆角矩形
        var canvas =  document.createElement("canvas");
        container.insertBefore(canvas,null);
        this.attr(canvas,{width:width,height:height,className:"canvas"});
        this.css("#"+this.id +" canvas" ,"position:absolute;");
        if(canvas.getContext) {
          var ctx = canvas.getContext('2d');
          ctx.fillStyle = "rgba(104,223,251,.5)";
          roundedRect(ctx,0, 0, width, height,5);
          ctx.shadowColor = '#00f';
          ctx.shadowOffsetX = 16;
          ctx.shadowOffsetY = 16;
          ctx.shadowBlur = 8;
          ctx.shadowColor = 'rgba(0, 0, 255, 0.25)';
          function roundedRect(ctx,x,y,width,height,radius){
            ctx.beginPath();
            ctx.moveTo(x,y+radius);
            ctx.lineTo(x,y+height-radius);
            ctx.quadraticCurveTo(x,y+height,x+radius,y+height);
            ctx.lineTo(x+width-radius,y+height);
            ctx.quadraticCurveTo(x+width,y+height,x+width,y+height-radius);
            ctx.lineTo(x+width,y+radius);
            ctx.quadraticCurveTo(x+width,y,x+width-radius,y);
            ctx.lineTo(x+radius,y);
            ctx.quadraticCurveTo(x,y,x,y+radius);
            ctx.fill();
          }
        }

<vml:roundrect class="vml" style="position: absolute;width:400px; height:300px;top:0px;left:0px;">
  <vml:fill class="vml" opacity="0.8" color="#68DFFB" />
  <vml:shadow class="vml" on="t" color="#333" opacity="0.2"  offset="10px,10px" />
</vml:roundrect>

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="410px" height="310px">
  <defs>
    <filter id="drop-shadow">
      <feGaussianBlur in="SourceAlpha" result="blur-out" stdDeviation="1.5" />
      <feOffset in="blur-out" result="the-shadow" dx="0" dy="2" />
      <feBlend in="SourceGraphic" in2="the-shadow" mode="normal" />
    </filter>
  </defs>
  <rect x="10px" y="10px" width="400px" height="300px" rx="5"  fill="#333"
        style="opacity:0.2" filter="url(#drop-shadow)"/>
  <rect width="400px" height="300px" rx="5"  fill="#68DFFB" style="opacity:0.8" />
</svg>

接着下来就是绑定事件了,字符串拼接有一个不好处,要获取刚刚生成的DOM对象的引用比较麻烦。不过我打算利用事件代理就另当另论了,因为我们手头上最明确的对象就是那个DIV元素,我们把所有事件都绑定在它上面就是了。这个留在下次说。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值