HTML分页打印实现

最近在开发的过程中遇到的一个一次性打印多张单据的需求,我们的单据的长度是不确定的,如果直接打印页面的话一个单据有可能会被“腰斩”打印在两张纸上。这个需求让我联想起了以前写论文的时候,在Word里面添加分页符,这样不管上面一章的内容的长度怎么变化,下面一章的内容永远都是顶到页眉的。Word的本质实际上是所见即所得的网页,它的底层就是HTML代码,所以HTML也应该有方法可以实现类似的功能。
以下是实现的方法,也非常简单:
// 循环体开始
<div class="print-main" style="page-break-after:always;">
页面内容
</div>
// 循环体结束

使用Underscore.js的template将Backbone.js的js代码和html代码分离

这段时间在学习Require.js和Backbone.js的过程中,发现有些项目里的HTML代码都是写在View的js代码里面的,渲染的时候需要对Collection进行循环,再将HTML代码拼接上去,这似乎不是一件非常好的事情,因为将js代码和html代码融合到一起会增加代码的维护难度,而且这个过程中考虑到性能的因素,需要将HTML代码放到一个数组中,最后进行拼接,代码写起来比较麻烦。我看到他们的代码之后就在考虑是否有一种类似php模板引擎的东西可以将Collection传递进去然后渲染。

我查阅了Backbone.js的手册http://backbonejs.org/#View-template ,里面有一段文字:

However, we suggest choosing a nice JavaScript templating library. Mustache.js, Haml-js, and Eco are all fine alternatives. Because Underscore.js is already on the page, _.template is available, and is an excellent choice if you prefer simple interpolated-JavaScript style templates.

Whatever templating strategy you end up with, it’s nice if you never have to put strings of HTML in your JavaScript.

它建议我们使用js的模板库,而刚好Backbone.js强依赖于Underscore.js所以Underscore.js已经被引入了,它提供了一个_.template方法,这个方法支持使用内嵌js代码的html模板代码,在js代码里没有出现HTML代码是一件非常nice的事情!这正符合了我们MVC的思想,前端的HTML代码也便于维护,要不然就真的成为意大利面条式代码了!

关于Underscore.js的template的说明在http://underscorejs.org/#template ,这里有教你怎么使用。

Template functions can both interpolate variables, using <%= … %>, as well as execute arbitrary JavaScript code, with <% … %>. If you wish to interpolate a value, and have it be HTML-escaped, use <%- … %>

上面这段文字告诉我们在这个模板的代码里面js内嵌代码的标签如何使用,接下来我举一个例子:

我们先建一个template,位于:template/album/index.html

<%
var title = 'My albums';
document.title = title;
%>
<h1><%= title %></h1>
<p>
    <a href="album-rest/add">Add new album</a>
</p>
<table class="table">
<thead>
    <tr>
        <th>Title</th>
        <th>Artist</th>
        <th> </th>
    </tr>
</thead>
<tbody id="album-list">
<% _.each(albums, function(album) { %>
<tr class="album-row">
    <td><%= album.get('title') %></td>
    <td><%= album.get('artist') %></td>
    <td>
        <a href="album-rest/edit/<%= album.get('id') %>">Edit</a>
        <a href="album-rest/delete/<%= album.get('id') %>">Delete</a>
    </td>
</tr>
<% }); %>
</tbody>
</table>

下面的这个代码片段是定义了一个Backbone的View,sync属性会去请求服务端获取获取所有album的数据,最后将数据存放到albumList这个Collection里面。随后执行render方法,在render里面this.template = _.template(AlbumTpl, albums);这句代码就是用来完成数据和模板混合的工作的,AlbumTpl来自template/album/index.html,另外必须要将Collection中的所有的model以数组的形式获取到赋给albums,除非你在模板里面又进行了对Collection的解析操作,否则不能只传入一个Collection,因为Underscore.js的template是无法识别Backbone.js的Collection的对象结构的。

define(["model/album", "collection/album-list", "text", 'text!template/album/index.html'], function(Album, AlbumList, text, AlbumTpl) {
	var IndexView = Backbone.View.extend({
		model : Album,
		initialize: function() {
		},
		sync : function (render) {
			var albumList = new AlbumList;
			var view = this;
			Backbone.sync('read', albumList, {
				success : function (result) {
					albumList.add(result.ret);
					view.collection = albumList;
					view.render();
				}
			});
		},
		render: function() {
			albumList = this.collection;
			albums = albumList.models;
			console.log(_.template(AlbumTpl, albums));
			this.template = _.template(AlbumTpl, albums);
			$("#page-wrapper").html(this.template);
		}
	});
	return IndexView;
});

通过上面的操作,就可以实现js代码和html代码分离了。

用来处理HTML页面弹出框的jQuery插件

最近站长Tony开发了一个jquery.pop.js插件,这是一个用来处理弹出框的jQuery插件,目的是为了兼容IE6浏览器,从此不用不用为了IE6写CSS hack了,现代浏览器的fix和absolute怎么写就怎么写,无需考虑IE6一样兼容。值得注意的是jquery版本要求是1.3到1.8,HTML声明请遵循W3C标准。

使用方法:

$('#loginBox').popup();
$('#loginBox').pophide();

以上是弹出框的弹出和隐藏。

$('#loginBox').popup({
filter : '#filter'
});
$('#loginBox').pophide({
filter : '#filter'
});

如果添加了参数filter,表示弹出的同时开启滤镜,关闭的时候关闭滤镜。filter传入的值和你想要填写的选择器的内容是一样的。

demo地址:http://www.tonitech.com/demo/jquery.pop.js

