网页打印,可以通过浏览器的"打印"功能实现,但"打印模板"机制,却是 ie 5.5 /6.0以及 netscape 6.0 所独有的;准确一点, ie 5.5 只是一个机制雏形,在 ie 6.0 中才得以完全体现。ie 6.0的打印功能模块,在精确控制页面边界,文本间隔,以及打印的统一性上,功能更为完备。
通过创建打印模板,你可以精确控制:
网页打印及预览时的页面风格与内容编排风格;打印属性,如自动为打印的页面添加卷标或编号;精确控制打印预览界面的各个元素与变量。
通过打印模板,你可以:
自动为所有打印页面添加固定内容,如公司标识,版权申明,或者指定广告;自定义页面标头与尾注等元素,比如页码或卷标;指定打印历史与任务;书本化奇偶分页映射打印……
打印模板机制是建立在动态 html 语言基础上的,涉及到主要两个行为:devicerect,layoutrect ,下面我们就这两个行为深入地探讨 ie 6.0 的打印机制。
另外需要说明的是,dhtml(动态超文本标识语言)的行为跟其他语言的"行为"一样,都是一种应用编程接口,初始状态下有自己的默认属性,在一定的事件下,由用户决定调用其承认的功能模块,从而产生相对应的"行为"。而且,"行为"可以自己编写,不过得以".htc"为其扩展名以供调用。
一.devicerect ,定义打印总体风格:
打印总体风格,包括为打印页面添加如公司标识的固定内容(网页上不一定有,只体现在打印纸张上或预览页面上,后同);打印页面的颜色风格;打印页面的边缘属性或图案;等等。
在进行 devicerect 引用前,先得确定页面风格,方法是用<style>进行设置。
例一:我们来定制如下的打印模板
8.5 inch 宽
11 inch 高
黄色背景
1 pixel 宽的黑色实心左边界
1 pixel 宽的黑色实心上边界
4 pixels 宽的黑色实心右边界
4 pixels 宽的黑色实心下边界
所有边界与纸张边缘为 10 pixels 的距离
现在我们用 style 进行设定,假设这个 style 名为 mystyle1:
<style type="text/css">
.mystyle1
{
width:8.5in;
height:11in;
background:#ffff99;
border-left:1 solid black;
border-top:1 solid black;
border-right:4 solid black;
border-bottom:4 solid black;
margin:10px;
}
</style>
下面我们给出 devicerect 引用的完全页面代码
<html xmlns:ie>
<head>
<?import namespace="ie" implementation="#default">
<style type="text/css">
.mystyle1
{
width:8.5in;
height:11in;
background:#ffff99;
border-left:1 solid black;
border-top:1 solid black;
border-right:4 solid black;
border-bottom:4 solid black;
margin:10px;
}
</style>
</head>
<body>
<ie:devicerect id="page1" class="mystyle1" media="print">
</ie:devicerect>
<ie:devicerect id="page2" class="mystyle1" media="print">
</ie:devicerect>
</body>
</html>
在这个页面中,共进行了两个 devicerect引用。作为一种规则,每一个单独的打印页面,必须有一个相对应的 devicerect 标记,如果有1000 个页面,那就得有 1000 个 devicerect标记!吓住了?别担心,后面我们会教你一个方法,让所有的 devicerect 标记自动完成!
在上面的代码中,id 是标志属性,不同的页面必须有自己不同的标识;class 引用了 style 属性;media属性则指明了本页面的最终用途是进行打印;<?import namespace="ie"implementation="#default">这句话则是指输入默认的行为,它们分别是 devicerect,layoutrect。
二.layoutrect ,定义页面内容风格:
跟 devicerect 一样,不同的页面,要进行layoutrect 引用时都需要添加 layoutrect 标记,其智能添加方法将在后面介绍; layoutrect 与devicerect 如果在同一个页面中同时出现,则前者需放在后者之内;另外,layoutrect 对内容风格的设定,也通过 style 得以实现。
例二:我们来定制如下的内容风格的打印模板
5.5 inches 宽
8 inches 高
与打印纸张边缘,四边保持 1 inch 的宽度(加上页面本身的边缘宽度,为实际的打印边缘宽度)
白色背景
1 inch 宽的虚线边界
先定制名为 contentstyle 的风格:
<style type="text/css">
.contentstyle
{
width:5.5in;
height:8in;
margin:1in;
background:white;
border:1 dashed gray;
}
</style>
然后下面是进行引用的完整网页代码:
<html>
<head>
<?import namespace="ie" implementation="#default">
<style type="text/css">
.contentstyle
{
width:5.5in;
height:8in;
margin:1in;
background:white;
border:1 dashed gray;
}
</style>
</head>
<body>
<ie:layoutrect id="layoutrect1" contentsrc="2.html" class="contentstyle" nextrect="layoutrect2"/>
<ie:layoutrect id="layoutrect2" class="contentstyle"/>
</body>
</html>
跟例一中的源代码相比,例二中只是以 layoutrect 代替了原来的devicerect 标记;devicerect定制的是模板整体风格,而 layoutrect 定制的是具体内容的版面风格;layoutrect的 id 属性也具有唯一性; contentsrc 属性则指明了具体的将起作用网页文件;class 指明了风格的引用对象;跟devicerect 不同,在进行 layoutrect引用时,必须在每个页面指定 nextrec ,即依次排列的下一个内容风格,这里的"下一个内容"用其页面的相应 id 进行标识,如本例中的 layoutrect2。
三.devicerect 与 layoutrect 的协同作战:
上面我们分别讨论了 devicerect 与layoutrect 的作用与引用方法,现在我们来看一下,如何在同一个打印模板中进行定制与引用。
在每一个打印模板上,必然包含两方面的内容,一个是整体的模板风格(devicerect),另一个是内容风格(layoutrect);第一个打印页面跟其他页面是不同的,因为第一个页面中必须指明contentsrc 属性,而同一打印任务中的其他页面不再需要进行 contentsrc 的指定。
例三:
下面是第一个页面中的 devicerect 代码:
<ie:devicerect id="page1" class="masterstyle"media="print">
<ie:layoutrect id="layoutrect1" contentsrc="2.html" class="contentstyle"nextrect="layoutrect2"/>
</ie:devicerect>
下面是其他页面中的 devicerect 代码:
<ie:devicerect id="page2" class="masterstyle" media="print">
<ie:layoutrect id="layoutrect2" class="contentstyle"/>
</ie:devicerect>
下面我们将 devicerect 与 layoutrect结合起来使用其源代码如下:
<html xmlns:ie>
<head>
<?import namespace="ie" implementation="#default">
<style type="text/css">
.contentstyle
{
width:5.5in;
height:8in;
margin:1in;
background:white;
border:1 dashed gray;
}
.mystyle1
{
width:8.5in;
height:11in;
background:#ffff99;
border-left:1 solid black;
border-top:1 solid black;
border-right:4 solid black;
border-bottom:4 solid black;
margin:10px;
}
</style>
</head>
<body>
<ie:devicerect id="page1" class="mystyle1" media="print">
<ie:layoutrect id="layoutrect1" contentsrc="2.html" class="contentstyle"nextrect="layoutrect2"/>
</ie:devicerect>
<ie:devicerect id="page2" class="mystyle1" media="print">
<ie:layoutrect id="layoutrect2" class="contentstyle"/>
</ie:devicerect>
</body>
</html>
四.devicerect 与 layoutrect 标记的动态自动添加:
前面我们说到,每个单独的打印页面都需要各自的 devicerect 与layoutrect 标记,那么,如果我们有 1000 个页面需要打印,是否就要在每个页面上重复繁琐的copy & paste 操作?
答案是否定的,我们完全可以通过 javascript 脚本来完成这一繁琐的工作。
要实现 html 声明的动态创建,关键在于 <div> 标记的定义,下面是其定义规则。
<div id="devicecontainer">
……
</div>
<div>与</div>之间,采用 insertadjacenthtml() 方式,并主要利用了其 afterbegin 与 beforeend两个变量,现在我们将第一个页面"插入"到<div></div>之间:
devicecontainer.insertadjacenthtml("afterbegin", newhtml);
具有继承属性的后续页面,调用 beforeend 变量:
devicecontainer.insertadjacenthtml("beforeend", newhtml);
要装载 devicecontainer 页面,还需在 <body>中添加:
<body onload="addfirstpage()">
现在我们在 javascript 中添加包含前面详细介绍的 layoutrect 与devicerect 元素,用到的命令是 addfirstpage() 。需要注意的是,newhtml标记后使用的是双引号,而 layoutrect 与 devicerect 标记后的变量使用单引号。如下:
function addfirstpage() {
newhtml = "<ie:devicerect id=devicerect1 media=print class=mystyle1>";
newhtml += "<ie:layoutrect id=layoutrect1 contentsrc=2.html" + "onlayoutcomplete=onpagecomplete()nextrect=layoutrect2" + "class=contentstyle/>";
newhtml += "</ie:devicerect>";
devicecontainer.insertadjacenthtml("afterbegin", newhtml);
}
细心的读者一定会发现,layoutrect后出现了一个新的属性:layoutrect:onlayoutcomplete ,这个属性主要指定了 layoutrect 停止响应的后续事件,如系统资源消耗殆尽而停止响应,或者 layoutrect指定的变量溢出。
好了,有了上面的原理,下面我们来编写具有自动"插入"功能的 javascript 代码:
function onpagecomplete() {
if (event.contentoverflow) {
newhtml = "<ie:devicerect id=devicerect" + (lastpage + 1) + "media=print class=mystyle1>";
newhtml += "<ie:layoutrect id=layoutrect" + (lastpage + 1) + "onlayoutcomplete=onpagecomplete() nextrect=layoutrect" + (lastpage + 2) +" class=contentstyle/>";
newhtml += "</ie:devicerect>";
devicecontainer.insertadjacenthtml("beforeend", newhtml);
lastpage++;
}
在上面的代码中,contentoverflow 代表的是由于页面信息过长,本页的 layoutrect停止响应,则直接跳到下一个页面,让 layoutrect 重新定义下一个页面的版面;onpagecomplete()则不管页面是否过长,layoutrect是否停止响应,只要到了页面尾部则自动跳到下一页,这也是最常见的情况。
在编写本脚本时,关键处在于保持清醒,不能让任意一个变量出错。其中,id 不仅针对 devicerect与 layoutrect ,还为 nextrect 所引用,页面指向不能出错;当前页面的页码应该是lastpage+1 ,下一个页面的页码应该是 lastpage+2 ;nextrect 标记需要下一个页面的 layoutrect 属性支持,因此它的值应该为 "layoutrect"+(lastpage+2);打开第一个页面时,这个 lastpage初始值为 1 。
