Bonny

Bonny 查看完整档案

绵阳编辑西南科技大学  |  软件工程 编辑  |  填写所在公司/组织 null.null 编辑
编辑

无他,唯手熟尔。
停更
csdn:https://blog.csdn.net/Bonny722

个人动态

Bonny 赞了问题 · 2019-03-18

解决前端替换不可见字符

前端如何用正则替换不可见字符

例如:

const str = '1111168‬3'
console.log(str.length) // 9

在8和3之间存在一个不可见字符,在java中可以通过str.replaceAll('\\p{Cf}','')替换掉,但是前端的str.replace不行,求大佬给一个可用正则
参考链接:https://my.oschina.net/sfshin...
图片描述

关注 1 回答 1

Bonny 关注了用户 · 2019-03-18

赵栩彬 @crabapple

愿,你在遭受打击时,记起你的珍贵,抵抗恶意;
愿,你在迷茫时,坚信你的珍贵,爱你所爱,行你所行;
愿,晚风微扬时,听从你心,无问西东.

关注 182

Bonny 评论了文章 · 2019-02-16

GitHub pages + Hexo 搭建自己的个人博客

hexo是一个非常简单简洁的博客系统,因为不喜欢wordpress的臃肿然后就转Hexo。

这是我自己搭建好的博客

第一步:配置GitHub pages

首先需要一个GitHub账号
然后可以
具体可参照官方教程

第二步:安装node.js

下载安装包

安装的时候选择一下路径就可以了,其他就可以直接点下一步。

现在使用

node -v

以及

npm -v

可以查看到node以及npm的版本
因为npm比较慢,可以安装cnpm替代之后的npm命令。

安装cnpm

npm install -g cnpm --registry=https://registry.npm.taobao.org

第三步:现在安装Hexo

 cnpm install -g hexo-cli

进入clone下来的目录
执行

hexo init blog

然后进入刚刚创建目录

cd blog

可以看到这个目录

├── _config.yml
├── package.json
├── scaffolds
├── source
|   ├── _drafts
|   └── _posts
└── themes

执行

cnpm install

之后执行

hexo clean
hexo g
hexo s

然后打开本地的localhost:4000就可以看到博客的样子了。
打开配置文件_config.yml
改变下面的地方
clipboard.png

修改文件时冒号后面要跟一个空格

repo修改为clone的地址,可以是ssh也可以https的clone地址。
然后执行

hexo d
如果报错 ERROR Deployer not found: git
先执行cnpm install hexo-deployer-git --save

提交过会儿之后就可以访问到了。

其他

1、常用操作

新建一篇文章:

hexo new post 文章名字

使用Markdown编辑后就可以看到了。

hexo clean  清理缓存

hexo generate 进行渲染 简写 hexo g

hexo server 部署到本地(调试使用) 简写 hexo s。然后浏览器输入 http://localhost:4000

调试完毕后使用 hexo deploy 简写为 hexo d来部署到git服务器。

2、改变主题

这是官方的主题网站
将主题clone到你的theme,在配置文件中

clipboard.png

将theme改变为你下载的主题名称
然后编译,运行,发布。

3、解析域名

第一步域名解析:

需要一个域名,然后在解析的时候选择记录类型为CNAME

如图
clipboard.png

记录值填你的github的主页网址
添加两个解析,主机记录有两个@和www

解析完之后需要等一段时间,可以在控制台ping你的域名,如果成功了就解析成功了。

第二步:github上配置你的域名

然后在public目录下添加CNAME这个文件
内容为你的域名

然后清除缓存,编译,部署。

由于使用的主题不一样,更多的个性化,使用next主题的可以参考官方网址

查看原文

Bonny 回答了问题 · 2019-01-23

在阿里云上买来的服务器要怎么样才能用上啊

使用Xshell或者其他ssh连接工具。

关注 5 回答 4

Bonny 发布了文章 · 2019-01-20

Python的virtualenv使用

virtualenv为应用提供了隔离的Python运行环境,解决了不同应用间多版本的冲突问题。

安装virtualenv

pip3 install virtualenv

使用virtualenv

