博客代码运行框 开发实录

在博客园写博客,贴得出代码却看不到效果,需要用户复制到本地文件去运行,这样的阅读体验很差,所以我决定开发一个代码运行框,进一步提升用户体验。


需要的控件有<textarea>和<button>

<textarea>:用于输入HTML代码

<button>:点击后弹出浮层,展现运行结果


这个运行框组件的HTML结构为:

<div id="code_box">
	<textarea></textarea>
	<button>运行</button>
</div>
<div id="layer">
	<div id="layer_bg"></div>
	<div id="layer_content"></div>
</div>


其中layer是浮层,layer_bg用于实现半透明背景,真正的内容放在layer_content,这里涉及一个问题,就是确定layer_content的高宽和位置。

先来说高宽吧,我们点击button后,会把textarea的value取出来,因为是一段完整的HTML代码,即一个单独的页面,自然想到使用iframe,怎么用iframe呢?

var codeBox = document.getElementById('code_box'),
	textarea = codeBox.children[0],
	btn = codeBox.children[1],
	layer = document.getElementById('layer'),
	content = document.getElementById('layer_content');
	
btn.onclick = function(){
	runCode(textarea.value);
}
var runCode = function(htmlCode){
	var iframe = document.createElement('iframe'), win = null, doc = null;
	content.innerHTML = '';
	content.appendChild(iframe);//如果不加在这,iframe.contentDocument为空
	
	win = iframe.contentWindow || iframe.contentDocument.parentWindow;
	doc = iframe.contentWindow.document || iframe.contentDocument;
	
	doc.open();
	doc.write(htmlCode);
	doc.close();
	
	layer.style.display = 'block';//如果不加在这,IE10,FF获取不到iframe高度
	var h = doc.documentElement.scrollHeight || doc.body.scrollHeight,
		w = doc.documentElement.scrollWidth || doc.body.scrollWidth;

	iframe.style.width = w + 'px';
	iframe.style.height = h + 'px';
	
	var viewWidth = document.documentElement.clientWidth,
		viewHeight = document.documentElement.clientHeight;
	content.style.left = (viewWidth/2 - w/2) + 'px';
	content.style.top = (viewHeight/2 - h/2) + 'px';
}


可以看到我用了scrollXXX来获得高宽,其实我开始是想用clientXXX的,为啥不用了呢,我先把这两种属性的测试数据贴出来吧:

测试页面:www.baidu.com;测试时,浏览器控制台的高度保持不变,所有浏览器均出现垂直和水平滚动条
 

先来张chrome的测试图


先来看看clientXXX

documentElement.clientWidth 和 documentElement.clientHeight就是上图红框标注的区域,即文档可见区域


奇怪的是body.clientWidth 和 body.clientHeight

body.clientWidth == documentElement.clientWidth

body.clientHeight != document.Element.clientHeight


如果body.clientXXX表示的是body的可见区域,那么body.clientHeight说不通

如果body.clientXXX表示的是body实际的高宽,那么body.clientWidth说不通

我以为是百度首页写得不好,切到google.cn去看了下,结果一样的,这就奇怪了 ,希望大家能指点一下。

 
接着scrollXXX

documentElement.scrollWidth 和 documentElement.scrollHeight表示文档实际的高宽

body.scrollWidth 和 body.scrollWidth表示body元素实际的高宽,不出意外的话,基本都等于documentElement.scrollXXX,但还有例外

测试结果中,Firefox和Opera的  body.scrollWidth < documentElement.scrollWidth

现在我除了想骂街已经没有别的想法了。。。。

===============================================================

骂街归来继续写,好了,先小结一下,下面要用到的:

获得文档可见区域的宽度:document.documentElement.clientWidth

获得文档可见区域的高度:document.documentElement.clientHeight

获得文档实际的宽度:document.documentElement.scrollWidth

获得文档实际的高度:document.documentElement.scrollHeight


回到之前iframe高宽的问题,因为是动态写入数据,高宽都未知,自然是用scrollXXX比较好,因为最大也就它了。


确定了高宽,再来看看定位的问题,为了美观,#layer_content必须水平垂直居中对齐,下面用js实现定位:
 

