一、 讨论范围:
基于web网页、浏览器限于IE。
二、 引子:
我们团队在做项目的过程中,碰到不同情况的打印需求;我这里把打印需求分成四种。
1)、复杂的报表打印,需要做套打。
2)、最简单的网页内容打印。
3)、简单设置后的网页内容打印。
4)、简单设置后(包括横向、纵向)自动设置后的网页内容打印。
之所以把3和4分开,是因为这两者研究的过程中两者看似小的差别,但技术实现上还是有不一样的地方,我们团队在项目过程中刚好碰到了第4种需求,进行一翻技术研究后,发觉第4种需求技术解决方案着实让人烦恼。但是再进一步在用户体验的角度来看,第4种和第3种虽说都能实现,但体验差不多一样糟糕。因此最终的折衷方案适合于第3、4种需求。
这里先对前两种需求的技术选型做出简单说明,然后再进一步讨论第3、4种需求及我们的折衷方案。
1)复杂的报表打印,需要做套打 |
开发ActiveX控件;或者使用开源;或者购买商用控件。我们团队使用的是自己开发的ActiveX控件。 |
2)最简单的网页内容打印 |
使用IE自带的打印,或者简单的使用js调用 Webbrowser |
三、 展开讨论--web页面设置
在ie浏览器->打印->页面设置界面,可以看到有以下元素可以设置:
1)纸张大小
2)纵向/横向
3)打印背景颜色和图像
4)启用缩小字体填充
5)页眉
6)页脚
7)左边距
8)右边距
9)上边距
10)下边距
11)字体大小
在设置并保存后,退出ie后,再次进入界面会发现纵向/横向和纸张大小这两个保存会丢掉,其他的都能保存住上次设置的状态。或许因为纵向/横向和纸张大小在打印设置那里还可以设置,所以这个值就没有被存入注册表。来看一下注册表
HKEY_CURRENT_USER/SOFTWARE/Microsoft/Internet Explorer/PageSetup,可以看到以下键值(中文作者加上)
font(字体大小)
footer(页脚)
header(页眉)
margin_bottom(下边距)
margin_left(左边距)
margin_right(右边距)
margin_top(下边距)
Print_Background(打印背景颜色和图像)
Shrink_To_Fit(启用缩小字体填充)。
通过页面设置和注册表对比,可以很清楚看到纸张大小和纵向/横向不被存入注册表。因此就有了引子里讲到的第3和第4种需求的区别,第3种需求是指不设置纸张大小和纵向/横向设置。第4种需求则多了这两项。
四、如何修改页面设置注册表
基于第3种需求,主要是修改注册表,javascript代码如下:
<script type="text/javascript"> var hkey_root,hkey_path,hkey_key hkey_root="HKEY_CURRENT_USER"; hkey_path="\\Software\\Microsoft\\Internet Explorer\\PageSetup\\"; //这个是用来设置打印页眉页脚的,你可以设置为空或者其它 try{ var RegWsh = new ActiveXObject("WScript.Shell"); hkey_key="header"; RegWsh.RegWrite(hkey_root+hkey_path+hkey_key,""); hkey_key="footer"; RegWsh.RegWrite(hkey_root+hkey_path+hkey_key,""); }catch(e){ alert(e.description); } </script>
五、 如何修改页面设置纵向/横向及纸张大小
能否不通过第三方的activeX,直接利用javascript直接修改这两个属性呢?在网上折腾了两天后,只找到一种办法,还是使用WScript.Shell,代码例子如下
<script type="text/javascript"> try{ var RegWsh = new ActiveXObject("WScript.Shell"); RegWsh.sendKeys('%fu');//按下Alt+F+U键 RegWsh.sendKeys('%a');//按下了ALT+A键 RegWsh.sendKeys('{ENTER}');//按下Enter键 }catch(e){ alert(e.description); } </script>
在执行时,可以看到有弹出页面设置的界面然后保存关闭的过程。
如果大家有其他体验更好的解决方案,希望能补充。
六、用户体验带来的烦恼
1、以上不管是哪种方案,都会提示用户安全上的确认,如果我们的ActiveX是通过官方认证的,相对来说安全级别是较高的,大部分用户是能接受的。
2、而第四、五点的实现在一般用户的安全设置情况下,会报出错误提示”automation服务器不能创建对象”。
客户端可以通过以下三种办法排查:
1)、如果是Scripting.FileSystemObject (FSO 文本文件读写)被关闭了, 开启FSO功能即可,在“运行”中执行regsvr32 scrrun.dll即可。
2)、安全模式设置成“中”,如果javascript脚本中报这个错误,还应将IE的安全设置“不允许运行未标记为安全的activeX控件”启用即可。注意如果您将相应的网站设成“受信任的站点”, 必须对“受信任的站点”进行相应的IE安全设置,此时如果对“Internet”IE设置将是徒劳的。
3)、有些脚本需要微软的 MSXML 控件才能进入。当使用 IE 5 以上版本的缺省安全模式时,会提示是否接受 MSXML 控件, 如果接受,MSXML 将自动安装到您的机器上(得等上几分钟)。 如果自动安装不成功,可以自行下载和安装 MSXML 3.0 SP7。有时是由于msxml 3服务被关掉了,使用regsvr32 msxml3.dll即可。
但是这样的体验无疑是用户无法忍受的,除非你的系统是后台内部少数人使用的场景,即便客户端的设置不弹出错误提示”automation服务器不能创建对象”,但第五点的实现会看到打开页面时,自动弹出页面设置窗口并自动关闭的过程,我想这样的体验也是用户所厌恶的。
七、令人不爽的折衷方案
讲了这么多,可能还没讲清楚我到底想要个什么样的打印需求,再次描述:我们想要一个简单的页面打印,比如某个网页上有个打印按钮,然后点击打印,能自动设置好纸张大小、纵向/横向及其他页面设置元素,并直接打印出页面上某个对象(其他不打印的对象可以通过css或js控制不被打印出来)。
令人遗憾的是,通过以上的阐述,通过Javascript和WScript.Shell直接实现的方式,用户体验太差。放弃!
折衷方案一、降低需求标准,通过javascript调用Webbrowser弹出打印设置,让用户自行设置纵向/横向及其他设置后再打印。体验较差,我们在项目过程中,由于时间的原因,做为临时解决方案。
折衷方案二、采用ActiveX,一般第三方的打印控件比较大,而我们的第3、4种需求方案实际上非常简单,用不到一般商用的庞大复杂的报表功能,因此可以做个简单但够用的体积又很小的ActiveX控件是最好的解决方案。ActiveX控件,免不了客户端第一次打开时下载和信任确认问题,这是ActiveX都无法避免的问题,但这种方案完全满足了用户的需求,但ActiveX开发需要的时间多,正式签名等过程复杂。我们将在下个sprint中考虑采用ActiveX。
八、发文目的
因为花了我2天多时间,本想通过javascript来实现本文中简单的自动打印设置并打印(即本文所提到的第3、4种需求),结果引出了这一系列技术问题及用户体验问题,如果大家有更好的解决方案,请予以分享。如果有碰到我同样需求又需要做出技术选型的朋友,希望本文能让你有所参考少走弯路。
--董柏 于2011.11.15中午