$ virtualenv [OPTIONS] DEST_DIR
选项:
--version 显示当前版本号。
-h, --help 显示帮助信息。
-v, --verbose 显示详细信息。
-q, --quiet 不显示详细信息。
-p PYTHON_EXE 指定所用的python解析器的版本
比如 --python=python2.5 就使用2.5版本的解析器创建新的隔离环境。 
默认使用的是当前系统安装(/usr/bin/python)的python解析器
--clear  清空非root用户的安装,并重头开始创建隔离环境。
--no-site-packages  默认,令隔离环境不能访问系统全局的site-packages目录。
--system-site-packages  令隔离环境可以访问系统全局的site-packages目录。

可以使用

virtualenv --no-site-packages venv

创建一个干净的虚拟环境,与原来的全局packages的隔绝。

进入虚拟环境

在Posix系统(*nix/BSD)中,用法如下:

source venv/bin/activate

在win中,直接执行Scripts目录下的activate:

.\venv\Scripts\activate

进入后在命令行前面会出现(venv)

退出虚拟环境

在Posix系统(*nix/BSD)中:

deactivate

win:

deactivate.bat

常用命令

记录安装的第三方模块

pip freeze > requirements.txt

安装txt文件里所记录的所有第三方模块

pip install -r requirements.txt

在编译器中配置虚拟环境

pyCharm

在file-setting-project-Project interpreter 中进行配置

VScode

在usersetting中的用户设置中设置:

clipboard.png

查看原文

赞 1 收藏 2 评论 0

Bonny 发布了文章 · 2019-01-16

《JavaScript设计模式》阅读笔记_part2

JavaScript设计模式阅读

更多文章查看本专栏

设计模式第一篇:创建型设计模式

1、简单工厂模式

简单工厂模式:又叫静态工厂方法,有一个工厂对象决定创建某一种产品对象类的实例。主要用于创建同一类对象。

根据现有的需求选择不同的东西。

// 简单的工厂模式
var redBall = function () {
    console.log('redBall')
};
var greenBall = function () {
    console.log('greenBall')
};
var blackBall = function () {
    console.log('blackBall')
};
var blueBall = function () {
    console.log('blueBall')
};

//工厂函数
var ballFactory = function (type) {
    switch (type) {
        case 'red':
            return new redBall();
            break;
        case 'green':
            return new greenBall();
            break;
        case 'black':
            return new blackBall();
            break;
        case 'blue':
            return new blueBall();
            break;

    }
}

通过一个工厂产生多个同类的,或者有相同属性但是也存在差异的产品。

function createBook(name,time,type) {
    var t = new Object();
    t.name = name;
    t.time = time;
    t.type = type;
    return t;
}

function createBall(type,text) {
    var t = new Object();
    t.content = text;
    t.show = function () {
        // do something
    }
    switch (type) {
        case 'red':
            // different Part
            break;
        case 'green':
            // different Part
            break;
        case 'black':
            // different Part
            break;
        case 'blue':
            // different Part
            break;
    }
}

和类的区别:类是将初始的东西给你,然后你自己去对相应的需求进行添加实例方法。而工厂是根据你需要的方法直接生成好给你。好处,如果有大量相同的含有特殊功能的实例存在,可以通过简单工厂增加复用性。

核心:根据情况的不同选择不同的情况进行处理,像是一个封装型的'if else'。

2、工厂方法模式

工厂方法模式:又称为工厂模式,也叫虚拟构造器模式或者多态工厂模式。

它属于类创建型模式。通过对产品类的抽象使其创建业务,只要负责用于创建多类的实例。
将实际创建对象的工作推迟到了子类当中。

//  类的安全模式
var Factory = function (type, content) {
    if(this instanceof  Factory){
        return new this[type](content);
    }else{
        return new Factory(type, content);
    }
};
//  创建不同类型基类的实现
Factory.prototype={
    Java:function (content) {
        this.content = content;
    },
    PHP:function (content) {
        this.content = content;
    },
    Python:function (content) {
        this.content = content;
    },
    JavaScript:function (content) {
        this.content = content;
    },
}

3、抽象工厂模式

通过对类的工厂抽象使其业务用于对产品类簇的创建,而不负责创建某一类产品的实例。

用于产生类簇。

创建一个类,类里面拥有许多抽象的类,抽象的类定义了同类的类的结构。在使用的时候将抽象的类进行继承。

/**
 * 实现subType类对工厂类中的superType类型的抽象类的继承
 * @param subType 要继承的类
 * @param superType 工厂类中的抽象类type
 */