var viewWidth = document.documentElement.clientWidth,
	viewHeight = document.documentElement.clientHeight;
content.style.left = (viewWidth/2 - w/2) + 'px';
content.style.top = (viewHeight/2 - h/2) + 'px';


核心功能都解释完了,下面开始收尾,还剩这几个需求:

1. 关闭按钮

2. 一个页面可能有多个运行框,所以需要调整HTML代码

3. 浮层的淡入淡出效果(这个我不贴代码,一帖又是超长的)

4. 代码运行框可能位于任何地方,所以弹出浮层时,它的top值需要设置

5. 如果有垂直滚动条,弹出浮层后需要禁用


下面给出最终版,这里就不让大家运行了,因为浮层上弹浮层是很蛋疼的一件事。

<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
	<style type="text/css">
		html, body,
		#layer, #layer_bg {
			width:100%;
			height:100%;
		}
		#layer, #layer_content {
			position:absolute;
			left:0;
			top:0;
		}
		
		html, body {
			margin:0;
			padding:0;
		}
		body {
			height:10000px;
		}
		#layer {
			display:none;
		}
		#layer_bg {
			background:#000;
			opacity:0.8;
		}
		#layer_content {
			background:#fff;
			padding:10px;
		}
		#close_btn {
			color:#fff;
			cursor:pointer;
			
			position:absolute;
			right:-5px;
			top:-10px;
		}
	</style>
	
	<script type="text/javascript">
		var layer = null, content = null, closeBtn = null, iframeDiv = null;
	
		window.onload = function(){
			layer = document.getElementById('layer');
			content = document.getElementById('layer_content');
			closeBtn = document.getElementById('close_btn');
			iframeDiv = document.getElementById('layer_iframe');
			
			closeBtn.onclick = function(){
				layer.style.display = '';
				document.body.style.overflow = '';
			};
		}
		var runCode = function(btn){
			var code = btn.previousSibling.value;
			if(code){
				document.body.style.overflow = 'hidden';//禁用滚动条,测试发现body通吃, 而documentElement在FF是个悲剧,求正解!!!
				layer.style.top = (document.documentElement.scrollTop || document.body.scrollTop) + 'px';
				showResult(code);
			}else{
				window.alert('请先输入代码!');
			}
		};
		var showResult = function(htmlCode){
			var iframe = document.createElement('iframe'), win = null, doc = null;
			iframe.frameBorder = 0;//把那个难看的边框去了

			iframeDiv.innerHTML = '';
			iframeDiv.appendChild(iframe);//如果不加在这,iframe.contentDocument为空
			
			win = iframe.contentWindow || iframe.contentDocument.parentWindow;
			doc = iframe.contentWindow.document || iframe.contentDocument;
			
			doc.open();
			doc.write(htmlCode);
			doc.close();
			
			layer.style.display = 'block';//如果不加在这,IE10,FF获取不到iframe高度
			var h = doc.documentElement.scrollHeight || doc.body.scrollHeight,
				w = doc.documentElement.scrollWidth || doc.body.scrollWidth;

			iframe.style.width = w + 'px';
			iframe.style.height = h + 'px';
			
			var viewWidth = document.documentElement.clientWidth,
				viewHeight = document.documentElement.clientHeight;
			content.style.left = (viewWidth/2 - w/2) + 'px';
			content.style.top = (viewHeight/2 - h/2) + 'px';
		}
	</script>
</head>
<body>
	<!-- 这个div整个页面可以有多个 -->
	<div>
		<!-- 写成一行是为了button.previousSibling可以获得textarea-->
		<textarea></textarea><button onclick="runCode(this)">运行</button>
	</div>
	
	<!-- 这个div整个页面只有一个 -->
	<div id="layer">
		<div id="layer_bg"></div>
		<div id="layer_content">
			<span id="close_btn">X</span>
			<div id="layer_iframe">
			
			</div>
		</div>
	</div>
</body>
</html>

  

posted @ 2011-10-19 15:03  越己  阅读(590)  评论(0编辑  收藏  举报