使用 React-Pdf 打造在线简历生成器

前言

PDF 格式是使用30年前开发的文件格式,并且是打造使用最广泛的文件格式之一,我们最喜欢使用它作为简历、线简合同、历生发票、成器电子书等文件的使用格式,最主要的打造原因是文档格式可以兼容多种设备和应用程序,而且内容 100%保持相同的线简格式。

React-PDF 简介

React PDF 是历生一个使用 React 创建 PDF 文件的工具,支持在浏览器、成器移动设备和服务器上创建PDF文件。使用

可以用它们轻松地将内容呈现到文档中,打造我们可以使用 CSS 属性进行样式设置,线简使用 flexbox 进行布局,历生它支持渲染文本、成器图像、 svg 等等,香港云服务器详情可以参考官网

程序实现

今天我将使用 React-pdf 和 next.js 来构建一个在线简历生成器,先一起来看下效果

在线地址:https://cv.runjs.cool/

初始化项目

yarn create next-app --example with-ant-design next-resume

cd next-resume

yarn add @react-pdf/renderer

React-pdf 渲染需要一些额外的依赖项和 webpack5 配置。

yarn add process browserify-zlib stream-browserify util buffer assert

这一步骤是因为 React-pdf 构建在 PDFKit 的基础之上,在使用浏览器时需要使用两个 node.js API polyfill。而 webpack 5 不再包括自动引入 nodejs polyfill ,我们必须选择进入所有我们想要的 polyfill。为了做到这一点,我们必须为我们的项目添加一些依赖项:

在根目录下创建一个 next.config.js

module.exports = {

reactStrictMode: true,

webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {

config.resolve.fallback = {

...config.resolve.fallback,

module: "empty",

dgram: "empty",

dns: "mock",

fs: "empty",

http2: "empty",

net: "empty",

tls: "empty",

child_process: "empty",

process: require.resolve("process/browser"),

zlib: require.resolve("browserify-zlib"),

stream: require.resolve("stream-browserify"),

util: require.resolve("util"),

buffer: require.resolve("buffer"),

asset: require.resolve("assert"),

};

config.plugins.push(

new webpack.ProvidePlugin({

Buffer: ["buffer", "Buffer"],

process: "process/browser",

})

);

return config;

},

};

实现逻辑

新建在 App.js 将用户输入实时绑定到 state 中,然后时时渲染预览页面

import Preview from ./component/Preview

import React, { useState } from react

function App() {

const [profile, setProfile] = useState({

name: "狂奔滴小马",

about: "分享 Javascript 热门\n框架,探索 web 极致\n优化体验。",

email: "maqi1520@qq.com",

avatar:"https://p6-passport.byteacctimg.com/img/user-avatar/585e1491713363bc8f67d06c485e8260~300x300.image",

})

const handleChange = (name, value) => {

setProfile({ ...profile, [name]: value })

}

return (

style={ {

width: 100%,

height: 100vh,

display: flex,

}}

>

name=name

defaultValue={ profile.name}

onChange={ (e) => {

handleChange(e.target.name, e.target.value)

}}

/>

name=avatar

defaultValue={ profile.avatar}

onChange={ (e) => {

handleChange(e.target.name, e.target.value)

}}

/>

name=about

defaultValue={ profile.about}

onChange={ (e) => {

handleChange(e.target.name, e.target.value)

}}

/>

name=email

defaultValue={ profile.email}

onChange={ (e) => {

handleChange(e.target.name, e.target.value)

}}

/>

)

}

export default App

Preview.js 是页面的右侧部分,并嵌入我们将要创建的PDF文档。

另外我们还有 PDFDownloadLink,它可以用来下载 pdf 文件。

import React from react

import { Document, Page, PDFViewer, PDFDownloadLink } from @react-pdf/renderer

import LeftSection from ./LeftSection

import RightSection from ./RightSection

import styles from ../styles

const Preview = ({ profile }) => {

return (

showToolbar={ false}

style={ {

width: 100%,

height: 95%,

}}

>

document={

fileName=somename.pdf

>

{ ({ loading }) => (loading ? Loading document... : Download now!)}

)

}

// 创建文档组件

const Template = ({ profile }) => {

return (

)

}

export default Preview

我们可以直接设置 PDF 为 A4 纸尺寸。

import { StyleSheet } from @react-pdf/renderer

export default StyleSheet.create({

page: {

display: flex,

flexDirection: row,

},

section_right: {

margin: 10,

padding: 10,

paddingTop: 20,

width: 75%,

},

section_left: {

width: 25%,

height: 100%,

backgroundColor: #084c41,

},

profile_container: {

display: flex,

flexDirection: column,

alignItems: center,

marginTop: 20,

marginBottom: 20px,

height: 150,

},

name_text: {

paddingTop: 10px,

paddingBottom: 5px,

fontSize: 14px,

fontWeight: 900,

color: white,

}

})

通过 StyleSheet.create 创建 JavaScript 样式表

LeftSection.js 代码展示

import { View, Text, Image, } from @react-pdf/renderer

import styles from ../styles

export const Profile = ({ profile }) => {

return (

style={ {

justifyContent: center,

}}

>

{ profile.name}

{ profile.about}

)

}

const LeftSection = ({ profile }) => {

return (

)

}

export default LeftSection

也可以直接写内联样式控制 PDF 内的样式。但是站群服务器不支持 float 浮动属性,具体大家可以看官网

遇到问题

本以为这样就可以完成,没想到还有一个巨坑,不支持中文,中文在 pdf 中会显示乱码, 通过 issue 找到了答案

import { StyleSheet, Font } from "@react-pdf/renderer";

Font.register({

family: "Alibaba-PuHuiTi-Light",

src: "/Alibaba-PuHuiTi-Light.ttf",

});

export const styles = StyleSheet.create({

page: {

fontFamily: "Alibaba-PuHuiTi-Light",

flexDirection: "row",

display: "flex",

...

},

})

然后就可以显示中文字体了。这边我下载了阿里巴巴普惠体。

重构

以上是一个简易版的实现,通过上面的代码示例,你应该至少看懂了原理,为了让整个简历数据丰富,我使用了antd 来实现丰富的表单列表。使用 react context 来管理我们的数据。下面展示下目录结构:

├── components

│ ├── app

│ │ └── index.tsx

│ ├── editor

│ │ ├── FormCreator.tsx

│ │ ├── conifg.js

│ │ └── index.tsx

│ ├── icon

│ │ └── index.tsx

│ └── preview

│ ├── avatar.tsx

│ ├── awardList.tsx

│ ├── educationList.tsx

│ ├── index.tsx

│ ├── profile.tsx

│ ├── projectList.tsx

│ ├── skillList.tsx

│ ├── style.ts

│ └── workExpList.tsx

├── context

│ └── resumeContext.ts

├── hooks

│ └── useResume

│ └── index.ts

├── pages

│ ├── _app.tsx

│ ├── api

│ │ └── hello.js

│ └── index.tsx

└── styles

├── logo.png

└── globals.css

部署

最后我使用 vercel 部署并且绑定自定义域名

体验地址 https://cv.runjs.cool/

以上就是本文全部内容,希望这篇文章对大家有所帮助,也可以参考我往期的文章或者在评论区交流你的想法和心得,欢迎一起探索前端。

参考资料

[1]官网: https://react-pdf.org/

[2]issue: https://github.com/diegomura/react-pdf/issues/267

[3]dev.to: https://dev.to/przpiw/react-pdf-rendering-4g7b

[4]devtool: https://cv.devtool.tech/app

源码下载
滇ICP备2023000592号-31