const VehicleFactory = function(subType, superType) {
    if (typeof VehicleFactory[superType] === 'function') {
        function F() {
            this.type = '车辆'
        }
        F.prototype = new VehicleFactory[superType]()
        subType.constructor = subType
        subType.prototype = new F()                // 因为子类subType不仅需要继承superType对应的类的原型方法,还要继承其对象属性
    } else throw new Error('不存在该抽象类')
}

VehicleFactory.Car = function() {
    this.type = 'car'
}
VehicleFactory.Car.prototype = {
    getPrice: function() {
        return new Error('抽象方法不可使用')
    },
    getSpeed: function() {
        return new Error('抽象方法不可使用')
    }
}

const BMW = function(price, speed) {
    this.price = price
    this.speed = speed
}
VehicleFactory(BMW, 'Car')        // 继承Car抽象类
BMW.prototype.getPrice = function() {        // 覆写getPrice方法
    console.log(`BWM price is ${this.price}`)
}
BMW.prototype.getSpeed = function() {
    console.log(`BWM speed is ${this.speed}`)
}

const baomai5 = new BMW(30, 99)
// baomai5.getPrice()                          // BWM price is 30
// baomai5 instanceof VehicleFactory.Car       // true

4、建造者模式

将一个复杂对象的构建层与其表示层相互分离,同样的构造过程可采用不同的表示。

关注产生过程,将对象的创建分为模块化创建,自定义度变高。

建造一个电脑:

//  构建基本主体
const basicComputer = function () {

}
basicComputer.prototype = {
    //  自定义的一些原型方法
}
//  构建CPU模块
const cpu = function (type) {
    this.type = type;
}
cpu.prototype = {
    //  自定义的一些原型方法
}
//  构建显卡模块
const graphicsCard  = function (type) {
    this.type = type;
}
graphicsCard.prototype = {
    //  自定义的一些原型方法
}
//  构建屏幕模块
const screen = function (type) {
    this.type = type;
}
screen.prototype = {
    //  自定义的一些原型方法
}

const computer = function () {
    const t = new basicComputer();
    t.cpu = new cpu();
    t.graphicsCard = new graphicsCard();
    t.screen = new screen();
    return t;
}

5、原型模式

用原型实例指向创建对象的类,使用与创建新的对象的类共享原型对象的类型以及方法。

基于继承,将复杂的放置在函数中,简单的共同的放置到一个构造函数中。

在使用的时候可以对原型进行拓展。

代码与继承类似,但是核心就是将简单的共有的放置到构造函数中,与类的思想类似。

6、单例模式

只允许实例化一次的类。在使用的时候可以用于创建代码库,创建命名空间。

单例模式实现代码库,产生命名空间,一次只能实例化一个。

//  一个命名空间
const A = {
    fun_1: {
        fun_1_1:function () {
            //  do something
        },
    },
    fun_2: {
        //  do something

    },
    fun_3:function () {
        //  do something

    }
}
//  空间类可为一个代码块,也可以为更多一层次的代码库(命名空间)
查看原文

赞 0 收藏 0 评论 0

Bonny 发布了文章 · 2019-01-11

安装Docker

用设置 Docker 的镜像仓库并从中进行安装

前期准备

更新包

 $ sudo apt-get update

安装软件包,以允许 apt 通过 HTTPS 使用镜像仓库:

 $ sudo apt-get install \
     apt-transport-https \
     ca-certificates \
     curl \
     software-properties-common

添加 Docker 的官方 GPG 密钥:

 $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

验证密钥是否为:9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88

 $ sudo apt-key fingerprint 0EBFCD88

设置 stable 镜像仓库,不同的处理器架构不同,详情参见官网,我使用的:

$ sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

开始安装

更新包

 $ sudo apt-get update

安装最新版本的 Docker CE

 $ sudo apt-get install docker-ce

安装特定版本的 Docker CE

输出可用版本

 $ apt-cache madison docker-ce

选择特定版本

VERSION为版本号
 $ sudo apt-get install docker-ce=<VERSION>

检验安装

sudo docker run hello-world

输出一下信息为正常:

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/
查看原文

赞 1 收藏 1 评论 0

Bonny 发布了文章 · 2019-01-10

React实现打印功能

一、需求分析:

环境:react,antd,antd-pro
将选中的数据进行打印,可以自定义分页的大小。
由于打印的列等多个因素,导致如果写成组件在使用的时候依旧会改变源码,所以采用了写成页面的方式,

