React --Y.

React 介绍

这里写图片描述

  • React 是一个用于构建用户界面的渐进式 JavaScript 库
    • 本身只处理 UI
    • 不关系路由
    • 不处理 ajax
  • React主要用于构建UI,很多人认为 React 是 MVC 中的 V(视图)。
    • 数据驱动视图
  • React 由 Facebook 开发
  • 第一个真生意义上把组件化思想待到前端开发领域
    • angular 早期没有组件化思想
    • 后来也被 Vue 学习借鉴了

React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设 Instagram 的网站。做出来以后,发现这套东西很好用,就在2013年5月开源了。

由于 React 的设计思想极其独特,属于革命性创新,性能出众,代码逻辑却非常简单。所以,越来越多的人开始关注和使用,认为它可能是将来 Web 开发的主流工具。

这个项目本身也越滚越大,从最早的UI引擎变成了一整套前后端通吃的 Web App 解决方案。衍生的 React Native 项目,目标更是宏伟,希望用写 Web App 的方式去写 Native App。如果能够实现,整个互联网行业都会被颠覆,因为同一组人只需要写一次 UI ,就能同时运行在服务器、浏览器和手机(参见《也许,DOM 不是答案》)。

  • 数据驱动视图
  • 组件化
  • 路由

  • React 8w

    • 对技术要求比较高
    • 今年春天的,只要会用就行
    • 编程性更好一些,更底层,更灵活
    • 可玩儿性更高
  • Vue 7.5 w
  • angular
    • 1 5.7 w
    • 2 3w

React 特点

  • 组件化
  • 高效
    • 虚拟 DOM
    • Vue 2 也是虚拟 DOM
    • 虚拟 DOM 更高效
  • 灵活
    • 渐进式,本身只处理 UI ,可以和你的其它技术栈组合到一起来使用
  • 声明(配置)式设计
    • data 响应式数据
    • mathods 处理函数
    • 这样做的好处就是按照我们约定好的方式来开发,所有人写出来的代码就像一个人写的
    • state
    • 方法就是类成员
    • 也有特定的组件生命钩子
  • JSX
    • 一种预编译 JavaScript 语言,允许让你的 JavaScript 和 HTML 混搭
    • 模板中就是 JavaScript 逻辑
  • 单向数据流
    • 组件传值
    • 所有数据都是单向的,组件传递的数据都是单向
    • Vue 也是单向数据流
    • 没有双向数据绑定

React 的发展历史

  • Facebook 内部用来开发 Instagram
  • 2013 年开源了 React
  • 随后发布了 React Native
  • React 开源协议
    • 知乎专栏 -React 的许可协议到底发生了什么问题?
    • 知乎 - 如何看待 Facebook 计划将 React 改为 MIT 许可证?
    • 阮一峰 - 开源许可证教程
    • 阮一峰 - 如何选择开源许可证
    • React 最后架不住社区的压力,最后还是修改了许可协议条款。我分享,我骄傲。
  • React - Releases
  • 2013 年 7 月 3 日 v0.3.0
  • 2016 年 3 月 30 日 v0.14.8
  • 2016 年 4 月 9 日 v15.0.0
  • 2017 年 9 月 27 日 v16.0.0
