在本博客中,我们将使用 React.js(通过 Vite 设置)、Node.js(使用 Express)、SerpApi 从 Google Jobs 获取工作列表,并使用 Material-UI (MUI) 美化样式,来构建一个工作板网络应用。
完成本教程后,你将拥有一个功能性的求职网站,用户可以搜索工作并在上面查看从谷歌职位列表获取的结果。
这是该项目的演示版本:
前提
要跟上,你需要:
- 了解 React.js 和 Node.js 的基础知识
- 安装了 Node.js
- SerpApi 账户和 API 密钥
- 使用 Vite 进行项目配置
- 用 MUI 做样式
网站网址: https://serpapi.com/
可以选择创建一个账户或登录,如果您已经有账户的话
接下来,在左侧栏中点击API密钥部分,并选择生成新密钥、使用已有密钥或创建新密钥。
注:此处的Markdown链接格式似乎有误,正确的格式应该是[中文描述](链接)
。
这里是你项目的最终结构,包括服务器和客户端的样子看起来是这样的:
这里是最终的项目结构,包括服务器和客户端的结构。
职位板/
│
├── job-board-client/ # 前端 (React + Vite)
│ ├── node_modules/
│ ├── public/
│ ├── src/
│ │ ├── components/
│ │ │ ├── SearchBar.jsx # 搜索栏组件
│ │ │ ├── JobList.jsx # 职位列表组件
│ │ ├── App.jsx # 主组件
│ │ ├── main.jsx # 应用入口
│ │ └── index.css # 全局样式表
│ ├── .gitignore
│ ├── index.html # 主 HTML
│ ├── package.json # 依赖和脚本
│ ├── vite.config.js # Vite 配置
│ └── README.md
│
├── job-board-server/ # 后端 (Node.js + Express)
│ ├── node_modules/
│ ├── index.js # Express 服务器入口点
│ ├── .env # 环境变量 (例如 SERP_API_KEY)
│ ├── package.json # 依赖和脚本
│ ├── .gitignore
│ └── README.md
全屏/退出全屏
3. 创建一个job-board
根文件夹
在终端输入以下命令:
mkdir job-board
cd job-board/
全屏 退出全屏
4. 启动 React 前端应用(Vite + React.js)从用 Vite 创建 React 项目开始。
# a用 Vite 创建 React 项目
npm create vite@latest job-board-client --template react
# 进入项目目录
cd job-board-client
# 安装所有依赖项
npm install
点击进入全屏模式,点击退出全屏模式
安装 Material-UI(MUI)来设计样式,使用 axios 调用 API。
安装 MUI 核心和图标以进行样式设计
npm install axios @mui/material @emotion/react @emotion/styled @mui/icons-material
切换到全屏,或切换回窗口
5. 启动 Node.js 后端服务(Express)接下来,创建一个后端文件夹,并使用Express启动一个服务器。为了创建后端,你必须在job-board
目录中。你可以通过运行这个命令cd ..
来切换到上一级目录。
然后运行,
# 创建后端文件夹(创建一个用于存放后端代码的文件夹)
mkdir job-board-server
cd job-board-server
# 初始化一个Node.js项目
npm init -y
# 安装Express框架
npm install express cors axios dotenv
全屏 全屏退出
图片说明:此处应添加描述或说明,根据实际需要提供相应的中文描述。
index.js
,位于job-board-server 目录中。
在 job-board-server
文件夹里创建一个 index.js
文件,并创建一个返回工作列表的 API,来实现这个功能。
const express = require('express');
const cors = require('cors');
const axios = require('axios');
require('dotenv').config();
const app = express();
app.use(cors());
const PORT = process.env.PORT || 5000;
// 获取职位列表的端点
app.get('/api/jobs', async (req, res) => {
const { query } = req.query;
try {
const serpApiUrl = `https://serpapi.com/search.json?engine=google_jobs&q=${query}&api_key=${process.env.SERP_API_KEY}`;
const response = await axios.get(serpApiUrl);
res.json(response.data.jobs_results || []);
} catch (error) {
res.status(500).json({ error: 'Error fetching jobs' });
}
});
app.listen(PORT, () => {
console.log(`服务器运行在端口 ${PORT}`);
});
点击全屏 点击退出全屏
7. 设置环境变量在你的 job-board-server
目录中新建一个 .env
文件,并加入你的 SerpApi API 密钥。
SERP_API_KEY=你的serp_api_key_here
请将此处替换为您的实际API密钥
全屏 / 退出全屏
8. 前端:工作搜索界面(React + MUI)。在 React 项目中,创建一个允许用户搜索的组件,使用户可以输入搜索词并查看职位搜索结果。
在 src/components/SearchBar.jsx
文件中创建一个 SearchBar
组件。
import React, { useState } from 'react';
import { TextField, Button, CircularProgress } from '@mui/material';
const SearchBar = ({ onSearch, loading }) => {
const [query, setQuery] = useState('');
const handleSearch = () => {
if (query.trim()) {
onSearch(query);
}
};
return (
<div style={{ display: 'flex', justifyContent: 'center', marginTop: '20px' }}>
<TextField
label="职位搜索"
variant="outlined"
value={query}
onChange={(e) => setQuery(e.target.value)}
style={{ marginRight: '10px', width: '300px' }}
/>
<Button
variant="contained"
color="primary"
onClick={handleSearch}
disabled={loading}
>
{loading ? <CircularProgress size={24} /> : '搜索'}
</Button>
</div>
);
};
export default SearchBar;
全屏模式 退出全屏
在 src/components/JobList.jsx
文件里,创建一个 JobList
组件来显示工作列表。
import React from 'react';
import { Card, CardContent, CardActions, Typography, Button, Grid, CircularProgress, Box } from '@mui/material';
import { WorkOutline } from '@mui/icons-material';
const JobCard = ({ job }) => {
// 工作卡片组件
return (
<Card
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
// height: '100%',
boxShadow: '0 4px 8px #1976d2',
p: 2,
mt:3
}}>
<CardContent>
<Typography variant="h5" component="div">
{job.title}
</Typography>
<Typography sx={{ mb: 1.5 }} color="text.secondary">
{job.company_name} - {job.location}
</Typography>
<Typography variant="body2">
{job.description.slice(0, 150)}... {/* 预览描述的前150个字符 */}
</Typography>
</CardContent>
<CardActions>
<Button
sx={{
backgroundColor: '#1976d2',
color: '#fff',
'&:hover': {
backgroundColor: '#1565c0',
},
width: '100%',
}}
size="small" href={job.share_link} target="_blank" rel="noopener">
申请
</Button>
</CardActions>
</Card>
);
};
const JobList = ({ jobs, loading }) => {
// 工作列表组件
if (loading) {
return (
<Box display="flex" justifyContent="center" marginTop="20px">
<CircularProgress />
</Box>
);
}
if (jobs.length === 0) {
return (
<Box display="flex" justifyContent="center" alignItems="center" flexDirection="column" marginTop="20px">
<WorkOutline style={{ fontSize: 60, color: 'gray' }} />
<Typography variant="h6" color="text.secondary">
当前没有可申请的工作
</Typography>
</Box>
);
}
return (
<Grid container spacing={2}>
{jobs.map((job, index) => (
<Grid item xs={12} sm={6} md={4} key={index}>
<JobCard job={job} />
</Grid>
))}
</Grid>
);
};
export default JobList;
进入全屏,退出全屏
在 App.jsx 中,把所有东西整合起来。
import React, { useState } from 'react';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import SearchBar from './components/SearchBar';
import JobList from './components/JobList';
import axios from 'axios';
import { Container } from '@mui/material';
// 创建主题和提供主题
const theme = createTheme({
palette: {
primary: {
main: '#1976d2',
},
secondary: {
main: '#ff4081',
},
},
});
const App = () => {
const [jobs, setJobs] = useState([]);
const [loading, setLoading] = useState(false);
const handleSearch = async (query) => {
try {
setLoading(true);
const response = await axios.get(`http://localhost:5000/api/jobs`, {
params: { query }
});
setJobs(response.data);
setLoading(false);
} catch (error) {
console.error('获取职位列表失败:', error);
setLoading(false);
}
};
return (
<ThemeProvider theme={theme}>
<Container>
<SearchBar onSearch={handleSearch} loading={loading} />
<JobList jobs={jobs} loading={loading} />
</Container>
</ThemeProvider>
);
};
export default App;
全屏模式 退出全屏
9. 让我们开始启动服务器吧确保后端和前端都已经运行起来。
# 在job_board_server文件夹中运行
node index.js
切换到全屏模式,退出全屏
# 在job-board-client文件夹里:
npm run dev
全屏模式, 退出全屏
🎉 看,你现在已经成功打造了一个功能齐全的求职板网页应用!前端使用 React.js ⚛️ 构建,并用 Material-UI 🎨 进行美化设计,后端则使用 Node.js 🚀 和 Express 从 SerpApi 获取并提供职位列表。
这是一个很好的开始点,比如可以增加更多高级功能,例如按地点筛选📍,添加职位详情页面📄,甚至允许用户保存职位列表 💾。
这篇博客到这里就结束了!更多更新敬请期待,继续开发超棒的应用!💻✨
编程快乐!😊
共同學(xué)習(xí),寫下你的評論
評論加載中...
作者其他優(yōu)質(zhì)文章