二、实现需求:

1、数据传值

进行传值的时候,刚开始使用的是在通过this.props.location进行传值,但是这样数据被写死了,导致再次进入页面的时候无法更新打印的值。
最后采用了一个全局的model进行实现的传值。

2、表格生成

分为四部分进行生成,分别是标题、表头、表格、表尾。其中表头,表尾因为需求的原因写死。
以下为代码:

createTitle = (title)=>(
  <div>
    <h1 style={styleObj.title}>{title}</h1>
  </div>
)

createHeader = (headerData)=>{
  headerData = [
    {
      orderID:'订单编号',
      value:'P201901020002',
    },{
      people:'采购人员',
      value:'xxx',
    },{
      time:'采购时间',
      value:'2019年01月01日',
    }
  ];
  return (
    <table>
      <tbody style={styleObj.header}>
      <tr>
        <th>订单编号:</th>
        <th colSpan="7">
          <input style={styleObj.printInput} value="P201901020002" />
        </th>
      </tr>
      <tr>
        <th>采购员:</th>
        <th colSpan="7">
          <input style={styleObj.printInput} value="xxx" />
        </th>
        <th>采购时间:</th>
        <th colSpan="7">
          <input style={styleObj.printInput} value="2019年01月01日" />
        </th>
      </tr>
      </tbody>
    </table>
  )
}

createForm = (printCol,printData)=>(
  <table style={styleObj.printTable}>
    <tbody>
    {
      (
        <tr style={styleObj.printTableTr}>
          {printCol.map(item=><th style={{...styleObj[item.key],...styleObj.printTableTh}}><div>{item.name}</div></th>)}
        </tr>
      )
    }
    {
      printData.map(item=> (
          <tr style={styleObj.printTableTr}>
            {Object.keys(item).map(i => <th style={styleObj.printTableTh}>{item[i]}</th>)}
          </tr>
        )
      )
    }
    </tbody>
  </table>
)

createFooter = (footerData)=>{
  return (
    <table>
      <tbody style={styleObj.footer}>
      <tr>
        <th>供应商(签字)</th>
        <th>
          <div style={styleObj.footerSpace} />
        </th>
        <th colSpan="4">
          <input style={styleObj.printInputFooter} />
        </th>
        <th>库管员(签字)</th>
        <th>
          <div style={styleObj.footerSpace} />
        </th>
        <th colSpan="4">
          <input style={styleObj.printInputFooter} />
        </th>
        <th>{`第${footerData.current}页`}</th>
        <th>{`共${footerData.total}页`}</th>
      </tr>
      </tbody>
    </table>
  )
}
createPrintArea = (printCol)=>{
  const {printGroupData} = this.state;
  return (
    printGroupData.map((item,index)=>{
      if(item.length){
        return (
          <div style={styleObj.printArea}>
            {this.createTitle('xxxxxxx公司xxx单')}
            {this.createHeader('asd')}
            {this.createForm(printCol,item)}
            {this.createFooter({current:index+1,total:printGroupData.length})}
          </div>
        )
      }
    })
  )
}

最主要的是CSS的调整,因为之后的打印需求将所有的CSS内联:
以下为css:

export const styleObj = {
  printArea:{
    width: '500px',
    fontSize: '12px',
    align:'center'
  },
  printInput:{
    fontWeight:'bold',
    border: 'none',
  },
  title:{
    textAlign: 'center',
    fontSize: '15px',
    fontWeight: '700',
  },
  header:{
    fontWeight:'bold',
    fontSize: '12px',
  },
  printTable:{
    fontSize: '12px',
    fontWeight: '700',
    color: 'black',
    border: '1px black',
    borderCollapse: 'collapse',
    textAlign: 'center',
  },
  printTableTh:{
    padding: '4px',
    border: '1px solid black',
    textAlign: 'center',
  },
  printTableTr:{
    textAlign:'center',
    padding: '4px',
    border: '1px solid black',
  },
  number:{
    width: '60px',
  },
  goodsName:{
    width: '180px',
  },
  unitName:{
    width: '75px',
  },
  specifications:{
    width: '90px',
  },
  goodsType:{
    width: '90px',
  },
  footer:{
    fontSize:'12px',
  },
  footerSpace:{
    width: '20px',
    display: 'block',
  },
  printInputFooter:{
    fontWeight:'bold',
    border:'none',
    width: '85px',
  },
};