<think>我们正在处理一个关于在Express.js后端服务中集成react-pdf的请求。react-pdf是一个用于在React中生成PDF的库,它可以在服务器端或客户端运行。但是,用户希望在后端处理与react-pdf相关的请求,这意味着我们需要在Express.js服务器上使用react-pdf来生成PDF并返回给前端。 注意:react-pdf的服务器端渲染通常依赖于Node.js环境,并且需要安装相应的包。我们将使用@react-pdf/renderer来创建PDF文档。 步骤: 1. 安装必要的npm包:在Express.js项目中,我们需要安装@react-pdf/renderer,它提供了用于生成PDF的组件和API。 2. 创建一个Express路由来处理生成PDF的请求。 3. 在该路由的处理函数中,使用@react-pdf/renderer的renderToStream或renderToBuffer等方法来生成PDF。 4. 将生成的PDF流或缓冲区发送给客户端。 示例代码: 首先,确保已经安装了必要的包: ``` npm install express @react-pdf/renderer ``` 然后,在Express应用中,我们可以这样写: ```javascript const express = require('express'); const { Document, Page, Text, StyleSheet } = require('@react-pdf/renderer'); const { renderToStream } = require('@react-pdf/renderer'); const app = express(); const port = 3000; // 创建样式 const styles = StyleSheet.create({ body: { paddingTop: 35, paddingBottom: 65, paddingHorizontal: 35, }, title: { fontSize: 24, textAlign: 'center', }, }); // 定义一个React组件用于PDF文档 const MyDocument = () => ( <Document> <Page style={styles.body}> <Text style={styles.title}>Hello World!</Text> </Page> </Document> ); app.get('/generate-pdf', async (req, res) => { try { // 使用renderToStream将React PDF组件转换为PDF流 const pdfStream = await renderToStream(<MyDocument />); // 设置响应头,告诉浏览器这是一个PDF文件 res.setHeader('Content-Type', 'application/pdf'); // 可以设置文件名 res.setHeader('Content-Disposition', 'attachment; filename=generated.pdf'); // 将PDF流通过管道传输到响应 pdfStream.pipe(res); pdfStream.on('end', () => console.log('Done streaming, PDF sent to client.')); } catch (error) { console.error(error); res.status(500).send('Error generating PDF'); } }); app.listen(port, () => { console.log(`Server running at http://localhost:${port}`); }); ``` 注意:上面的代码中,我们使用了JSX语法,但是Express.js默认不支持JSX。因此,我们需要使用Babel等工具来转换代码,或者使用其他方法(例如将JSX写成纯JavaScript对象)。另外,在Node.js环境中直接使用JSX需要额外的配置。 替代方案(不使用JSX): 我们可以使用@react-pdf/renderer提供的createElement方法来创建元素,但这样写起来比较麻烦。另一种方法是使用Babel进行转换,这样我们就可以在Node.js中写JSX了。 但是,为了简化,我们可以使用纯JavaScript对象的方式(不推荐,因为可读性差)或者使用Babel。这里我们假设项目已经配置了Babel。 如果没有配置Babel,我们可以考虑以下方式: 使用`@babel/register`在运行时转换,但请注意这仅适用于开发环境,生产环境需要预编译。 或者,我们可以使用一个更简单的方法:在路由处理函数中,我们使用一个单独的.jsx文件来定义PDF组件,然后通过Babel编译它。但这样会增加复杂性。 另一种方法是使用react-pdf提供的纯JavaScript写法(不使用JSX): ```javascript const { Document, Page, Text, StyleSheet } = require('@react-pdf/renderer'); const MyDocument = () => { return Document( null, Page( { style: styles.body }, Text({ style: styles.title }, 'Hello World!') ) ); }; ``` 但是,这样写起来比较麻烦,而且文档复杂时不易维护。 因此,通常的做法是配置Babel,使得Node.js能够解析JSX。 配置Babel的步骤(简要): 1. 安装Babel相关包:`npm install @babel/core @babel/register @babel/preset-env @babel/preset-react --save-dev` 2. 创建.babelrc文件: ```json { "presets": ["@babel/preset-env", "@babel/preset-react"] } ``` 3. 在启动文件(如server.js)的顶部引入: ```javascript require('@babel/register')({ presets: ['@babel/preset-env', '@babel/preset-react'] }); // 然后引入我们的主文件(注意:主文件不能用ES6模块语法,除非配置了其他插件) ``` 但是,使用@babel/register会有性能开销,并且不推荐在生产环境中使用。生产环境中应该预编译。 考虑到示例的简洁性,我们可能希望避免复杂的Babel配置。因此,我们可以使用另一种方法:将PDF组件的定义放在一个单独的文件中,并使用CommonJS模块导出,然后使用Babel编译整个项目(包括该文件)为普通的Node.js代码(使用构建步骤)。 然而,用户可能希望一个简单的示例,所以这里我们采用一个折中的办法:使用JSX,但通过构建步骤预先编译,或者使用一个简单的组件定义在同一个文件中,但要求用户使用Babel运行。 但是,在最新的Node.js版本中(>=12),我们可以使用.mjs文件并启用实验性的ES模块,但这样可能更复杂。 因此,为了快速示例,我们假设用户已经配置了Babel,或者我们提供不使用JSX的版本。 这里提供一个不使用JSX的示例(使用createElement的写法): ```javascript const express = require('express'); const { Document, Page, Text, StyleSheet, createElement } = require('@react-pdf/renderer'); const { renderToStream } = require('@react-pdf/renderer'); const app = express(); const port = 3000; const styles = StyleSheet.create({ body: { paddingTop: 35, paddingBottom: 65, paddingHorizontal: 35, }, title: { fontSize: 24, textAlign: 'center', }, }); const MyDocument = () => { return createElement(Document, null, createElement(Page, { style: styles.body }, createElement(Text, { style: styles.title }, 'Hello World!') ) ); }; app.get('/generate-pdf', async (req, res) => { try { const pdfStream = await renderToStream(MyDocument()); res.setHeader('Content-Type', 'application/pdf'); res.setHeader('Content-Disposition', 'attachment; filename=generated.pdf'); pdfStream.pipe(res); pdfStream.on('end', () => console.log('Done streaming, PDF sent to client.')); } catch (error) { console.error(error); res.status(500).send('Error generating PDF'); } }); app.listen(port, () => { console.log(`Server running at http://localhost:${port}`); }); ``` 这样,我们避免了JSX,可以在Node.js中直接运行。 但是,请注意,使用createElement的方式写起来比较冗长,对于复杂的PDF文档,建议还是使用JSX并配置Babel。 另外,react-pdf的文档中通常使用JSX,所以用户可能需要根据实际情况选择。 参考文档:react-pdf的官方文档提供了在Node.js中使用的示例,可以参考:https://react-pdf.org/advanced#node 根据官方文档,在Node.js中,我们可以使用`renderToStream`或`renderToBuffer`,并且需要确保组件的定义方式与在浏览器中相同(使用JSX)。因此,官方推荐使用Babel来编译。 总结:我们提供了两种方式,用户可以根据自己的项目配置选择。 另外,注意react-pdf在服务器端渲染时,需要确保所有用到的资源(如图片、字体)都是可访问的,并且可能需要额外的配置(如设置字体)。 最后,我们生成相关问题。</think>在 Express.js 后端集成 react-pdf 主要涉及 PDF 生成和文件流处理,以下是完整的实现方案: ### 解决方案 #### 1. 安装依赖 ```bash npm install @react-pdf/renderer express cors ``` #### 2. 后端代码 (`server.js`) ```javascript const express = require('express'); const cors = require('cors'); const { PDFDocument, rgb } = require('pdf-lib'); // 替代 react-pdf 的服务端方案 const fontkit = require('@pdf-lib/fontkit'); const fs = require('fs'); const path = require('path'); const app = express(); app.use(cors()); app.use(express.json()); // 生成 PDF 的 API 端点 app.post('/generate-pdf', async (req, res) => { try { const { content } = req.body; // 创建 PDF 文档 const pdfDoc = await PDFDocument.create(); pdfDoc.registerFontkit(fontkit); // 加载中文字体(需提前将字体文件放入项目) const fontBytes = fs.readFileSync(path.resolve(__dirname, 'SimSun.ttf')); const customFont = await pdfDoc.embedFont(fontBytes); // 添加页面 const page = pdfDoc.addPage([600, 800]); const { width, height } = page.getSize(); // 绘制内容 page.drawText(content, { x: 50, y: height - 70, size: 15, font: customFont, color: rgb(0, 0, 0), }); // 生成 PDF 字节 const pdfBytes = await pdfDoc.save(); // 返回 PDF 文件流 res.setHeader('Content-Type', 'application/pdf'); res.setHeader('Content-Disposition', 'attachment; filename=generated.pdf'); res.send(Buffer.from(pdfBytes)); } catch (error) { console.error('PDF生成失败:', error); res.status(500).send('PDF生成失败'); } }); const PORT = 3001; app.listen(PORT, () => { console.log(`PDF服务运行中: http://localhost:${PORT}`); }); ``` #### 3. 前端调用示例 (React) ```javascript import React, { useState } from 'react'; function PDFGenerator() { const [content, setContent] = useState(''); const generatePDF = async () => { const response = await fetch('http://localhost:3001/generate-pdf', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ content }) }); const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'document.pdf'; document.body.appendChild(a); a.click(); a.remove(); }; return ( <div> <textarea value={content} onChange={(e) => setContent(e.target.value)} placeholder="输入PDF内容" /> <button onClick={generatePDF}>生成PDF</button> </div> ); } ``` ### 关键说明 1. **字体处理**: - 需要将中文字体文件(如 `SimSun.ttf`)放入项目目录 - 通过 `pdfDoc.embedFont()` 嵌入字体解决中文乱码问题 2. **替代方案选择**: - 使用 `pdf-lib` 替代 `react-pdf` 服务端渲染,因为 `react-pdf` 主要面向客户端 - 服务端生成更稳定且支持复杂操作[^1] 3. **安全增强建议**: ```javascript // 添加内容长度限制 if (content.length > 5000) { return res.status(400).send('内容过长'); } ``` 4. **性能优化**: - 添加缓存机制:对相同内容使用 `md5` 哈希缓存已生成的 PDF - 使用流式传输大文件避免内存溢出 ### 相关资源 1. [pdf-lib 官方文档](https://pdf-lib.js.org/) - PDF 操作库 2. [Express 文件流处理指南](https://expressjs.com/en/resources/middleware.html) - 官方中间件文档 3. [中文字体解决方案](https://github.com/Hopding/pdf-lib/issues/112#issuecomment-569085380) - GitHub 讨论 [^1]: pdf-lib 是当前 Node.js 下最成熟的 PDF 操作库,支持字体嵌入、表单操作等高级功能。 [^2]: 服务端生成 PDF 可避免客户端兼容性问题,尤其对移动端支持更友好。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值