一步步教你实现弹出窗口(第2部分)
上部分已给出主要辅助方法css了,有了它我们就可以实现类的实例的样式共享。另外,我们的类的实现模式是基于prototype,这样就实现方法共享。现在我们来看看如何渲染它,首先呈上它大体的结构层代码:
< div class = "cnblogs_code" >< pre > <!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> < span style = "color: #800000;" >< div id = "" class = "popups" >< br > < div class = "caption" ></ div >< br > < form >< br > < div class = "replaceable" ></ div >< br > < div class = "submitable" >< br > < a class = "negative" href = "javascript:void(0)" >取消</ a >< br > < a class = "positive" href = "javascript:void(0)" >确认</ a >< br > </ div >< br > </ form >< br > < a class = "closebtn" href = "javascript:void(0)" ></ a >< br ></ div ></ span ></ pre > </ 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来实现。
<div class= "cnblogs_code" ><pre><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http: //www.CodeHighlighter.com/<br /><br />--><span style="color: #000000;"> Dialog.prototype </span><span style="color: #000000;">=</span><span style="color: #000000;"> {<br> constructor: Dialog,<br> init: </span><span style="color: #0000FF;">function</span><span style="color: #000000;">() {<br> </span><span style="color: #0000FF;">var</span><span style="color: #000000;"> container </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">this</span><span style="color: #000000;">.container,width </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">this</span><span style="color: #000000;">.width, height </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">this</span><span style="color: #000000;">.height,<br> id </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">this</span><span style="color: #000000;">.id,builder </span><span style="color: #000000;">=</span><span style="color: #000000;"> [],<br> document.body.insertBefore(container,</span><span style="color: #0000FF;">null</span><span style="color: #000000;">);<br> container.id </span><span style="color: #000000;">=</span><span style="color: #000000;"> id;<br> container.className </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #000000;">"</span><span style="color: #000000;">popups</span><span style="color: #000000;">"</span><span style="color: #000000;">;<br> builder.push(</span><span style="color: #000000;">'</span><span style="color: #000000;"><br></span><span style="color: #000000;">'</span><span style="color: #000000;">+</span><span style="color: #0000FF;">this</span><span style="color: #000000;">.title</span><span style="color: #000000;">+</span><span style="color: #000000;">'</span><span style="color: #000000;"><br></span><span style="color: #000000;">'</span><span style="color: #000000;">);<br> builder.push(</span><span style="color: #000000;">'</span><span style="color: #000000;"><br></span><span style="color: #000000;">'</span><span style="color: #000000;">); builder.push(</span><span style="color: #000000;">'</span><span style="color: #000000;"><br></span><span style="color: #000000;">'</span><span style="color: #000000;">); builder.push(</span><span style="color: #000000;">'</span><span style="color: #000000;">取消</span><span style="color: #000000;">'</span><span style="color: #000000;">); builder.push(</span><span style="color: #000000;">'</span><span style="color: #000000;">确认</span><span style="color: #000000;">'</span><span style="color: #000000;">); builder.push(</span><span style="color: #000000;">'</span><span style="color: #000000;"><br></span><span style="color: #000000;">'</span><span style="color: #000000;">);<br> builder.push(</span><span style="color: #000000;">''</span><span style="color: #000000;">);<br> container.innerHTML </span><span style="color: #000000;">=</span><span style="color: #000000;"> builder.join(</span><span style="color: #000000;">''</span><span style="color: #000000;">);<br> }<br>}<br></span></pre> </div> |
这样就创建完成了。我们再来看表现层。要做得好看,得花一些功夫。自已用IE8开发人员工具看生成后的CSS代码吧。它已经使用到CCS3的圆角特征(这在IE8中看不到)。有的人想去掉按下按钮时出现的虚线框,这里给出一个简捷方法:outline:0。
接着看如何实现圆角与半透明效果与盒阴影。如果不考虑IE与Opera,只需要多添加三行代码:
<div class= "cnblogs_code" ><pre><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http: //www.CodeHighlighter.com/<br /><br />--><span style="color: #800000;">this.css(".popups","background:rgba(104,223,251,.8)");<br>this.css(".popups","-moz-border-radius:5px;-moz-box-shadow:10px 10px 5px #c0c0c0;");<br>this.css(".popups","-webkit-border-radius:5px;-webkit-box-shadow:10px 10px 5px #c0c0c0;");<br></span></pre> </div> |
不过要实现兼容IE也不难,就是利用VML生成一个圆角矩形,然后利用二级标记fill与shadow轻易实现上述功能。由于VML元素与HTML元素是位于同一个层的,因此我们插入这些VML时肯定会影响原来的文档流,因此我的弹出层的大多数对象都是定位元素,这样谁都影响不了谁。标准浏览器就有点麻烦了,本来我费了很大劲用canvas实现圆角矩形,但回头发现它不住阴影fillShadow等方法。于是改用SVG。我们可以比较一下动态生成后VML与SVG的代码。
<div class= "cnblogs_code" ><pre><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http: //www.CodeHighlighter.com/<br /><br />--><span style="color: #008000;">//</span><span style="color: #008000;">利用canvas实现圆角矩形</span><span style="color: #008000;"><br></span><span style="color: #000000;"> </span><span style="color: #0000FF;">var</span><span style="color: #000000;"> canvas </span><span style="color: #000000;">=</span><span style="color: #000000;"> document.createElement(</span><span style="color: #000000;">"</span><span style="color: #000000;">canvas</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br> container.insertBefore(canvas,</span><span style="color: #0000FF;">null</span><span style="color: #000000;">);<br> </span><span style="color: #0000FF;">this</span><span style="color: #000000;">.attr(canvas,{width:width,height:height,className:</span><span style="color: #000000;">"</span><span style="color: #000000;">canvas</span><span style="color: #000000;">"</span><span style="color: #000000;">});<br> </span><span style="color: #0000FF;">this</span><span style="color: #000000;">.css(</span><span style="color: #000000;">"</span><span style="color: #000000;">#</span><span style="color: #000000;">"</span><span style="color: #000000;">+</span><span style="color: #0000FF;">this</span><span style="color: #000000;">.id </span><span style="color: #000000;">+</span><span style="color: #000000;">"</span><span style="color: #000000;"> canvas</span><span style="color: #000000;">"</span><span style="color: #000000;"> ,</span><span style="color: #000000;">"</span><span style="color: #000000;">position:absolute;</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br> </span><span style="color: #0000FF;">if</span><span style="color: #000000;">(canvas.getContext) {<br> </span><span style="color: #0000FF;">var</span><span style="color: #000000;"> ctx </span><span style="color: #000000;">=</span><span style="color: #000000;"> canvas.getContext(</span><span style="color: #000000;">'</span><span style="color: #000000;">2d</span><span style="color: #000000;">'</span><span style="color: #000000;">);<br> ctx.fillStyle </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #000000;">"</span><span style="color: #000000;">rgba(104,223,251,.5)</span><span style="color: #000000;">"</span><span style="color: #000000;">;<br> roundedRect(ctx,</span><span style="color: #000000;">0</span><span style="color: #000000;">, </span><span style="color: #000000;">0</span><span style="color: #000000;">, width, height,</span><span style="color: #000000;">5</span><span style="color: #000000;">);<br> ctx.shadowColor </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #000000;">'</span><span style="color: #000000;">#00f</span><span style="color: #000000;">'</span><span style="color: #000000;">;<br> ctx.shadowOffsetX </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #000000;">16</span><span style="color: #000000;">;<br> ctx.shadowOffsetY </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #000000;">16</span><span style="color: #000000;">;<br> ctx.shadowBlur </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #000000;">8</span><span style="color: #000000;">;<br> ctx.shadowColor </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #000000;">'</span><span style="color: #000000;">rgba(0, 0, 255, 0.25)</span><span style="color: #000000;">'</span><span style="color: #000000;">;<br> </span><span style="color: #0000FF;">function</span><span style="color: #000000;"> roundedRect(ctx,x,y,width,height,radius){<br> ctx.beginPath();<br> ctx.moveTo(x,y</span><span style="color: #000000;">+</span><span style="color: #000000;">radius);<br> ctx.lineTo(x,y</span><span style="color: #000000;">+</span><span style="color: #000000;">height</span><span style="color: #000000;">-</span><span style="color: #000000;">radius);<br> ctx.quadraticCurveTo(x,y</span><span style="color: #000000;">+</span><span style="color: #000000;">height,x</span><span style="color: #000000;">+</span><span style="color: #000000;">radius,y</span><span style="color: #000000;">+</span><span style="color: #000000;">height);<br> ctx.lineTo(x</span><span style="color: #000000;">+</span><span style="color: #000000;">width</span><span style="color: #000000;">-</span><span style="color: #000000;">radius,y</span><span style="color: #000000;">+</span><span style="color: #000000;">height);<br> ctx.quadraticCurveTo(x</span><span style="color: #000000;">+</span><span style="color: #000000;">width,y</span><span style="color: #000000;">+</span><span style="color: #000000;">height,x</span><span style="color: #000000;">+</span><span style="color: #000000;">width,y</span><span style="color: #000000;">+</span><span style="color: #000000;">height</span><span style="color: #000000;">-</span><span style="color: #000000;">radius);<br> ctx.lineTo(x</span><span style="color: #000000;">+</span><span style="color: #000000;">width,y</span><span style="color: #000000;">+</span><span style="color: #000000;">radius);<br> ctx.quadraticCurveTo(x</span><span style="color: #000000;">+</span><span style="color: #000000;">width,y,x</span><span style="color: #000000;">+</span><span style="color: #000000;">width</span><span style="color: #000000;">-</span><span style="color: #000000;">radius,y);<br> ctx.lineTo(x</span><span style="color: #000000;">+</span><span style="color: #000000;">radius,y);<br> ctx.quadraticCurveTo(x,y,x,y</span><span style="color: #000000;">+</span><span style="color: #000000;">radius);<br> ctx.fill();<br> }<br> }<br></span></pre> </div> <div class= "cnblogs_code" > <pre><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http: //www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF;"><</span><span style="color: #800000;">vml:roundrect </span><span style="color: #FF0000;">class</span><span style="color: #0000FF;">="vml"</span><span style="color: #FF0000;"> style</span><span style="color: #0000FF;">="position: absolute;width:400px;<br> height:300px;top:0px;left:0px;"</span><span style="color: #0000FF;">></span><span style="color: #000000;"><br></span><span style="color: #0000FF;"><</span><span style="color: #800000;">vml:fill </span><span style="color: #FF0000;">class</span><span style="color: #0000FF;">="vml"</span><span style="color: #FF0000;"> opacity</span><span style="color: #0000FF;">="0.8"</span><span style="color: #FF0000;"> color</span><span style="color: #0000FF;">="#68DFFB"</span><span style="color: #FF0000;"> </span><span style="color: #0000FF;">/></span><span style="color: #000000;"><br></span><span style="color: #0000FF;"><</span><span style="color: #800000;">vml:shadow </span><span style="color: #FF0000;">class</span><span style="color: #0000FF;">="vml"</span><span style="color: #FF0000;"> on</span><span style="color: #0000FF;">="t"</span><span style="color: #FF0000;"> color</span><span style="color: #0000FF;">="#333"</span><span style="color: #FF0000;"> opacity</span><span style="color: #0000FF;">="0.2"</span><span style="color: #FF0000;"> offset</span><span style="color: #0000FF;">="10px,10px"</span><span style="color: #FF0000;"> </span><span style="color: #0000FF;">/></span><span style="color: #000000;"><br></span><span style="color: #0000FF;"></</span><span style="color: #800000;">vml:roundrect</span><span style="color: #0000FF;">></span></pre> </div> <div class= "cnblogs_code" > <pre><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http: //www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF;"><</span><span style="color: #800000;">svg </span><span style="color: #FF0000;">xmlns</span><span style="color: #0000FF;">="http://www.w3.org/2000/svg"</span><span style="color: #FF0000;"> version</span><span style="color: #0000FF;">="1.1"</span><span style="color: #FF0000;"> width</span><span style="color: #0000FF;">="410px"</span><span style="color: #FF0000;"> height</span><span style="color: #0000FF;">="310px"</span><span style="color: #0000FF;">></span><span style="color: #000000;"><br></span><span style="color: #0000FF;"><</span><span style="color: #800000;">defs</span><span style="color: #0000FF;">></span><span style="color: #000000;"><br> </span><span style="color: #0000FF;"><</span><span style="color: #800000;">filter </span><span style="color: #FF0000;">id</span><span style="color: #0000FF;">="drop-shadow"</span><span style="color: #0000FF;">></span><span style="color: #000000;"><br> </span><span style="color: #0000FF;"><</span><span style="color: #800000;">feGaussianBlur </span><span style="color: #FF0000;">in</span><span style="color: #0000FF;">="SourceAlpha"</span><span style="color: #FF0000;"> result</span><span style="color: #0000FF;">="blur-out"</span><span style="color: #FF0000;"> stdDeviation</span><span style="color: #0000FF;">="1.5"</span><span style="color: #FF0000;"> </span><span style="color: #0000FF;">/></span><span style="color: #000000;"><br> </span><span style="color: #0000FF;"><</span><span style="color: #800000;">feOffset </span><span style="color: #FF0000;">in</span><span style="color: #0000FF;">="blur-out"</span><span style="color: #FF0000;"> result</span><span style="color: #0000FF;">="the-shadow"</span><span style="color: #FF0000;"> dx</span><span style="color: #0000FF;">="0"</span><span style="color: #FF0000;"> dy</span><span style="color: #0000FF;">="2"</span><span style="color: #FF0000;"> </span><span style="color: #0000FF;">/></span><span style="color: #000000;"><br> </span><span style="color: #0000FF;"><</span><span style="color: #800000;">feBlend </span><span style="color: #FF0000;">in</span><span style="color: #0000FF;">="SourceGraphic"</span><span style="color: #FF0000;"> in2</span><span style="color: #0000FF;">="the-shadow"</span><span style="color: #FF0000;"> mode</span><span style="color: #0000FF;">="normal"</span><span style="color: #FF0000;"> </span><span style="color: #0000FF;">/></span><span style="color: #000000;"><br> </span><span style="color: #0000FF;"></</span><span style="color: #800000;">filter</span><span style="color: #0000FF;">></span><span style="color: #000000;"><br> </span><span style="color: #0000FF;"></</span><span style="color: #800000;">defs</span><span style="color: #0000FF;">></span><span style="color: #000000;"><br> </span><span style="color: #0000FF;"><</span><span style="color: #800000;">rect </span><span style="color: #FF0000;">x</span><span style="color: #0000FF;">="10px"</span><span style="color: #FF0000;"> y</span><span style="color: #0000FF;">="10px"</span><span style="color: #FF0000;"> width</span><span style="color: #0000FF;">="400px"</span><span style="color: #FF0000;"> height</span><span style="color: #0000FF;">="300px"</span><span style="color: #FF0000;"> rx</span><span style="color: #0000FF;">="5"</span><span style="color: #FF0000;"> fill</span><span style="color: #0000FF;">="#333"</span><span style="color: #FF0000;"><br> style</span><span style="color: #0000FF;">="opacity:0.2"</span><span style="color: #FF0000;"> filter</span><span style="color: #0000FF;">="url(#drop-shadow)"</span><span style="color: #0000FF;">/></span><span style="color: #000000;"><br> </span><span style="color: #0000FF;"><</span><span style="color: #800000;">rect </span><span style="color: #FF0000;">width</span><span style="color: #0000FF;">="400px"</span><span style="color: #FF0000;"> height</span><span style="color: #0000FF;">="300px"</span><span style="color: #FF0000;"> rx</span><span style="color: #0000FF;">="5"</span><span style="color: #FF0000;"> fill</span><span style="color: #0000FF;">="#68DFFB"</span><span style="color: #FF0000;"> style</span><span style="color: #0000FF;">="opacity:0.8"</span><span style="color: #FF0000;"> </span><span style="color: #0000FF;">/></span><span style="color: #000000;"><br></span><span style="color: #0000FF;"></</span><span style="color: #800000;">svg</span><span style="color: #0000FF;">></span></pre> </div> <br> |
接着下来就是绑定事件了,字符串拼接有一个不好处,要获取刚刚生成的DOM对象的引用比较麻烦。不过我打算利用事件代理就另当别论了,因为我们手头上最明确的对象就是那个DIV元素,我们把所有事件都绑定在它上面就是了。这个留在下次说。