3、实现分页

分页即将数据进行分割,然后每次生成表格的时候将分割后的每个表格数据依次传入表格生成函数,从而生成全部表格。
分页函数:

//传入的数据为:分页的大小,需要分页的数据。
page = (pageNumber,printData)=>{
  const printDataBack = printData.concat();
  const printGroupData = [];
  while(printDataBack.length >= pageNumber){
    let tempGroup = [];
    tempGroup = printDataBack.splice(0,pageNumber);
    printGroupData.push(tempGroup);
  }
  if(printDataBack.length){
    printGroupData.push(printDataBack);
  }
  printGroupData.forEach((item)=>{
    item.forEach((i,index)=>{
      i.number = index+1;
    })
  });
  return printGroupData;
}

注意:解构出来的数据是引用,需要进行备份。
设置一个input框以及一个按钮,input框用于输入分页的数字,再点击按钮以及第一次进入页面的时候进行分页。

4、实现打印

实现方法一(不推荐):
直接在本页面进行刷新

优点:css不用内嵌。
缺点:导致本页面刷新,某些数据丢失。

实现方法:直接获取到需要打印的区域,然后将本页面的innerHTML设置为获取的区域,然后调用系统的print,最后调用reload

代码:

print = () => {
    window.document.body.innerHTML = window.document.getElementById('billDetails').innerHTML;  
    window.print(); 
    window.location.reload();
}
实现方法二:
打开一个页面进行打印

优点:打印不在关乎本页面的业务
缺点:CSS需要内联
代码:

handlePrint = () => {
  const win = window.open('','printwindow');
  win.document.write(window.document.getElementById('printArea').innerHTML);
  win.print();
  win.close();
}

三、完整代码

以下为完整代码:
index.js

import React, { PureComponent } from 'react';
import { connect } from 'dva';
import {
  Row,
  Button,
  Col,
  Card,
  Form,
  message,
  InputNumber,
} from 'antd';
import PageHeaderWrapper from '@/components/PageHeaderWrapper';
import {styleObj} from './style';


@Form.create()
@connect(({ print }) => ({
  print,
}))
class PrintTable extends PureComponent {
  state = {
    printData:[],
    printCol:[],
    pageNumber:10,
    printGroupData:[],
  }

  componentDidMount() {
    const printCol = [
      {
        key:'number',
        name:'序号',
      },{
        key:'goodsName',
        name:'商品名称',
      },{
        key:'goodsType',
        name:'商品类型',
      },{
        key:'unitName',
        name:'单位',
      },{
        key:'specifications',
        name:'规格',
      }];
    const printData = [];
    const { pageNumber } = this.state;
    const { print:{ payload:{formPrintData} } } = this.props;
    formPrintData.forEach((i,index)=>{
      const colData = {};
      printCol.forEach(j=>{
        colData[j.key] = i[j.key];
      })
      colData.number = index+1;
      printData.push(colData);
    });
    const printGroupData = this.page(pageNumber,printData);
    this.setState({
      printData,
      printCol,
      printGroupData,
    })
  }

  componentWillReceiveProps(nextProps){
    const printCol = [
      {
        key:'number',
        name:'序号',
      },{
        key:'goodsName',
        name:'商品名称',
      },{
        key:'goodsType',
        name:'商品类型',
      },{
        key:'unitName',
        name:'单位',
      },{
        key:'specifications',
        name:'规格',
      }];
    const printData = [];
    const { pageNumber } = this.state;
    const { print:{ payload:{formPrintData} } } = nextProps;
    formPrintData.forEach((i,index)=>{
      const colData = {};
      printCol.forEach(j=>{
        colData[j.key] = i[j.key];
      })
      colData.number = index+1;
      printData.push(colData);
    });
    const printGroupData = this.page(pageNumber,printData);
    this.setState({
      printData,
      printCol,
      printGroupData,
    })
  }

  createTitle = (title)=>(
    <div>
      <h1 style={styleObj.title}>{title}</h1>
    </div>
    )

