如何在Gatsby项目的JavaScript代码中使用本地TXT文件填充体育赛事表格
如何在Gatsby中使用本地TXT文件数据渲染体育赛事表格?
问题描述
我用MechanicalSoup(Python库)爬取了学校网站的体育赛事数据,生成了两个TXT文件:upcomingFixturesData.txt和resultsFixturesData.txt,每行格式如下:
22/03/2022 4:15pm Hockey Hockey v SchoolName: U16 (a, leave at 3.00pm) 22/03/2022 10:00am Fives Fives National Championships: U18 (SchoolName, leave at 9.00am) 22/03/2022 4:00pm Netball Netball: Leavers v Common Room (h)
目前我的Gatsby组件里用的是模拟数据渲染表格,之前处理JSON格式的课程表时,我可以直接用map方法遍历渲染。现在想知道能不能用同样的map方法处理这两个TXT文件?如果不行,还有什么其他方法可以在JavaScript代码中使用这些本地TXT数据?
回答
当然可以用map方法处理这些TXT文件!不过首先得把纯文本格式的内容转换成结构化的JavaScript数组对象——毕竟map是用来遍历数组的,直接对字符串用不了。下面给你两种实用的方法,适配Gatsby的场景:
方法一:直接在组件中解析TXT文件(适合静态数据)
这种方法最简单,适合数据不常更新的情况,利用Webpack的资源加载能力直接导入TXT文件,然后解析成数组对象:
将TXT文件放在项目目录:比如放在
src/data/scraped/下(和你之前的JSON文件同目录)。编写解析函数:把TXT字符串转换成包含赛事信息的对象数组:
function parseFixtures(txtContent) { // 按行拆分,过滤空行 return txtContent.split('\n').filter(line => line.trim() !== '').map(line => { // 拆分每行:前三个元素是日期、时间、项目,剩余部分合并为赛事详情 const [date, time, sport, ...subtitleParts] = line.split(/\s+/); return { date, time, title: sport, subtitle: subtitleParts.join(' ') }; }); }
- 在组件中导入并渲染:
import upcomingTxt from '../../data/scraped/upcomingFixturesData.txt'; import resultsTxt from '../../data/scraped/resultsFixturesData.txt'; import Wrapper from './your-wrapper-component'; // 替换成你的实际组件 import RowWrapper from './your-row-wrapper-component'; import Row from './your-row-component'; import Description from './your-description-component'; export default function SportsSection() { const upcomingFixtures = parseFixtures(upcomingTxt); const resultsFixtures = parseFixtures(resultsTxt); return ( <Wrapper> {/* 即将到来的赛事 */} <RowWrapper> <Description>Upcoming Fixtures</Description> {upcomingFixtures.map((item, index) => ( <Row key={index} number={index + 1} title={item.title} subtitle={item.subtitle} time={item.time} /> ))} </RowWrapper> {/* 已结束的赛事结果 */} <RowWrapper> <Description>Recent Results</Description> {resultsFixtures.map((item, index) => ( <Row key={index} number={index + 1} title={item.title} subtitle={item.subtitle} time={item.time} /> ))} </RowWrapper> </Wrapper> ) }
方法二:用Gatsby的数据源系统处理(适合需要GraphQL或动态更新的场景)
如果你的赛事数据会定期更新,或者想利用Gatsby的GraphQL数据层,推荐用这种方法,在构建时解析TXT文件并生成可查询的节点:
- 安装依赖插件:
npm install gatsby-source-filesystem
- 配置
gatsby-config.js:让Gatsby读取TXT文件所在目录:
module.exports = { plugins: [ { resolve: `gatsby-source-filesystem`, options: { name: `fixtures`, path: `${__dirname}/src/data/scraped/`, }, }, ], }
- 编写
gatsby-node.js解析TXT文件:在构建时将TXT内容转换成结构化数据:
exports.onCreateNode = ({ node, actions }) => { const { createNodeField } = actions; // 只处理TXT文件 if (node.internal.type === `File` && node.extension === `txt`) { const fs = require('fs'); const content = fs.readFileSync(node.absolutePath, 'utf8'); // 判断是即将到来的赛事还是结果 const fixtureType = node.name.includes('upcoming') ? 'upcoming' : 'results'; // 解析内容成对象数组 const fixtures = content.split('\n').filter(line => line.trim() !== '').map(line => { const [date, time, sport, ...subtitleParts] = line.split(/\s+/); return { date, time, title: sport, subtitle: subtitleParts.join(' ') }; }); // 添加自定义字段到文件节点 createNodeField({ node, name: `fixtureType`, value: fixtureType, }); createNodeField({ node, name: `fixtures`, value: fixtures, }); } };
- 在组件中用GraphQL查询并渲染:
import { graphql } from 'gatsby'; import Wrapper from './your-wrapper-component'; import RowWrapper from './your-row-wrapper-component'; import Row from './your-row-component'; import Description from './your-description-component'; export const query = graphql` query FixturesQuery { upcoming: file(name: {eq: "upcomingFixturesData"}) { fields { fixtures { date time title subtitle } } } results: file(name: {eq: "resultsFixturesData"}) { fields { fixtures { date time title subtitle } } } } `; export default function SportsSection({ data }) { const upcomingFixtures = data.upcoming.fields.fixtures; const resultsFixtures = data.results.fields.fixtures; return ( <Wrapper> <RowWrapper> <Description>Upcoming Fixtures</Description> {upcomingFixtures.map((item, index) => ( <Row key={index} number={index + 1} title={item.title} subtitle={item.subtitle} time={item.time} /> ))} </RowWrapper> <RowWrapper> <Description>Recent Results</Description> {resultsFixtures.map((item, index) => ( <Row key={index} number={index + 1} title={item.title} subtitle={item.subtitle} time={item.time} /> ))} </RowWrapper> </Wrapper> ) }
注意事项
- 解析逻辑要根据你的TXT格式调整:如果后续赛事行的格式有变化(比如项目名称包含空格),需要修改
split的规则,比如用更精准的正则表达式拆分。 - 第一种方法适合小型、静态的数据;第二种方法更适合数据需要更新或需要和其他Gatsby数据源整合的场景。
内容的提问来源于stack exchange,提问作者roshpro
相关产品推荐
相关产品推荐