jquery.pop.js插件的代码如下:

//@charset "utf-8";
/**
 * jquery版本要求:1.3 ~ 1.8,HTML声明请遵循W3C标准
 * 用来处理弹出框的jQuery插件
 * 兼容IE6浏览器,从此您再也不用担心IE6的弹框
 * 不用写css hack,否则会出问题,现代浏览器怎么写就怎么写
 * @author wangzhiangtony@qq.com
 * @version 1.2
 * @date 2013-3-27 10:09:59
 */
(function($) {
    //弹出的窗口处于屏幕中间
    $.fn.popup = function(opts) {
        var defaults = {
            filter : ''
        };
        var options = $.extend(defaults, opts);

        if(defaults.filter != '') {
            var maskHeight = $('body').height();
            $(options.filter).css('height', maskHeight);
            $(options.filter).show();
        }
        var str = $(this);

        var pos = str.css('position');
        if(pos == 'fixed') {
            var top = ($(window).height() - str.height()) / 2;
            //fix兼容ie6
            if($.browser.msie && $.browser.version == "6.0") {
                str.css('position', 'absolute');
                var dom = str[0];
                $('body').css({
                    'background-image' : 'url(about:blank)',
                    'background-attachment' : 'fixed'
                });
                dom.style.setExpression('top', 'eval((document.documentElement.scrollTop)+' + top + ')');
            }
        } else {
            var top = $(window).scrollTop() + ($(window).height() - str.height()) / 2;
        }
        if(top > 0) {
            str.css('top', top);
        } else {
            str.css('top', 0);
        }

        var width = $(window).width();
        var left = (width - str.width()) / 2;
        if(left > 0) {
            str.css('left', left);
        } else {
            str.css('left', 0);
        }
        str.css('z-index', '1000');
        str.show();
    };

    $.fn.pophide = function(opts) {
        var defaults = {
            filter : ''
        };
        var options = $.extend(defaults, opts);

        if(defaults.filter != '') {
            $(options.filter).hide();
        }
        $(this).hide();
    };
})(jQuery);

demo下载地址:jquery.pop.js (503)

height:100%在IE里面不起作用的解决办法

在FF,CHROME等一些高级浏览器,左右布局的,父级高度都会自动匹配子级高的那一个,但是在IE6里面则是不一样的解析方式。

如果在IE6里面想height:100%,就必须从某个层级定高,或者自html,body{height:100%;}。

笔者是遇见了这样的问题,希望定位一个箭头,并且该箭头要垂直居中,这就意味着要top:50%;margin-top:-height/2;但是父级高度应该是100%。

这个时候通常有两种做法:

一、加一个空div

<div>
<div style="float:left;height:100%;">pointer</div>
<div></div>
<div style="float:left">
<div style="height:200px;"></div>
</div>
</div>

不行的话请用第二种

二、全部定高

html,body{
height:100%
}
<div style="height:100%">
<div style="float:left;height:100%;">pointer</div>
<div style="float:left">
<div style="height:200px;"></div>
</div>
</div>

CSS hack总结

1、源代码:

.hd_bg{ 
background:red; 
background:green\0; 
width:100%; 
height:90px
}

IE8和IE9显示的为绿色,其他的为红色,

所以属性后加“\0”只能被IE8和IE9识别

选择器hack:

2、源代码:

*html.color{
color:green;
background:url(../images/014304_btn_bg.gif) no-repeat; 
width:107px; 
height:37px
}

.color{
color:black
}

只有IE6的字体颜色改成绿色并显示背景图片。

所以* html只能被IE6识别。

3、源代码:

*:+html .color{
color: green;
background:url(../images/014304_btn_bg.gif) no-repeat; 
width:107px; 
height:37px
}

.color{
color:black
}

只有IE7显示字体颜色为绿色并显示背景图片。

所以*:first-child+html只能被IE7识别

4、源代码:

html>body .color{
color: green; 
background:url(../images/014304_btn_bg.gif) no-repeat; 
width:107px; 
height:37px
}

.color{
color:black
}

除了IE6,IE7~9和火狐的字体颜色都显示为绿色并显示背景图片,

所以html>body可以被除IE6以外的浏览器识别

5、源代码:

html>/**/body .color{
color: green; 
background:url(../images/014304_btn_bg.gif) no-repeat; 
width:107px; 
height:37px
}

.color{
color:black
}

只有IE8、IE9和火狐能显示绿色字体和图片

所以html>/**/body只能被IE8、IE9和火狐识别

6、源代码:

:root .color{
color: green; 
background:url(../images/014304_btn_bg.gif) no-repeat; 
width:107px; 
height:37px}

.color{
color:black
}

只有IE9和火狐显示了绿色字体和图片

所以:root可以被IE9和火狐识别

7、源代码:

@-moz-document url-prefix() {
.b{
color:#0F0; 
background:url(../images/014304_btn_bg.gif) no-repeat; 
width:107px; 
height:37px
}
}

只有火狐的字体颜色显示为绿色,并显示图片

所以@-moz-document url-prefix() {}只能被火狐识别

总结:

“*”可以被IE6和IE7识别。

“_”只能被IE6识别。“+”只能被IE7识别

IE6对于!important存在bug。(IE不识别!important)

属性后门加“\9”只能被IE浏览器识别。

所以属性后加“\0”只能被IE8和IE9识别

所以* html只能被IE6识别。

所以*:first-child+html只能被IE7识别

所以html>/**/body只能被IE8、IE9和火狐识别

所以html>body可以被除IE6以外的浏览器识别

所以:root可以被IE9和火狐识别

@-moz-document url-prefix() {}只能被火狐识别