  createHeader = (headerData)=>{
    headerData = [
      {
        orderID:'订单编号',
        value:'P201901020002',
      },{
        people:'采购人员',
        value:'xxx',
      },{
        time:'采购时间',
        value:'2019年01月01日',
      }
    ];
    return (
      <table>
        <tbody style={styleObj.header}>
          <tr>
            <th>订单编号:</th>
            <th colSpan="7">
              <input style={styleObj.printInput} value="P201901020002" />
            </th>
          </tr>
          <tr>
            <th>采购员:</th>
            <th colSpan="7">
              <input style={styleObj.printInput} value="xxx" />
            </th>
            <th>采购时间:</th>
            <th colSpan="7">
              <input style={styleObj.printInput} value="2019年01月01日" />
            </th>
          </tr>
        </tbody>
      </table>
    )
  }

  createForm = (printCol,printData)=>(
    <table style={styleObj.printTable}>
      <tbody>
        {
          (
            <tr style={styleObj.printTableTr}>
              {printCol.map(item=><th style={{...styleObj[item.key],...styleObj.printTableTh}}><div>{item.name}</div></th>)}
            </tr>
          )
        }
        {
          printData.map(item=> (
            <tr style={styleObj.printTableTr}>
              {Object.keys(item).map(i => <th style={styleObj.printTableTh}>{item[i]}</th>)}
            </tr>
            )
          )
        }
      </tbody>
    </table>
    )

  createFooter = (footerData)=>{
    return (
      <table>
        <tbody style={styleObj.footer}>
          <tr>
            <th>供应商(签字)</th>
            <th>
              <div style={styleObj.footerSpace} />
            </th>
            <th colSpan="4">
              <input style={styleObj.printInputFooter} />
            </th>
            <th>库管员(签字)</th>
            <th>
              <div style={styleObj.footerSpace} />
            </th>
            <th colSpan="4">
              <input style={styleObj.printInputFooter} />
            </th>
            <th>{`第${footerData.current}页`}</th>
            <th>{`共${footerData.total}页`}</th>
          </tr>
        </tbody>
      </table>
    )
  }

  handlePrint = () => {
    const win = window.open('','printwindow');
    win.document.write(window.document.getElementById('printArea').innerHTML);
    win.print();
    win.close();
  }

  createPrintArea = (printCol)=>{
    const {printGroupData} = this.state;
    return (
      printGroupData.map((item,index)=>{
        if(item.length){
          return (
            <div style={styleObj.printArea}>
              {this.createTitle('xxxxxxx公司xxx单')}
              {this.createHeader('asd')}
              {this.createForm(printCol,item)}
              {this.createFooter({current:index+1,total:printGroupData.length})}
            </div>
          )
        }
      })
    )
  }

  handlePage = ()=>{
    const { pageNumber, printData } = this.state;
    if(pageNumber <= 0){
      message.warning('输出正确的分页');
      return;
    }
    this.setState({
      printGroupData:this.page(pageNumber, printData)
    })
  }

  page = (pageNumber,printData)=>{
    const printDataBack = printData.concat();
    const printGroupData = [];
    while(printDataBack.length >= pageNumber){
      let tempGroup = [];
      tempGroup = printDataBack.splice(0,pageNumber);
      printGroupData.push(tempGroup);
    }
    if(printDataBack.length){
      printGroupData.push(printDataBack);
    }
    printGroupData.forEach((item)=>{
      item.forEach((i,index)=>{
        i.number = index+1;
      })
    });
    return printGroupData;
  }

  onChange = (value)=>{
    this.setState({
      pageNumber:value,
    })
  }

  render() {
    const { printCol, printData } = this.state;
    return (
      <PageHeaderWrapper title="查询表格">
        <Card>
          <Row>
            <Col span={6}>
              <Row>
                <Col span={12}>
                  <InputNumber onChange={this.onChange} placeholder='输入自定义分页数量' style={{width:'100%'}}/>
                </Col>
                <Button onClick={this.handlePage}>确认分页</Button>
              </Row>
              <Row>
                <Button onClick={this.handlePrint} type='primary'>打印</Button>
              </Row>
            </Col>
            <Col span={12}>
              <div id='printArea'>
                <div style={styleObj.printArea}>
                  {printCol.length&&printData.length? this.createPrintArea(printCol):null}
                </div>
              </div>
            </Col>
          </Row>
        </Card>
      </PageHeaderWrapper>
    );
  }
}

export default PrintTable;

style.js

