一、错误边界
1.何为错误边界?
React官网定义:错误边界是一种
React
组件,这种组件可以捕获并打印发生在其子组件树任何位置的JavaScript
错误,并且,它会渲染出备用UI
,而不是渲染那些崩溃了的子组件树。错误边界在渲染期间、生命周期方法和整个组件树的构造函数中捕获错误。
简单来说就是在错误发生的时候,可以捕获到异常的代码并渲染备用的UI。有的人会说这不就是try{}catch(){}
吗?其实我想说非也非也!try{}catch(){}
很棒,但是try{}catch(){}
仅仅只能用于命令式代码,而react组件
是声明式。我们是用react-demo搭建我们的测试环境。然后git clone -> npm install -> npm run start
,看见如下页面则表示成功。
接下来我们来修改一下代码:
class ErrorUI extends Component{
state={
mapArr:{}
}
render(){
return(
<ul>
{
this.state.mapArr.map(item=><li>{"我是测试"}</li>)
}
</ul>
)
}
}
我们先是创建了一个组件,然后故意将mapArr
设置为一个对象,在render
返回时遍历,但其实对象并没有map属性,这时我们查看界面是一片空白,然后我们F12
打开控制台会发现一片报红。但是明明是<ErrorUI />
这个组件的问题,我们希望Hello React可以展示出来。
那这怎么办呢?此时错误边界就派上用场了:自 React 16 起,任何未被错误边界捕获的错误将会导致整个 React 组件树被卸载。即会产生空白现象。因为
"显示错误的金额也比不呈现任何内容更糟糕"
。
如果一个 class 组件中定义了
static getDerivedStateFromError()
或componentDidCatch()
。 这两个生命周期方法中的任意一个(或两个)时,那么它就变成一个错误边界。前者渲染备用UI,后者打印错误信息。
class ErrorBoundary extends React.Component{
constructor(props){
super(props);
this.state={hasError:false};
}
static getDerivedStateFromError(error) {
//当出现错误时会进入这个生命周期函数
// 更新 state 使下一次渲染能够显示降级后的 UI
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// 你同样可以将错误日志上报给服务器
console.log(error);
console.log(errorInfo);
}
render() {
if (this.state.hasError) {
// 你可以自定义降级后的 UI 并渲染
return <h1>代码存在问题</h1>;
}
return this.props.children;
}
}
<div style={styleObj}>
Hello React
<ErrorBoundary>
<ErrorUI />
</ErrorBoundary>
</div>
根据错误边界的定义,我们创建了一个错误边界组件,并将可能产生错误的组件包裹,然后再次打开浏览器。你会发现浏览器正确运行并且将错误UI替换成了你所写的备用UI。
虽然控制台有捕获到错误,但是这丝毫不影响页面中其他元素的错误。2.错误边界的缺陷
- 事件处理(了解更多)
- 异步代码(例如 setTimeout 或 requestAnimationFrame 回调函数)
- 服务端渲染
- 它自身抛出来的错误(并非它的子组件)
- 语法错误
3.错误边界的实际用途
- 包裹在最顶层的路由组件并为用户展示一个 “Something went wrong” 的错误信息,就像服务端框架经常处理崩溃一样。
- 你也可以将单独的部件包装在错误边界以保护应用其他部分不崩溃。
二、Fragment标签
1.Fragment
标签极其用途
假设有这样一个场景,一个父组件希望子组件仅有2个div标签,但是如下所写肯定是有问题的, 因为在React的render方法/Vue的template中必须有一个根元素节点。
class LiComponent extends React.Component{
render(){
return(
<div>我是</div>
<div>测试</div>
<div>子元素</div>
)
}
}
<div style={styleObj}>
Hello React
<BoundErrorComponent>
<LiComponent />
</BoundErrorComponent>
</div>
这是我们需要将子元素用一个节点包裹起来,不然会产生语法错误,但是我们不想增加额外节点,从始至终都是这个节点该怎么做呢?使用<Fragment />
标签进行包裹。
<Fragment>
<div>我是</div>
<div>测试</div>
<div>子元素</div>
</Fragment>
打开浏览器即可发现
2.为什么在React
的render
方法/Vue
的template
中必须有一个根元素节点呢?
2.1.vue
当我们实例化Vue的时候,填写一个el选项,来指定我们的SPA入口:
let vm=new Vue({
el:"#app"
})
同时我们也会在body里面新增一个id为app的div
<body>
<div id="app"></div>
</body>
这很好理解,就是为vue开启一个入口,那我们不妨来想想,如果我在body下这样
<body>
<div id='app1'></div>
<div id='app2'></div>
</body
Vue其实并不知道哪一个才是我们的入口,因为对于一个入口来讲,这个入口就是一个‘Vue类',Vue需要把这个入口里面的所有东西拿来渲染,处理,最后再重新插入到dom中。如果同时设置了多个入口,那么vue就不知道哪一个才是这个‘类'。当我们在webpack搭建的vue开发环境下,使用单文件组件时,你可能会这样:
<template>
<div class='component'></div>
</template>
那这里为什么template下也必须有且只能有一个div呢? 这里我们要先看一看template这个标签,这个标签是HTML5出来的新标签,它有三个特性:
- 隐藏性:该标签不会显示在页面的任何地方,即便里面有多少内容,它永远都是隐藏的状态;
- 任意性:该标签可以写在页面的任何地方,甚至是head、body、sciprt标签内;
- 无效性:该标签里的任何HTML内容都是无效的,不会起任何作用;
但是呢,你可以通过innerHTML来获取到里面的内容。知道了这个,我们再来看.vue的单文件组件。其实本质上,一个单文件组件,本质上(我认为)会被各种各样的loader处理成为.js文件(因为当你import一个单文件组件并打印出来的时候,是一个vue实例),通过template的任意性我们知道,template包裹的HTML可以写在任何地方,那么对于一个.vue来讲,这个template里面的内容就是会被vue处理为虚拟dom并渲染的内容,导致结果又回到了开始 :既然一个.vue单文件组件是一个vue实例,那么这个实例的入口在哪里?
如果在template下有多个div,那么该如何指定这个vue实例的根入口?为了让组件能够正常的生成一个vue实例,那么这个div会被自然的处理成程序的入口。通过这个‘根节点',来递归遍历整个vue‘树'下的所有节点,并处理为vdom,最后再渲染成真正的HTML,插入在正确的位置。那么这个入口,就是这个树的‘根',各个子元素,子组件,就是这个树的‘枝叶',而自然而然地,这棵‘树',就是指一个vue实例了。
2.2 React
在阅读源码后我们发现render返回值类型为React.Node,而React.Node包含如上几种类型。
其实和Vue的道理一样,如果你不写一个根div,入口无法判别哪个才是真正的实例入口
2.3 总结
就像一个HTML文档只能有一个根元素一样.... 多个根元素必将导致无法构成一颗树。
3.带key
的<Fragment />
有可能你会遇到下面的某种情况
state={
arr:new Array(10).fill("测试")
}
render(){
return(
<div>
{
this.state.arr.map((item,index)=>(
<Fragment>
<div>{`测试${index}`}</div>
</Fragment>
))
}
</div>
)
}
但是你在控制台会看见这样的警告
原因:react的key关乎到react的dom-diff算法 react中对于dom的操作是根据生成的data-reactid进行绑定的,添加key可以保证dom结构的完整性,而不会根据react自己对dom标记的key进行重新分配 react每次决定重新渲染的时候,几乎完全是根据data-reactid来决定的。
细心的Fragment
显然是注意到了这一点。
<Fragment key={index}>
<div>{`测试${index}`}</div>
</Fragment>
Tips:
key
是唯一可以传递给Fragment
的属性。未来我们可能会添加对其他属性的支持,例如事件。
三、Context
1.何为Context
如上图,假设props
为棒棒糖,爷爷想给孙子一块棒棒糖,在传统react
中,想给孙子棒棒糖需要将棒棒糖给爸爸,然后爸爸再给儿子,实际的目的是给儿子,但是谁知道爸爸会不会偷吃呢?
Context
应运而生,Context
设计的目的就是为了解决这种问题,没有中间商赚差价。
//传统react写法
//顶层father组件
import React,{Fragment,Component} from 'react';
import Father from './Father';
export default class GrandFather extends React.Component{
state={
some:"大白兔奶糖"
}
render(){
return(
<div >
<div>{`全局共享数据:`}<span style={{color:"red"}}>{this.state.some}</span></div>
{`爷爷给孙子一块`}<span style={{color:"red"}}>{this.state.some}</span>
<Father some={this.state.some}/>
</div>
)
}
}
//中间层父亲组件
import React,{Fragment,Component} from 'react';
import Son from './Son';
export default class Father extends React.Component{
render(){
return(
<div>
{`父亲接収到爷爷给他的 `}<span style={{color:"red"}}>{this.props.some}</span>
<Son some={this.props.some}/>
</div>
)
}
}
//底层儿子组件
import React,{Fragment,Component} from 'react';
export default class Son extends React.Component{
render(){
return(
<div >
{`儿子接収到爷爷给他的 `}<span style={{color:"red"}}>{this.props.some}</span>
</div>
)
}
}
查看效果
使用Context改造后
//爷爷组件
import React from 'react';
import Father from './Father';
export const SomeContext=React.createContext();
export default class GrandFather extends React.Component{
state={
some:"大白兔奶糖"
}
render(){
return(
<div >
<div>{`全局共享数据:`}<span style={{color:"red"}}>{this.state.some}</span></div>
{`爷爷给孙子一块`}<span style={{color:"red"}}>{this.state.some}</span>
<SomeContext.Provider value={"大白兔奶糖"} >
<Father />
</SomeContext.Provider>
</div>
)
}
}
//父亲组件内容不变
//儿子组件
import React, { Fragment, Component } from 'react';
import { SomeContext } from './GrandFather'
export default class Son extends React.Component {
render() {
return (
<SomeContext.Consumer>
{value => {
return <div >
{`儿子接収到爷爷给他的 `}<span style={{ color: "red" }}>{value}</span>
</div>
}}
</SomeContext.Consumer>
)
}
}
2.相关API
介绍
React.createContext
const MyContext = React.createContext(defaultValue);
<MyContext.Consumer>
{defaultValue=>/**/}
</MyContext.Consumer>
或者
const MyContext=React.createContext();
<MyContext.Provider value={"some"}>
<Component />
<MyContext.Provider>
<MyContext.Consumer>
{value=>/**/}
</MyContext.Consumer>
创建一个
Context
对象。当React渲染一个订阅(Provider
)Context
对象的组件。这个组件会从组件树中离自身最近的那个匹配的Provider
中读取到当前的context
值。换句话说,如果组件树中没有Provider
时,defaultValue
才会生效,否则无法生效。
Context.Provider
生产者,提供数据的API,其中,当
Provider
的value
值发生变化时,它内部的所有消费组件都会重新渲染,且不受制于shouldComponentUpdate
函数。
<MyContext.Provider value={"some"}>
<Component />
<MyContext.Provider>
Class.contextType
import React from 'react';
import Father from './Father';
export const SomeContext=React.createContext("some");
export default class GrandFather extends React.Component{
state={
some:"大白兔奶糖"
}
static contextType = SomeContext;
render(){a
return(
<div >
<div>{`全局共享数据:`}<span style={{color:"red"}}>{this.context}</span></div>
</div>
)
}
}
挂载在
class
上的contextType
属性会被重赋值为一个由React.createContext()
创建的Context
对象。并可通过this.context
获取value
。
- Context.Consumer
消费者,包裹函数,这个函数接收当前的
context
值,返回一个React
节点。传递给函数的value
值等同于往上组件树离这个context
最近的Provider
提供的value
值。如果没有对应的Provider
,value
参数等同于传递给createContext()
的defaultValue
。
<MyContext.Consumer>
{value => /* 基于 context 值进行渲染*/}
</MyContext.Consumer>
3.高级用法
1.嵌套组件中更新context
传递一个函数,使得consumers组件更新context,即更新生产者的state
const ThemeContext = React.createContext({
theme: themes.dark,
toggleTheme: () => {},
});
<ThemeContext.Provider value={this.state}>
<Content />
</ThemeContext.Provider>
<ThemeContext.Consumer>
{({theme, toggleTheme}) => (
<button
onClick={toggleTheme}
style={{backgroundColor: theme.background}}>
Toggle Theme
</button>
)}
</ThemeContext.Consumer>
2.消费多个Context
//生产者
<ThemeContext.Provider value={theme}>
<UserContext.Provider value={signedInUser}>
<Layout />
</UserContext.Provider>
</ThemeContext.Provider>
//消费者
<ThemeContext.Consumer>
{theme => (
<UserContext.Consumer>
{user => (
<ProfilePage user={user} theme={theme} />
)}
</UserContext.Consumer>
)}
</ThemeContext.Consumer>
4.注意事项
当 provider 的父组件进行重渲染时,可能会在 consumers 组件中触发意外的渲染。举个例子,当每一次 Provider 重渲染时,以下的代码会重渲染所有下面的 consumers 组件,因为 value 属性总是被赋值为新的对象:
class App extends React.Component {
render() {
return (
<Provider value={{something: 'something'}}>
<Toolbar />
</Provider>
);
}
}
//转化后
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: {something: 'something'},
};
}
render() {
return (
<Provider value={this.state.value}>
<Toolbar />
</Provider>
);
}
}
四、高阶组件(重点)
高阶组件是这篇文章的重点,合理运用好高阶组件,会让开发变得更加有效率,同时代码也会变得更优雅。
1.何为高阶组件
高阶组件是参数为组件,返回值为新组件的函数。高阶组件是一个函数,一个返回新组件的函数。
const EnhancedComponent = higherOrderComponent(WrappedComponent);
2.何时应该使用高阶组件
当你的组件里面有大量的重复的代码,这些代码仅有一些参数之类的变化,这时你就可以使用高阶函数,将共用部分抽离出来,或者利用高阶函数完成更多操作。 在前文手写快递单中,我们的需求是添加按钮,选择快递打印快递单等(实际上快递单打印部分的代码很多),不幸的是不仅是一个页面需要使用打印快递单的功能,有十个页面都需要。而且打印快递单的逻辑与页面中的逻辑混杂在一起,很不方便。这时候脑海中灵光一现,高阶函数一下子就蹦了出来。通过高阶函数抽离代码,使得维护成本降低。首先我们将打印的代码放在项目中。
//打印的代码
import React from 'react';
import { expressHtml } from './ExpressHtml';
export default class Test extends React.Component{
constructor(props){
super(props);
this.state={
//由于初始化时我们需要创造打印机的纸张,所以我们需要打印机的value,
//由于操作系统打印机的顺序是由0开始的所以我们初始化时设置0
printerValue:0,
pageValue:undefined
}
}
componentDidMount(){
if(typeof CLODOP!=="undefined" && typeof LODOP!=="undefined"){
CLODOP.Create_Printer_List(this.selectRefs);
CLODOP.Create_PageSize_List(this.pageRefs, this.state.printerValue);
}
}
handlePrint=()=>{
//const MODE="PREVIEW";
//const MODE="PRINT_DESIGN";
const MODE="PRINT";
this.demoPrint(MODE)
}
demoPrint=(MODE)=>{//MODE对应着LODOP的预览、打印以及设计
const {printerValue }=this.state;
const MarkDestination="586 216 ";
const LogisticCode="7720052644695844";
const PackageName="萍乡中转包";
const OrderCode="FH191209007";
const Sender={
Name: "刘德华",
Mobile: "17798680131",
ProvinceName: "江苏省",
CityName: "苏州市",
ExpAreaName: "昆山市",
Address: "花桥镇家宝路608号 工业园H库"
}
const Receiver={
Name: "赵先生",
Mobile: "15245451110",
ProvinceName: "江西省",
CityName: "萍乡市",
ExpAreaName: "莲花县",
Address: "陕西省某个地方",
}
const Onecode=`<div style="font-size:0;position:relative;width:200px;height:30px;">
<div style="background-color:black;width:2px;height:30px;position:absolute;left:0px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:3px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:8px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:11px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:15px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:18px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:22px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:26px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:29px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:33px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:37px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:42px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:44px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:47px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:51px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:55px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:58px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:62px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:66px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:69px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:74px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:77px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:81px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:86px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:88px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:92px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:96px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:99px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:103px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:106px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:110px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:114px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:117px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:121px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:125px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:129px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:132px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:137px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:139px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:143px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:147px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:150px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:154px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:159px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:161px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:165px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:169px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:172px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:176px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:178px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:183px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:187px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:192px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:196px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:198px;top:0px;"> </div>
<div style="background-color:black;width:0px;height:30px;position:absolute;left:200px;top:0px;"> </div>
<div style="background-color:black;width:0px;height:30px;position:absolute;left:200px;top:0px;"> </div>
</div>`
const html = expressHtml(LogisticCode, MarkDestination, PackageName, Sender, Receiver, Onecode, OrderCode);
if(typeof CLODOP==="undefined"){
alert("系统检测出你没有启动打印设备或者端口号设置错误!!");
return;
}
LODOP.SET_PRINTER_INDEXA(Number(printerValue));
LODOP.ADD_PRINT_HTM(0, 0, "100%", "100%", html);
if(MODE){
LODOP[MODE]();
}
}
handleChangePrinter=(e)=>{
this.setState({
printerValue: e.target.value,
pageValue: undefined
}, () => {
if (typeof CLODOP !== "undefined") {
CLODOP.Create_PageSize_List(this.pageRefs, this.state.printerValue);
}
})
}
handleChangePage=(e)=>{
this.setState({
pageValue: e.target.value
})
}
render(){
const styleObj={
justifyContent:"center",
alignItems:"center",
fontSize:50,
color:'skyblue',
width:'100%',
height:'100%',
backgroundColor:"blue",
}
const buttonObj={
border: 'none',
borderRadius:'2px',
background:'#e0e0e0',
color:'inherit',
display: 'inline-flex',
justifyContent: 'center',
alignItems: 'center',
whiteSpace: 'nowrap',
fontWeight:500,
height: '32px',
padding: '0 15px',
fontSize: '14px',
outline: 0,
position: 'relative',
textDecoration:'none',
transition:'all .3s ease',
opacity:1,
cursor:'pointer',
backgroundColor: 'rgba(91,231,196)',
opacity:1,
color:'white',
boxShadow: '0 2px 2px 0 rgba(0,0,0,0.14), 0 1px 5px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.2)'
}
const selectObj={
border: "1px solid #d9d9d9",
padding: "4px 0"
}
return(
<div style={styleObj}>
<div style={{width:"100%"}}>Hello React</div>
<div style={{width:"100%"}}><button style={buttonObj} onClick={this.handlePrint}>测试打印</button></div>
<select style={selectObj} ref={ref => this.selectRefs = ref} value={this.state.printerValue} size="1" onChange={this.handleChangePrinter}></select>
<select style={selectObj} ref={ref => this.pageRefs = ref} value={this.state.pageValue} size="1" onChange={this.handleChangePage}></select>
</div>
)
}
}
//快递单的html
export function expressHtml(LogisticCode,MarkDestination,PackageName,Sender,Receiver,Onecode,OrderCode,Remark=""){
return `<html style="overflow:hidden;"><head><style>.item{position:absolute;}</style></head><body style="position:relative;overflow:hidden;">
<div class="item vline" style="left:1px;top:1px;height:479px;width:0;border-left:1px solid #000;"></div>
<div class="item hline" style="left:1px;top:1px;width:278px;height:0;border-top:0.909091px solid #000"></div>
<div class="item vline" style="left:279px;top:1px;height:479px;width:0;border-left:1px solid #000;"></div>
<div class="item hline" style="left:2px;top:50px;width:278px;height:0;border-top:0.909091px solid #000"></div>
<div class="item hline" style="left:1px;top:280px;width:278px;height:0;border-top:0.994318px solid #000"></div>
<div class="item text" style="left:5px;top:35px;width:148.011364px;height:12.011364px;font-family:'微软雅黑';font-size:10px;font-weight:400;overflow:visible">2019-09-11</div>
<div class="item text" style="left:68.9943px;top:100.98px;width:154.011364px;height:17.011364px;font-family:'微软雅黑';font-size:12px;font-weight:400;overflow:visible">${LogisticCode}</div>
<div class="item hline" style="left:2px;top:122px;width:278px;height:0;border-top:0.994318px solid #000"></div>
<div class="item hline" style="left:1px;top:163px;width:278px;height:0;border-top:0.994318px solid #000"></div>
<div class="item hline" style="left:1px;top:203px;width:278px;height:0;border-top:0.994318px solid #000"></div>
<div class="item hline" style="left:1px;top:479px;width:278px;height:0;border-top:0.994318px solid #000"></div>
<div class="item text" style="left:39.9972px;top:348px;width:232.011364px;height:16.011364px;font-family:'微软雅黑';font-size:10px;font-weight:400;overflow:visible"></div>
<div class="item text" style="left:164.5px;top:5px;width:65.011364px;height:19.011364px;font-family:'微软雅黑';font-size:13px;font-weight:800;overflow:visible;display:none">代收货款:</div>
<div class="item text" style="left:164.5px;top:26px;width:61.011364px;height:20.011364px;font-family:'微软雅黑';font-size:14px;font-weight:400;overflow:visible;display:none"></div>
<div class="item text" style="left:237.486px;top:460px;width:46.011364px;height:17.011364px;font-family:'微软雅黑';font-size:12px;font-weight:400;overflow:visible">已验视</div>
<div class="item text" style="left:5px;top:127px;width:270.011364px;height:50.011364px;font-family:'微软雅黑';font-size:26px;font-weight:400;overflow:visible">${MarkDestination}</div>
<div class="item hline" style="left:1.99432px;top:320px;width:278px;height:0;border-top:0.994318px solid #000"></div>
<div class="item hline" style="left:1.99432px;top: 360px;width:278px;height:0;border-top:0.994318px solid #000;"></div>
<div class="item image" style="left: 34.4886px;top: 325.983px;width: 243px;height: 49px;">${Onecode}</div></body></html>
<div class="item text" style="left:3.99719px;top: 365.989px;width:39.011364px;height:16.011364px;font-family:'微软雅黑';font-size:10px;font-weight:400;overflow:visible">备注:</div>
<div class="item text" style="left:5px;top:384px;width:269.011364px;height:81.011364px;font-family:'微软雅黑';font-size:12px;font-weight:400;overflow:visible">订单编号:${OrderCode?OrderCode:"空"}</div>
<div class="item text" style="left:5px;top:401px;width:230.011364px;height:79.011364px;font-family:'微软雅黑';font-size:12px;font-weight:400;overflow:hidden">劳保用品<br /><span style="font-size:16px;font-weight: 600;">需本人签收,禁止投放驿站</span></div>
<div class="item text" style="left:5px;top:438px;width:230.011364px;font-family:'微软雅黑';font-size:12px;font-weight:400;overflow:hidden">${Remark}</div>
<img class="item image" style="left:5px;top:169px;width:30px;height:30px;" rb319WBVhDOFORiabxDKJdnHYSuE8HVdBx/C58cYbJ4uiVWGGmqkI2iac79StliDCEuK5tPIL1/KVd7LmNRClpojJshUZGlrp18u/ZguRSjmbvTWnNoyO0qwdUr+K6xwGNI5SaKvPdSi5EAityMrAlNpFXxKxIlpjUGrbXFYy5hGUwal55eFKBhDiuSCf0g1qQfQ+gtV+N9C4hdiMUJYBCTGoxjZChUNQsjqt8rKUIIqq2mExhpBKelJnFaxa75ufr88MTW0yPsamb6L0EpNxEcsHhgYIhiAar5GU/cknn7wnFQS4he9lIo0hZhv0pcFgyVpC0L4/F8B92ANjOXNJmGB0OWNTu4dUyvcSEwHJbheHOWpNIT7jTDUxr3jFK5rHPvaxe35T GtfRS7zYnpHOpELFdwXmYiHomRR5GiLVwSZac7UUaDFqRGVzH0rtLsjmd+TCVml0gtid4c7bwe0SgSo67W9tnSUe379CH2urUrVt7feGUEnXbaaUk8I24pkE0Ey38Sx3Tn3OhTP5Eo79rcv+iasGR1cOpTAbosvHwwS3U38VtUur/+9a9PHKO2VZtqlm2XZYxIQm8MF5YofZgHAxDPXjw4WZ/bgQLGE9+SS7Ld2aQYQ4wVOr+GqgHkRJ2idOeOP+YE4cdxB9rGVohXOsJv/qdDU6zGiKc HUQVdOqG8Agew3ub0q0rXGiuS6XIGjVpZVmcQMwq61NMKskcgonbfAJFMd+JORpJV1B4/7CA q3j+X2TElOxZp+Ay0MLL5nU9uEDxcnIL7KDuBJeRkGFXcj9eup97R1L+BynmcVbTrPB8AAAAAElFTkSuQmCC">
<div class="item text" style="left:44.4972px;top:169.977px;width:230.011364px;height:37.011364px;font-family:'微软雅黑';font-size:18px;font-weight:400;overflow:visible">${PackageName}</div>
<div class="item text" style="left:39px;top:210px;width:236.011364px;height:68.011364px;font-family:'微软雅黑';font-size:12px;font-weight:400;overflow:visible">${Receiver.Name} ${Receiver.Mobile} ${Receiver.ProvinceName} ${Receiver.CityName} ${Receiver.ExpAreaName} ${Receiver.Address}</div>
<div class="item text" style="left:37.4972px;top:283.989px;width:236.011364px;height:35.011364px;font-family:'微软雅黑';font-size:12px;font-weight:400;overflow:visible">${Sender.Name} ${Sender.Mobile} ${Sender.ProvinceName} ${Sender.CityName} ${Sender.ExpAreaName} ${Sender.Address}</div>
style="color:white;left:235.923px;top:6.96022px;width:0px;height:0px;font-family:'微软雅黑';font-size:15px;font-weight:900;overflow:visible;display:none">货到付款</div>
<div class="item image" style="left: 34.4886px;top: 65.983px;width: 243px;height: 49px;">${Onecode}</div></body></html>
`
}
可以看出正常运行。接下来我们再改造。我们在src目录下新建components目录。新建一个js用来写我们的高阶组件。由上得出高阶函数是一个函数,传入原组件,返回一个新组件。大致我们可以得出以下的高阶组件模型。那
import React from "react";
export default (WrappedComponent)=>{
class NewComponent extends React.Component {
render(){
const newProps={
}
return <WrappedComponent {...newProps}/>
}
}
return NewComponent
}
然后我们分析一下哪些东西是所有打印快递单页面共用的。
1. 打印按钮以及相关联
//高阶组件
import React from "react";
export default (WrappedComponent) => {
class NewComponent extends React.Component {
constructor(props){
super(props);
this.state={
//由于初始化时我们需要创造打印机的纸张,所以我们需要打印机的value,
//由于操作系统打印机的顺序是由0开始的所以我们初始化时设置0
printerValue:0,
pageValue:undefined
}
}
componentDidMount(){
}
handlePrint = () => {
//const MODE="PREVIEW";
//const MODE="PRINT_DESIGN";
const MODE = "PRINT";
this.demoPrint(MODE)
}
demoPrint = (MODE) => {//MODE对应着LODOP的预览、打印以及设计
const { printerValue } = this.state;
const MarkDestination = "586 216 ";
const LogisticCode = "7720052644695844";
const PackageName = "萍乡中转包";
const OrderCode = "FH191209007";
const Sender = {
Name: "刘德华",
Mobile: "17798680131",
ProvinceName: "江苏省",
CityName: "苏州市",
ExpAreaName: "昆山市",
Address: "花桥镇家宝路608号 工业园H库"
}
const Receiver = {
Name: "赵先生",
Mobile: "15245451110",
ProvinceName: "江西省",
CityName: "萍乡市",
ExpAreaName: "莲花县",
Address: "陕西省某个地方",
}
const Onecode = `<div style="font-size:0;position:relative;width:200px;height:30px;">
<div style="background-color:black;width:2px;height:30px;position:absolute;left:0px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:3px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:8px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:11px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:15px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:18px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:22px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:26px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:29px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:33px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:37px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:42px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:44px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:47px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:51px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:55px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:58px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:62px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:66px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:69px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:74px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:77px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:81px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:86px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:88px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:92px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:96px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:99px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:103px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:106px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:110px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:114px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:117px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:121px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:125px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:129px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:132px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:137px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:139px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:143px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:147px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:150px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:154px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:159px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:161px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:165px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:169px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:172px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:176px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:178px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:183px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:187px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:192px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:196px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:198px;top:0px;"> </div>
<div style="background-color:black;width:0px;height:30px;position:absolute;left:200px;top:0px;"> </div>
<div style="background-color:black;width:0px;height:30px;position:absolute;left:200px;top:0px;"> </div>
</div>`
const html = expressHtml(LogisticCode, MarkDestination, PackageName, Sender, Receiver, Onecode, OrderCode);
if (typeof CLODOP === "undefined") {
alert("系统检测出你没有启动打印设备或者端口号设置错误!!");
return;
}
LODOP.SET_PRINTER_INDEXA(Number(printerValue));
LODOP.ADD_PRINT_HTM(0, 0, "100%", "100%", html);
if (MODE) {
LODOP[MODE]();
}
}
render() {
const buttonObj = {
border: 'none',
borderRadius: '2px',
background: '#e0e0e0',
color: 'inherit',
display: 'inline-flex',
justifyContent: 'center',
alignItems: 'center',
whiteSpace: 'nowrap',
fontWeight: 500,
height: '32px',
padding: '0 15px',
fontSize: '14px',
outline: 0,
position: 'relative',
textDecoration: 'none',
transition: 'all .3s ease',
opacity: 1,
cursor: 'pointer',
backgroundColor: 'rgba(91,231,196)',
opacity: 1,
color: 'white',
boxShadow: '0 2px 2px 0 rgba(0,0,0,0.14), 0 1px 5px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.2)'
}
const buttonElement =(
<div style={{ width: "100%" }}><button style={buttonObj} onClick={this.handlePrint}>测试打印</button></div>
)
const newProps = {
buttonElement,
}
return <WrappedComponent {...newProps} />
}
}
return NewComponent
}
//改造后的打印页面
import React from 'react';
import { expressHtml } from '../utils/ExpressHtml';
export default class Test extends React.Component{
constructor(props){
super(props);
this.state={
//由于初始化时我们需要创造打印机的纸张,所以我们需要打印机的value,
//由于操作系统打印机的顺序是由0开始的所以我们初始化时设置0
printerValue:0,
pageValue:undefined
}
}
handleChangePrinter=(e)=>{
this.setState({
printerValue: e.target.value,
pageValue: undefined
}, () => {
if (typeof CLODOP !== "undefined") {
CLODOP.Create_PageSize_List(this.pageRefs, this.state.printerValue);
}
})
}
handleChangePage=(e)=>{
this.setState({
pageValue: e.target.value
})
}
render(){
const styleObj={
justifyContent:"center",
alignItems:"center",
fontSize:50,
color:'skyblue',
width:'100%',
height:'100%',
backgroundColor:"blue",
}
const selectObj={
border: "1px solid #d9d9d9",
padding: "4px 0"
}
return(
<div style={styleObj}>
<div style={{width:"100%"}}>Hello React</div>
{this.props.buttonElement}
<select style={selectObj} ref={ref => this.selectRefs = ref} value={this.state.printerValue} size="1" onChange={this.handleChangePrinter}></select>
<select style={selectObj} ref={ref => this.pageRefs = ref} value={this.state.pageValue} size="1" onChange={this.handleChangePage}></select>
</div>
)
}
}
这是我们发现页面的打印按钮不见了,那是不是我们写错了呢?其实不然,因为我们还没有将高阶函数导入进来呢!
我们将高阶函数导入import TypingPage from '../../component/TypingPage';
页面中使用高阶函数有2种方法:
- 将组件包裹导出
export default TypingPage(Test);
- 使用装饰器语法
@TypingPage
class Test extends React.Component{}
当然直接这么写是会报错的,因为它不识别es装饰器语法,需要借助babel
来转化。
npm install @babel/plugin-proposal-decorators --save-dev
//.babelrc
"plugins":[
["@babel/plugin-proposal-decorators", { "legacy": true }]
]
这下子重启可以看到
2. 选择打印机按钮以及相关联
最后打印高阶组件变成下面这样
import React,{Fragment } from "react";
export default (WrappedComponent) => {
class NewComponent extends React.Component{
constructor(props){
super(props);
this.state={
//由于初始化时我们需要创造打印机的纸张,所以我们需要打印机的value,
//由于操作系统打印机的顺序是由0开始的所以我们初始化时设置0
printerValue:0,
pageValue:undefined
}
}
componentDidMount(){
if(typeof CLODOP!=="undefined" && typeof LODOP!=="undefined"){
CLODOP.Create_Printer_List(this.selectRefs);
CLODOP.Create_PageSize_List(this.pageRefs, this.state.printerValue);
}
}
handlePrint = () => {
//const MODE="PREVIEW";
//const MODE="PRINT_DESIGN";
const MODE = "PRINT";
this.demoPrint(MODE)
}
handleChangePrinter=(e)=>{
this.setState({
printerValue: e.target.value,
pageValue: undefined
}, () => {
if (typeof CLODOP !== "undefined") {
CLODOP.Create_PageSize_List(this.pageRefs, this.state.printerValue);
}
})
}
handleChangePage=(e)=>{
this.setState({
pageValue: e.target.value
})
}
demoPrint = (MODE) => {//MODE对应着LODOP的预览、打印以及设计
const { printerValue } = this.state;
const MarkDestination = "586 216 ";
const LogisticCode = "7720052644695844";
const PackageName = "萍乡中转包";
const OrderCode = "FH191209007";
const Sender = {
Name: "刘德华",
Mobile: "17798680131",
ProvinceName: "江苏省",
CityName: "苏州市",
ExpAreaName: "昆山市",
Address: "花桥镇家宝路608号 工业园H库"
}
const Receiver = {
Name: "赵先生",
Mobile: "15245451110",
ProvinceName: "江西省",
CityName: "萍乡市",
ExpAreaName: "莲花县",
Address: "陕西省某个地方",
}
const Onecode = `<div style="font-size:0;position:relative;width:200px;height:30px;">
<div style="background-color:black;width:2px;height:30px;position:absolute;left:0px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:3px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:8px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:11px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:15px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:18px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:22px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:26px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:29px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:33px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:37px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:42px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:44px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:47px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:51px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:55px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:58px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:62px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:66px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:69px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:74px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:77px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:81px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:86px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:88px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:92px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:96px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:99px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:103px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:106px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:110px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:114px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:117px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:121px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:125px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:129px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:132px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:137px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:139px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:143px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:147px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:150px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:154px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:159px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:161px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:165px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:169px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:172px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:176px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:178px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:183px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:187px;top:0px;"> </div>
<div style="background-color:black;width:3px;height:30px;position:absolute;left:192px;top:0px;"> </div>
<div style="background-color:black;width:1px;height:30px;position:absolute;left:196px;top:0px;"> </div>
<div style="background-color:black;width:2px;height:30px;position:absolute;left:198px;top:0px;"> </div>
<div style="background-color:black;width:0px;height:30px;position:absolute;left:200px;top:0px;"> </div>
<div style="background-color:black;width:0px;height:30px;position:absolute;left:200px;top:0px;"> </div>
</div>`
const html = expressHtml(LogisticCode, MarkDestination, PackageName, Sender, Receiver, Onecode, OrderCode);
if (typeof CLODOP === "undefined") {
alert("系统检测出你没有启动打印设备或者端口号设置错误!!");
return;
}
LODOP.SET_PRINTER_INDEXA(Number(printerValue));
LODOP.ADD_PRINT_HTM(0, 0, "100%", "100%", html);
if (MODE) {
LODOP[MODE]();
}
}
render() {
const buttonObj = {
border: 'none',
borderRadius: '2px',
background: '#e0e0e0',
color: 'inherit',
display: 'inline-flex',
justifyContent: 'center',
alignItems: 'center',
whiteSpace: 'nowrap',
fontWeight: 500,
height: '32px',
padding: '0 15px',
fontSize: '14px',
outline: 0,
position: 'relative',
textDecoration: 'none',
transition: 'all .3s ease',
opacity: 1,
cursor: 'pointer',
backgroundColor: 'rgba(91,231,196)',
opacity: 1,
color: 'white',
boxShadow: '0 2px 2px 0 rgba(0,0,0,0.14), 0 1px 5px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.2)'
}
const selectObj={
border: "1px solid #d9d9d9",
padding: "4px 0"
}
const buttonElement =(
<div style={{ width: "100%" }}><button style={buttonObj} onClick={this.handlePrint}>测试打印</button></div>
)
const selectElement=(
<Fragment>
<select style={selectObj} ref={ref => this.selectRefs = ref} value={this.state.printerValue} size="1" onChange={this.handleChangePrinter}></select>
<select style={selectObj} ref={ref => this.pageRefs = ref} value={this.state.pageValue} size="1" onChange={this.handleChangePage}></select>
</Fragment>
)
const newProps = {
buttonElement,
selectElement
}
return <WrappedComponent {...newProps} />
}
}
return NewComponent
}
而需要增加打印按钮的页面只需要增加三行
import React from 'react';
import TypingPage from '../../component/TypingPage';
@TypingPage
class Test extends React.Component{
render(){
const styleObj={
justifyContent:"center",
alignItems:"center",
fontSize:50,
color:'skyblue',
width:'100%',
height:'100%',
backgroundColor:"blue",
}
return(
<div style={styleObj}>
<div style={{width:"100%"}}>Hello React</div>
{this.props.buttonElement}
{this.props.selectElement}
</div>
)
}
}
export default Test;
以后需要打印快递单功能的页面只需要增加这三行,且不需要做额外的修改。是不是very nice呢?
3.高阶函数生命周期函数探究
我们在高阶函数和被包裹组件内部打印2个典型生命周期函数componentDidMount
和componnetWillMount
,和渲染函数render
。
这样就会给实际运行的代码造成一个问题,如果在被包裹组件中有一个state
是我们在包裹组件中所需要的,那我们该如何进行传递呢?有的人会说可以将state
提升至高阶函数中,但是再现有项目中,如果有很多个state
被使用,而且state
的逻辑相当复杂,我们抽离也是需要时间的,而且代码会变得很混乱,不仅如此,假设提升至高阶函数中,实际工作中我们有很多个装饰器包裹在组件上:
//创建报错状态的类并导出实例化的对象
class GlobalState {
bindState(thz) {
this.thz = thz
}
getState() {
return this.thz
}
}
export default new GlobalState;
//在被包裹组件的componentDidMount中
componentDidMount(){
globalState.bindState(this);
}
//在需要使用的地方即可
globalState.getState()