Skip to content

Commit

Permalink
build
Browse files Browse the repository at this point in the history
  • Loading branch information
hanzhangyu committed Oct 15, 2017
1 parent 31b04dd commit 7298f89
Showing 1 changed file with 135 additions and 50 deletions.
185 changes: 135 additions & 50 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,19 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var SCRIPT_REGEX = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi;
var arrayLikeMap = function arrayLikeMap(arrayLike, fn) {
for (var i = 0; i < arrayLike.length; i++) {
fn(arrayLike[i], i);
}
return arrayLike;
};

// 只会缓存iframe,window模式自动缓存在新建窗口
var singletonCacheData = {
iframe: null,
update: function update(iframe) {
this.iframe = iframe;
}
};

var Print = function (_React$Component) {
Expand All @@ -48,90 +56,149 @@ var Print = function (_React$Component) {
_this.getHead = function () {
var _this$props = _this.props,
insertHead = _this$props.insertHead,
ignoreHeadJs = _this$props.ignoreHeadJs,
title = _this$props.title,
otherStyle = _this$props.otherStyle;

var titleTemplate = title ? '<title>' + title + '</title>' : '';
var otherStyleTemplate = otherStyle ? '<style>' + otherStyle + '</style>' : '';
return '<head>' + titleTemplate + (insertHead ? document.head.innerHTML : '') + otherStyleTemplate + '</head>';
var headTagsTemplate = function () {
if (insertHead) {
var innerHTML = document.head.innerHTML;
return ignoreHeadJs ? innerHTML.replace(SCRIPT_REGEX, '') : innerHTML;
}
return '';
}();
return '' + titleTemplate + headTagsTemplate + otherStyleTemplate;
};

_this.getBodyStyle = function () {
var bodyStyle = _this.props.bodyStyle;

if (bodyStyle) {
var inlineStyle = '';
var stylesDom = document.body.getElementsByTagName('style');
arrayLikeMap(stylesDom, function (item) {
inlineStyle += item.innerHTML;
});
return '<style>' + inlineStyle + '</style>';
}
return '';
var inlineStyle = '';
var stylesDom = document.body.getElementsByTagName('style');
arrayLikeMap(stylesDom, function (item) {
inlineStyle += item.innerHTML;
});
return inlineStyle;
};

_this.lazyRenderBox = function () {
var box = void 0;
if (_this.box) {
box = _this.box;
_this.writeTemplate = function (doc) {
var _this$props2 = _this.props,
bodyStyle = _this$props2.bodyStyle,
lazyRender = _this$props2.lazyRender;

if (lazyRender) {
doc.write('<html><head></head><body></body></html>');
doc.head.innerHTML = _this.getHead();
_reactDom2['default'].render(_this.renderChild(), doc.body); // React的未来版本可能会异步地呈现组件
if (bodyStyle) {
var styleTag = document.createElement('style');
styleTag.innerHTML = _this.getBodyStyle();
doc.body.appendChild(styleTag);
}
} else {
box = document.createElement('div');
_this.box = box;
box.setAttribute('style', 'display:none');
document.body.appendChild(box);
var _dom = _reactDom2['default'].findDOMNode(_this);
var dom = _dom ? _dom.innerHTML : null;
doc.write('<html>\n <head>' + _this.getHead() + '</head>\n <body>' + dom + (bodyStyle ? '<style>' + _this.getBodyStyle() + '</style>' : '') + '</body>\n </html>');
}
_reactDom2['default'].render(_this.renderChild(), box);
return box;
doc.close();
};

_this.iframePrint = function (template) {
_this.createIframe = function (iframeCache, callback) {
var iframeStyle = _this.props.iframeStyle;

var iframe = void 0;
if (_this.iframe) {
iframe = _this.iframe;
if (iframeCache) {
iframe = iframeCache;
} else {
// 新建iframe节点并添加至页面
iframe = document.createElement('IFRAME');
_this.iframe = iframe;
iframe.setAttribute('style', _this.props.iframeStyle);
iframe.setAttribute('style', iframeStyle);
document.body.appendChild(iframe);
}
var doc = iframe.contentWindow.document;
doc.write(template);
doc.close();
iframe.onload = function () {
iframe.contentWindow.focus();
iframe.contentWindow.print();
_this.iframePrint(iframe, callback);
};
_this.writeTemplate(iframe.contentWindow.document);
};

_this.iframePrint = function (iframe, callback) {
iframe.contentWindow.focus();
iframe.contentWindow.print();
callback && callback(iframe);

// wait for a new change
_this.changed = false;
_this.props.onEnd();
};

_this.winPrint = function (template) {
_this.winCreateAndPrint = function () {
var win = window.open('', '', _this.props.winStyle);
var doc = win.document;
doc.write(template);
doc.close();
_this.writeTemplate(win.document);
win.onload = function () {
win.print();

// wait for a new change
_this.changed = false;
_this.props.onEnd();
};
};

_this.renderChild = function () {
var _this$props2 = _this.props,
children = _this$props2.children,
restProps = _objectWithoutProperties(_this$props2, ['children']);
var _this$props3 = _this.props,
children = _this$props3.children,
restProps = _objectWithoutProperties(_this$props3, ['children']);

return _react2['default'].Children.only(children, function (child) {
return (0, _react.cloneElement)(child, _extends({}, restProps));
});
};

_this.changed = true; // 不触发UI渲染
_this.onPrint = function () {
var _this$props3 = _this.props,
isIframe = _this$props3.isIframe,
lazyRender = _this$props3.lazyRender;
var _this$props4 = _this.props,
isIframe = _this$props4.isIframe,
clearIframeCache = _this$props4.clearIframeCache,
singletonCache = _this$props4.singletonCache,
onStart = _this$props4.onStart;

onStart();

if (isIframe) {
if (clearIframeCache) {
// 清理缓存模式
_this.createIframe(null, function (iframe) {
// remove dom
document.body.removeChild(iframe);
});
} else if (singletonCache) {
// 单例模式缓存模式
if (_this.changed || _this.iframe !== singletonCacheData.iframe) {
// 发生改变:1、数据改变;2、缓存对应的组件改变。
_this.createIframe(singletonCacheData.iframe, function (iframe) {
_this.iframe = iframe; // 保存本地用作对比
singletonCacheData.update(iframe);
});
} else {
_this.iframePrint(singletonCacheData.iframe);
}
} else if (_this.changed) {
// 普通缓存模式发生改变
_this.createIframe(_this.iframe, function (iframe) {
_this.iframe = iframe;
});
} else {
// 普通缓存模式未改变
_this.iframePrint(_this.iframe);
}
} else {
_this.winCreateAndPrint();
}

var _dom = lazyRender ? _this.lazyRenderBox() : _reactDom2['default'].findDOMNode(_this);
var dom = _dom ? _dom.innerHTML : null;
var template = '<html>' + _this.getHead() + '<body>' + _this.getBodyStyle() + dom + '</body></html>';
isIframe ? _this.iframePrint(template) : _this.winPrint(template);
// // lazyRender的遗留临时渲染节点不保留
// if (this.box) {
// document.body.removeChild(this.box);
// this.box = null;
// }
};
return _this;
}
Expand All @@ -151,11 +218,19 @@ var Print = function (_React$Component) {
document.addEventListener('keydown', this.prevent);
}
}
}, {
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps(nextProps) {
if (nextProps !== this.props) {
// this.setState({changed: true});
this.changed = true;
}
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
this.iframe && document.body.removeChild(this.iframe);
this.box && document.body.removeChild(this.box); // 移除懒加载隐藏节点
// this.box && document.body.removeChild(this.box); // 移除懒加载隐藏节点
this.prevent && document.removeEventListener('keydown', this.prevent);
}
}, {
Expand All @@ -170,25 +245,35 @@ var Print = function (_React$Component) {

Print.propTypes = {
insertHead: _propTypes2['default'].bool, // 是否植入本页面的head标签
bodyStyle: _propTypes2['default'].bool, // 是否植入body标签中的style
ignoreHeadJs: _propTypes2['default'].bool, // 当insertHead启用时是否屏蔽JS文件
bodyStyle: _propTypes2['default'].bool, // 是否植入body标签中的style,插入body底部
otherStyle: _propTypes2['default'].string, // 附加的样式将直接插入head最底部
isIframe: _propTypes2['default'].bool, // 是否使用iframe插入,否则将使用新窗口
iframeStyle: _propTypes2['default'].string, // 将被应用到iframe或者new window
winStyle: _propTypes2['default'].string, // 将被应用到iframe或者new window
title: _propTypes2['default'].string, // iframe或者新窗口的标题,将会在打印页的页眉和新窗口的title
preventDefault: _propTypes2['default'].bool, // 是否替换Ctrl+P
lazyRender: _propTypes2['default'].bool, // 是否只渲染在iframe或者新窗口上
clearIframeCache: _propTypes2['default'].bool, // 是否清理dom缓存。否的情况下,如props为改变将保留并直接使用上次打印留下的dom
singletonCache: _propTypes2['default'].bool, // 当clearIframeCache关闭时生效。类单例模式,当界面有多个打印组件时,最多允许保留一个缓存
onStart: _propTypes2['default'].func, // 组件开始打印渲染
onEnd: _propTypes2['default'].func, // 组件打印渲染完成
children: _propTypes2['default'].node.isRequired
};
Print.defaultProps = {
insertHead: true,
ignoreHeadJs: true,
bodyStyle: false,
otherStyle: undefined,
isIframe: true,
iframeStyle: 'position:absolute;width:0px;height:0px;',
winStyle: 'toolbar=no,menubar=no',
title: undefined,
preventDefault: false,
lazyRender: false
lazyRender: false,
clearIframeCache: false,
singletonCache: true,
onStart: function onStart() {},
onEnd: function onEnd() {}
};
exports['default'] = Print;

0 comments on commit 7298f89

Please sign in to comment.