export const styleObj = {
  printArea:{
    width: '500px',
    fontSize: '12px',
    align:'center'
  },
  printInput:{
    fontWeight:'bold',
    border: 'none',
  },
  title:{
    textAlign: 'center',
    fontSize: '15px',
    fontWeight: '700',
  },
  header:{
    fontWeight:'bold',
    fontSize: '12px',
  },
  printTable:{
    fontSize: '12px',
    fontWeight: '700',
    color: 'black',
    border: '1px black',
    borderCollapse: 'collapse',
    textAlign: 'center',
  },
  printTableTh:{
    padding: '4px',
    border: '1px solid black',
    textAlign: 'center',
  },
  printTableTr:{
    textAlign:'center',
    padding: '4px',
    border: '1px solid black',
  },
  number:{
    width: '60px',
  },
  goodsName:{
    width: '180px',
  },
  unitName:{
    width: '75px',
  },
  specifications:{
    width: '90px',
  },
  goodsType:{
    width: '90px',
  },
  footer:{
    fontSize:'12px',
  },
  footerSpace:{
    width: '20px',
    display: 'block',
  },
  printInputFooter:{
    fontWeight:'bold',
    border:'none',
    width: '85px',
  },
};
查看原文

赞 2 收藏 1 评论 2

Bonny 回答了问题 · 2019-01-10

echarts如何设置 显示几条数据?

为啥不在设置数据的时候就只设置10条数据喃

关注 2 回答 2

Bonny 发布了文章 · 2019-01-10

react下实现一个PDF展示组件

简介:在react的antd-pro的框架下展示本地的PDF文件

效果图:

clipboard.png

一、插件选取。

听说过大名鼎鼎的PDF.js,但是因为是在react框架下,所以选取了两个可行的插件

两个插件都是对PDF进行的封装。两个插件都进行了尝试,相对而言react-pdf功能更强大并且文档也比较清晰,但是使用也会相对复杂一点。最后使用的是react-pdf-js这个插件。

二、展示选择的文件。

react-pdf-js

第一步:展示一个本地文档。

按照官方的文档:

render() {
  let pagination = null;
  if (this.state.pages) {
    pagination = this.renderPagination(this.state.page, this.state.pages);
  }
  return (
    <div>
      <PDF
        file="test.pdf"
        onDocumentComplete={this.onDocumentComplete}
        page={this.state.page}
      />
      {pagination}
    </div>
  )
}

注意:官方文档没有任何说明。此处的file是一个require过来的文件。
例子:要加载一个'E:\1.pdf',那么应该那么配置:

const PDFTest = require('E:\\1.pdf');
render() {
  let pagination = null;
  if (this.state.pages) {
    pagination = this.renderPagination(this.state.page, this.state.pages);
  }
  return (
    <div>
      <PDF
        file={PDFTest}
        onDocumentComplete={this.onDocumentComplete}
        page={this.state.page}
      />
      {pagination}
    </div>
  )
}

第二步:根据文件选择框更改文件。

这一步被卡住过,刚开始想的是根据选择的文件然后获取文件的实际地址然后运用require去获取文件,但是实现的时候发现浏览器的安全策略无法让浏览器获取文件的真实路径。
但是!我们可以通过创建一个URL对象去获取文件的一个blob。使用window.URL.createObjectURL创建一个file文件,并且react-pdf-js可以直接接受一个这样子的文件。
部分代码如下:

handleButtonOnChange = e =>{
  if (e.currentTarget.files.length === 0) return;
  const url = window.URL.createObjectURL(e.currentTarget.files[0]);
  this.setState({
    pdfTest: {
      key:url,
      file:url,
    },
  })
}
createPDF = () =>{
  const { pageNumber, numPages, pdfTest } = this.state;
  if(!pdfTest) return;
  return(
    <div>
      <div className={style.pdfContainer}>
        <PDF
          key={pdfTest.key}
          file={pdfTest.file}
          onDocumentComplete={this.onDocumentComplete}
          page={pageNumber}
          className={style.pdfView}
          width='300px'
        />
      </div>
      <p style={{float:'right'}}>第 {pageNumber} 页  共 {numPages} 页</p>
    </div>
  )
}
render() {
  return (
    <div id='PDFViewer'>
      <input id='id' type="file" style={{width:'200px',height:'35px'}} accept=".pdf" onChange={this.handleButtonOnChange} />
      {this.createPDF()}
    </div>
  );
}

此处还有一个坑,就是key这个值。在文档中没有提到这个值,并且在源代码中也没有怎么出现这个值。这个key值应该是标识每个文件的一个唯一标识,当key值不同的时候会重新渲染canvas。

