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

  上部分已给出主要辅助方法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(
'
'+this.title+'
');
builder.push(
'
'); builder.push('
'); builder.push('取消'); builder.push('确认'); builder.push('
');
builder.push(
'');
container.innerHTML
= builder.join('');
}
}

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

<!doctype html> <title>一步步教你实现弹出窗口 by 司徒正美</title> <meta charset=”utf-8″/> <meta name=”keywords” content=”一步步教你实现弹出窗口 by 司徒正美” /> <meta name=”description” content=”一步步教你实现弹出窗口 by 司徒正美” /> <mce:script type=”text/javascript”><!– var Dialog = function(){ var options = arguments[0] || {}; this.title = options.title || “新窗口”, this.width = options.width || 400, this.height = options.height || 300, this.container = document.createElement(“div”), this.id = “id” + (( new Date() * Math.random()) >> 0); this.init(); } Dialog.prototype = { constructor: Dialog, init: function() { var container = this.container,width = this.width, height = this.height, id = this.id,builder = [],t = “getElementsByTagName”,d = document, bg = function(pic){ var bgcolor = arguments[1] || ‘transparent’, left = arguments[2] || ‘left’, s = ‘background:’+bgcolor + ‘ url(http://images.cnblogs.com/cnblogs_com/rubylouvre/205314/’ + pic + ‘) no-repeat ‘+left+’ center;’; return s; }; d.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)” mce_href=”javascript:void(0)”>取消</a>’); builder.push(‘<a class=”positive” href=”javascript:void(0)” mce_href=”javascript:void(0)”>确认</a>’); builder.push(‘</div></form>’); builder.push(‘<a class=”closebtn” href=”javascript:void(0)” mce_href=”javascript:void(0)”></a>’); container.innerHTML = builder.join(”); var size = this.getBrowserWindowSize(), left = (((size.width – width)/2) >> 0), top = (((size.height – height)/2) >> 0) ; //设置样式 this.css(“.popups”,”position:absolute;width:”+width+”px;height:”+ height+”px;left:”+left+”px;top:”+top+”px;background:#68DFFB”); this.css(“.popups .caption”,’position:absolute;top:10px;left:10px;width:’+ (width-50)+’px;height:20px;’+ ‘padding-left:30px;font:700 14px/20px “SimSun”,”Times New Roman”;color: #fff;’+ bg(“o_icon.gif”,”#68DFFB”,”5px”)); this.css(“.popups .closebtn”,’position:absolute;top:0;right:10px;display:block;width:28px; ‘+ ‘height:17px;text-decoration:none;’+ bg(“o_dialog_closebtn.gif”)); this.css(“.popups a.closebtn:hover”,bg(“o_dialog_closebtn_over.gif”)); this.css(“.popups form”, “position:absolute;top:30px;left:10px;border:3px solid #68DFFB;width:”+ (width-26)+”px;height:”+(height-51)+”px;background:#fff;”); this.css(“.popups .submitable”, “position:absolute;bottom:0;border-top:1px solid #c0c0c0;width:100%;height:40px;background:#f9f9f9;”); var buttoncss = ‘display:block;float:right;margin: 0.7em 0.5em;padding:2px 7px;border:1px solid #dedede;’ + ‘background:#f5f5f5;color:#a9ea00;font:700 12px/130% “SimSun”,”Times New Roman”;text-decoration:none;’; this.css(“a.positive”,buttoncss);//IE6有bug,不能动态创建联合选择器 this.css(“a.negative”,buttoncss); this.css(“a.negative”,”color:#ff5e00;”); this.css(“a.positive:hover”,”border:1px solid #E6EFC2;background:#E6EFC2;color:#529214;”); this.css(“a.negative:hover”,”border:1px solid #fbe3e4;background:#fbe3e4;color:#d12f19;”); this.css(“a.positive:active”,”border:1px solid #529214;background:#529214;color:#fff;”); this.css(“a.negative:active”,”border:1px solid #d12f19;background:#d12f19;color:#fff;”); this.css(“a”,”outline: 0;”); var ff = /a/[-1]==’a’; if(ff){ this.css(“a.positive”,”-moz-border-radius:4px;”); this.css(“a.negative”,”-moz-border-radius:4px;”); }else{ this.css(“a.positive”,”-webkit-border-radius:4px;”); this.css(“a.negative”,”-webkit-border-radius:4px;”); } }, getBrowserWindowSize :function(){ var de = document.documentElement; return { ‘width’: (de.clientWidth || document.body.clientWidth), ‘height’:(de.clientHeight || document.body.clientHeight) } }, createSVG : function(tag){ return document.createElementNS(“http://www.w3.org/2000/svg”,tag); }, attr: function(node,bag){ for(var i in bag){ if(bag.hasOwnProperty(i)) node.setAttribute(i,bag[i]) } }, css:function(selector,declaration){ if(typeof document.createStyleSheet === ‘undefined’) { document.createStyleSheet = (function() { function createStyleSheet() { var element = document.createElement(‘style’); element.type = ‘text/css’; document.getElementsByTagName(‘head’)[0].appendChild(element); var sheet = document.styleSheets[document.styleSheets.length – 1]; if(typeof sheet.addRule === ‘undefined’) sheet.addRule = function(selectorText, cssText, index) { if(typeof index === ‘undefined’) index = this.cssRules.length; this.insertRule(selectorText + ‘ {‘ + cssText + ‘}’, index); }; return sheet; } return createStyleSheet; })(); } if(!!Dialog.sheet){ if(!Dialog.memory.exists(selector,declaration)){ Dialog.memory.set(selector,declaration); Dialog.sheet.addRule(selector,declaration); } }else{ Dialog.sheet = document.createStyleSheet(); var memory = function(){ var keys = [],values = [],size = 0; return { get : function(k){ var results = []; for(var i=0,l=keys.length;i<l;i++){ if(keys[i] == k){ results.push(values[i]) } } return results; }, exists:function(k,v){ var vs = this.get(k); for(var i=0,l=vs.length;i<l;i++){ if(vs[i] == v) return true; } return false; }, set : function(k,v){ keys.push(k); values.push(v); size++; }, length :function(){ return size; } } } Dialog.memory = memory(); Dialog.memory.set(selector,declaration); Dialog.sheet.addRule(selector,declaration); } } }; window.onload = function(){ setTimeout(function(){ new Dialog({width:400,height:300,title:”司徒正美”}) },1000) } // –></mce:script> <h2 style=”text-align:center” mce_style=”text-align:center”>一步步教你实现弹出窗口 by 司徒正美</h2> <div id=”parent”></div><b id=”child” >样式规则</b> <pre> #navigation { -webkit-box-shadow: 0 0 10px #000; -moz-box-shadow: 0 0 10px #000; } #navigation li a:hover, #navigation li a:focus { -webkit-box-shadow: 0 0 5px #111; -moz-box-shadow: 0 0 5px #111; } box-shadow属性可以用多个值:水平偏移、垂直偏移、模糊半径、伸展半径和阴影颜色。水平和垂直偏移和阴影色使用的最多。 在一个div上应用红色阴影,右边和下边偏移4px,无模糊,我们可以使用下面的代码: div { -moz-box-shadow: 4px 4px 0 #f00; -webkit-box-shadow: 4px 4px 0 #f00; box-shadow: 4px 4px 0 #f00; } </pre> <button>测试</button> <div id=”multi”></div> <p>http://dev.opera.com/articles/view/svg-evolution-3-applying-polish/</p> <p>https://developer.mozilla.org/cn/Canvas_tutorial</p> <p>http://www.btinternet.com/~st_rise/main/mainfram.htm?../webplus/vml/vfill.htm</p> http://www.svgbasics.com/filters3.html

运行代码

  接着看如何实现圆角与半透明效果与盒阴影。如果不考虑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>

<!doctype html> <title>一步步教你实现弹出窗口 by 司徒正美</title> <meta charset=”utf-8″/> <meta name=”keywords” content=”一步步教你实现弹出窗口 by 司徒正美” /> <meta name=”description” content=”一步步教你实现弹出窗口 by 司徒正美” /> <mce:script type=”text/javascript”><!– var Dialog = function(){ var options = arguments[0] || {}; this.title = options.title || “新窗口”, this.width = options.width || 400, this.height = options.height || 300, this.container = document.createElement(“div”), this.id = “id” + (( new Date() * Math.random()) >> 0); this.init(); } Dialog.prototype = { constructor: Dialog, init: function() { var container = this.container,width = this.width, height = this.height, id = this.id,builder = [],t = “getElementsByTagName”,d = document, bg = function(pic){ var bgcolor = arguments[1] || ‘transparent’, left = arguments[2] || ‘left’, s = ‘background:’+bgcolor + ‘ url(http://images.cnblogs.com/cnblogs_com/rubylouvre/205314/’ + pic + ‘) no-repeat ‘+left+’ center;’; return s; }; d.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)” mce_href=”javascript:void(0)”>取消</a>’); builder.push(‘<a class=”positive” href=”javascript:void(0)” mce_href=”javascript:void(0)”>确认</a>’); builder.push(‘</div></form>’); builder.push(‘<a class=”closebtn” href=”javascript:void(0)” mce_href=”javascript:void(0)”></a>’); container.innerHTML = builder.join(”); var size = this.getBrowserWindowSize(), left = ((size.width – width)/2) >> 0, top = ((size.height – height)/2) >> 0 ; //设置样式 this.css(“.popups”,”position:absolute;width:”+ width+”px;height:”+height+”px;left:”+left+”px;top:”+top+”px;”); this.css(“.popups .caption”,’position:absolute;top:10px;left:10px;width:’ +(width-50)+’px;height:20px;’+ ‘padding-left:30px;font:700 14px/20px “SimSun”,”Times New Roman”;color: #fff;’+ bg(“o_icon.gif”,”#68DFFB”,”5px”)); this.css(“.popups .closebtn”,’position:absolute;top:0;right:10px;display:block;width:28px; ‘+ ‘height:17px;text-decoration:none;’+ bg(“o_dialog_closebtn.gif”)); this.css(“.popups a.closebtn:hover”,bg(“o_dialog_closebtn_over.gif”)); this.css(“.popups form”, “position:absolute;top:30px;left:10px;border:3px solid #68DFFB;width:”+ (width-26)+”px;height:”+(height-51)+”px;background:#fff;”); this.css(“.popups .submitable”, “position:absolute;bottom:0;border-top:1px solid #c0c0c0;width:100%;height:40px;background:#f9f9f9;”); var buttoncss = ‘display:block;float:right;margin: 0.7em 0.5em;padding:2px 7px;border:1px solid #dedede;’ + ‘background:#f5f5f5;color:#a9ea00;font:700 12px/130% “SimSun”,”Times New Roman”;text-decoration:none;’; this.css(“a.positive”,buttoncss);//IE6有bug,不能动态创建联合选择器 this.css(“a.negative”,buttoncss); this.css(“a.negative”,”color:#ff5e00;”); this.css(“a.positive:hover”,”border:1px solid #E6EFC2;background:#E6EFC2;color:#529214;”); this.css(“a.negative:hover”,”border:1px solid #fbe3e4;background:#fbe3e4;color:#d12f19;”); this.css(“a.positive:active”,”border:1px solid #529214;background:#529214;color:#fff;”); this.css(“a.negative:active”,”border:1px solid #d12f19;background:#d12f19;color:#fff;”); this.css(“a”,”outline: 0;”); var ff = /a/[-1]==’a’; if(ff){ this.css(“a.positive”,”-moz-border-radius:4px;”); this.css(“a.negative”,”-moz-border-radius:4px;”); }else{ this.css(“a.positive”,”-webkit-border-radius:4px;”); this.css(“a.negative”,”-webkit-border-radius:4px;”); } if (!+”\v1″ ){ if(!document.namespaces.vml){ document.namespaces.add(‘vml’, ‘urn:schemas-microsoft-com:vml’); var vmlobj = document.createElement(“<span class=”mceItemObject” classid=CLSID:10072CEC-8CC1-11D1-986E-00A0C955B42E id=VMLRender>”), head = document.getElementsByTagName(“head”)[0]; head.appendChild(vmlobj); document.createStyleSheet().addRule(“.vml”, “behavior: url(#VMLRender); display:inline-block;”); } var rect = document.createElement(‘<vml:roundrect class=”vml”>’); container.insertBefore(rect,container.firstChild); rect.style.cssText = “position:absolute;top:0px;left:0px;width:”+width+”px;height:”+height+”px;”; this.attr(rect,{arcsize:5 /Math.min(width, height),stroked:”f”}); rect.innerHTML = ‘<vml:fill class=”vml” opacity=”0.8″ color=”#68DFFB” />’ + ‘<vml:shadow class=”vml” on=”t” color=”#333″ opacity=”0.2″ offset=”10px,10px” />’ }else{ var svg = this.createSVG(“svg”); container.insertBefore(svg,container.firstChild); this.attr(svg,{width:width+10+”px”,height:height+10+”px”}); var defs = this.createSVG(“defs”); svg.appendChild(defs); var filter = this.createSVG(“filter”); defs.appendChild(filter); this.attr(filter,{id:”filter”+id}); var feGaussianBlur = this.createSVG(“feGaussianBlur”); filter.appendChild(feGaussianBlur) this.attr(feGaussianBlur,{“in”:”SourceAlpha”,result:”blur-out”, stdDeviation:1.5}); var feOffset = this.createSVG(“feOffset”); filter.appendChild(feOffset) this.attr(feOffset,{“in”:”blur-out”,result:”the-shadow”,dx:0,dy:2}); var feBlend = this.createSVG(“feBlend”); filter.appendChild(feBlend) this.attr(feBlend,{“in”:”SourceGraphic”,”in2″:”the-shadow”, mode:”normal”}); var shadow = this.createSVG(“rect”); svg.appendChild(shadow); this.attr(shadow,{x:”10px”,y:”10px”,width:width+”px”,height:height+”px”, rx:10, fill:”#333″,style:”opacity:0.2″,filter:”url(#filter”+id+”)”}); var rect = this.createSVG(“rect”); svg.appendChild(rect); this.attr(rect,{width:width+”px”,height:height+”px”,rx:5, fill:”#68DFFB”,style:”opacity:0.8″}); } }, getBrowserWindowSize :function(){ var de = document.documentElement; return { ‘width’: (de.clientWidth || document.body.clientWidth), ‘height’:(de.clientHeight || document.body.clientHeight) } }, createSVG : function(tag){ return document.createElementNS(“http://www.w3.org/2000/svg”,tag); }, attr: function(node,bag){ for(var i in bag){ if(bag.hasOwnProperty(i)) node.setAttribute(i,bag[i]) } }, css:function(selector,declaration){ if(typeof document.createStyleSheet === ‘undefined’) { document.createStyleSheet = (function() { function createStyleSheet() { var element = document.createElement(‘style’); element.type = ‘text/css’; document.getElementsByTagName(‘head’)[0].appendChild(element); var sheet = document.styleSheets[document.styleSheets.length – 1]; if(typeof sheet.addRule === ‘undefined’) sheet.addRule = function(selectorText, cssText, index) { if(typeof index === ‘undefined’) index = this.cssRules.length; this.insertRule(selectorText + ‘ {‘ + cssText + ‘}’, index); }; return sheet; } return createStyleSheet; })(); } if(!!Dialog.sheet){ if(!Dialog.memory.exists(selector,declaration)){ Dialog.memory.set(selector,declaration); Dialog.sheet.addRule(selector,declaration); } }else{ Dialog.sheet = document.createStyleSheet(); var memory = function(){ var keys = [],values = [],size = 0; return { get : function(k){ var results = []; for(var i=0,l=keys.length;i<l;i++){ if(keys[i] == k){ results.push(values[i]) } } return results; }, exists:function(k,v){ var vs = this.get(k); for(var i=0,l=vs.length;i<l;i++){ if(vs[i] == v) return true; } return false; }, set : function(k,v){ keys.push(k); values.push(v); size++; }, length :function(){ return size; } } } Dialog.memory = memory(); Dialog.memory.set(selector,declaration); Dialog.sheet.addRule(selector,declaration); } } }; window.onload = function(){ setTimeout(function(){ new Dialog({width:400,height:300,title:”司徒正美”}) },1000) } // –></mce:script> <h2 style=”text-align:center” mce_style=”text-align:center”>一步步教你实现弹出窗口 by 司徒正美</h2> <div id=”parent”></div><b id=”child” >样式规则</b> <pre> #navigation { -webkit-box-shadow: 0 0 10px #000; -moz-box-shadow: 0 0 10px #000; } #navigation li a:hover, #navigation li a:focus { -webkit-box-shadow: 0 0 5px #111; -moz-box-shadow: 0 0 5px #111; } box-shadow属性可以用多个值:水平偏移、垂直偏移、模糊半径、伸展半径和阴影颜色。水平和垂直偏移和阴影色使用的最多。 在一个div上应用红色阴影,右边和下边偏移4px,无模糊,我们可以使用下面的代码: div { -moz-box-shadow: 4px 4px 0 #f00; -webkit-box-shadow: 4px 4px 0 #f00; box-shadow: 4px 4px 0 #f00; } </pre> <button>测试</button> <div id=”multi”></div> <p>http://dev.opera.com/articles/view/svg-evolution-3-applying-polish/</p> <p>https://developer.mozilla.org/cn/Canvas_tutorial</p> <p>http://www.btinternet.com/~st_rise/main/mainfram.htm?../webplus/vml/vfill.htm</p> http://www.svgbasics.com/filters3.html

运行代码

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

千百度
© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容