以下做法不推荐:
在之前我没发现这个之前,通过修改源码的这个地方改为:

componentWillReceiveProps(newProps) {
  const {
    page,
    scale,
    file:oldfile,
    onDocumentComplete,
    cMapUrl,
    cMapPacked,
  } = this.props;
  const { pdf } = this.state;
  const { file:newfile } = newProps;
  if(newfile !== oldfile){
    PdfJsLib.GlobalWorkerOptions.workerSrc = '//cdnjs.cloudflare.com/ajax/libs/pdf.js/2.0.943/pdf.worker.js';
    PdfJsLib.getDocument({ url: newfile, cMapUrl, cMapPacked }).then((newPdf) => {
      this.setState({ pdf:newPdf });
      if (onDocumentComplete) {
        onDocumentComplete(newPdf._pdfInfo.numPages); // eslint-disable-line
      }
      pdf.getPage(page).then(p => this.drawPDF(p));
    });
  }else{
    if (newProps.page !== page) {
      pdf.getPage(newProps.page).then(p => this.drawPDF(p));
    }
    if (newProps.scale !== scale) {
      pdf.getPage(newProps.page).then(p => this.drawPDF(p));
    }
  }
}

手动实现了这个功能,但是这个判定方法存在一些问题,只有再加入一个变量去判断才会完善,就完全和他的key这个值一样,但是知道key值之后就没有再对源码进行修改了。

第三笔:其他功能。

翻页以及跳页:

handleTurnPage = e =>{
  const { pageNumber, numPages, turnPageNumber } = this.state;
  if(!numPages){
    message.warning('请先选择PDF文件');
    return;
  }
  let newPageNumber = pageNumber;
  switch (e.target.id) {
    case 'pageUp':
      newPageNumber -= 1;
      if(newPageNumber <= 0){
        message.warning('已经是第一页');
        return;
      }
      break;
    case 'pageDown':
      newPageNumber += 1;
      if(newPageNumber > numPages){
        message.warning('已经是最后一页');
        return;
      }
      break;
    case 'numberPage':
      if(!turnPageNumber){
        message.warning('请先输入数字');
        return;
      }else if(turnPageNumber <= 0||turnPageNumber > numPages){
        message.warning('请输入在页面范围内的数字');
        return;
      }
      newPageNumber = turnPageNumber;
      break;
    default:
      break;
  }
  this.setState({
    pageNumber:newPageNumber,
  })
}
render() {
  return (
    <div id='PDFViewer'>
      <input id='id' type="file" style={{width:'200px',height:'35px'}} accept=".pdf" onChange={this.handleButtonOnChange} />
      <div style={{float:'right'}}>
        <InputNumber onChange={this.onPageNumberInputChange} style={{width:'150px'}} placeholder='输入需要跳转的页' />
        <Button onClick={this.handleTurnPage} id="numberPage">确认跳转</Button>
        <Button onClick={this.handleTurnPage} id="pageUp">上一页</Button>
        <Button onClick={this.handleTurnPage} id="pageDown">下一页</Button>
      </div>
      {this.createPDF()}
    </div>
  );
}

完整代码:GitHub

react-pdf

这个插件的功能很强大,但是使用就相对而言比较复杂。官方的复杂demo

由于最后使用的是另外的一个插件。这里就只写一下踩坑记录。

1、file参数。

在这里file这个参数和react-pdf-js的不一样,在require的时候都是一样的,但是在转换的时候不用创建URL对象,直接将input里面的file传过去即可。并且不需要key。
例子:

handleButtonOnChange = e =>{
  if (e.currentTarget.files.length === 0) return;
  this.setState({
    pdfTest: {
      file:e.currentTarget.files[0],
    },
  })
}

2、不显示text layers

PDF存在一个问题无法选择里面的文字以及链接,但是PDF.js通过在里面添加一层文本层用于辅助选取,但是在这个插件里面会存在一个重影,导致文字显示效果不佳,如图:

clipboard.png

在官方文档中提到使用SVG可以解决这个问题,但是SVG选择出来是乱码。所以在使用的时候希望屏蔽掉text layer,在文档中也有提到,在page中设置。

以上是所有内容。

查看原文

赞 2 收藏 2 评论 1

认证与成就

  • 获得 31 次点赞
  • 获得 3 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 3 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2018-07-19
个人主页被 723 人浏览