资讯详情

Vue与Node.js全栈开发房屋租赁系统实践

📅 2026/9/16 8:48:45 | 华诺云谱 👁 阅读
Vue与Node.js全栈开发房屋租赁系统实践
1. 项目背景与技术选型在当今数字化时代房屋租赁行业正经历着从传统线下模式向线上平台的转型。一个高效、易用的房屋租赁系统能够极大提升房东和租客的匹配效率降低交易成本。基于Vue和Node.js的全栈解决方案因其现代化的技术架构和良好的开发体验成为构建此类系统的理想选择。Vue.js作为前端框架的优势在于响应式数据绑定自动同步视图与数据模型组件化开发可复用的UI组件提升开发效率丰富的生态系统Vue Router、Vuex等官方库支持渐进式框架可根据需求灵活扩展功能Node.js在后端的价值体现在非阻塞I/O模型适合处理大量并发请求JavaScript全栈前后端语言统一降低开发成本NPM生态海量开源模块可供选择高性能V8引擎提供出色的执行效率2. 系统架构设计2.1 前端架构规划采用Vue CLI搭建项目基础结构主要模块划分src/ ├── assets/ # 静态资源 ├── components/ # 通用组件 │ ├── SearchBar.vue │ ├── HouseCard.vue │ └── Pagination.vue ├── views/ # 页面级组件 │ ├── Home.vue │ ├── List.vue │ └── Detail.vue ├── router/ # 路由配置 ├── store/ # Vuex状态管理 └── api/ # 接口封装关键配置示例vue.config.jsmodule.exports { devServer: { proxy: { /api: { target: http://localhost:3000, changeOrigin: true } } }, css: { loaderOptions: { scss: { additionalData: import ~/styles/variables.scss; } } } }2.2 后端服务设计基于Express的RESTful API设计const express require(express) const mongoose require(mongoose) const cors require(cors) const app express() // 中间件 app.use(cors()) app.use(express.json()) // 数据库连接 mongoose.connect(mongodb://localhost:27017/house-rental, { useNewUrlParser: true, useUnifiedTopology: true }) // 路由定义 app.use(/api/houses, require(./routes/houses)) app.use(/api/users, require(./routes/users)) // 错误处理 app.use((err, req, res, next) { console.error(err.stack) res.status(500).send(Server Error) }) const PORT process.env.PORT || 3000 app.listen(PORT, () console.log(Server running on port ${PORT}))3. 核心功能实现3.1 房源管理模块数据库模型设计Mongoose Schemaconst houseSchema new mongoose.Schema({ title: { type: String, required: true }, price: { type: Number, required: true }, area: { type: Number, required: true }, address: { province: String, city: String, district: String, detail: String }, facilities: [{ name: String, has: Boolean }], images: [String], publishDate: { type: Date, default: Date.now }, landlord: { type: mongoose.Schema.Types.ObjectId, ref: User } }) module.exports mongoose.model(House, houseSchema)前端表单组件关键代码template el-form :modelhouseForm :rulesrules refform el-form-item label房源标题 proptitle el-input v-modelhouseForm.title/el-input /el-form-item el-form-item label租金(元/月) propprice el-input-number v-modelhouseForm.price :min0/el-input-number /el-form-item el-form-item label面积(㎡) proparea el-input-number v-modelhouseForm.area :min0/el-input-number /el-form-item !-- 更多表单项... -- /el-form /template script export default { data() { return { houseForm: { title: , price: 0, area: 0, // 其他字段... }, rules: { title: [{ required: true, message: 请输入标题, trigger: blur }], // 其他验证规则... } } } } /script3.2 搜索与筛选功能Elasticsearch集成方案安装elasticsearch包npm install elastic/elasticsearch创建搜索服务const { Client } require(elastic/elasticsearch) const client new Client({ node: http://localhost:9200 }) async function searchHouses(query) { const { body } await client.search({ index: houses, body: { query: { bool: { must: [ { match: { title: query.keyword }}, { range: { price: { gte: query.minPrice || 0, lte: query.maxPrice || Number.MAX_SAFE_INTEGER } }} ] } } } }) return body.hits.hits.map(hit hit._source) }前端筛选组件实现template div classfilter-container el-input placeholder关键词 v-modelfilters.keyword/el-input el-slider v-modelpriceRange range :max10000 :step100 /el-slider el-checkbox-group v-modelfilters.facilities el-checkbox v-foritem in facilityOptions :keyitem.value :labelitem.value {{ item.label }} /el-checkbox /el-checkbox-group /div /template4. 高级功能实现4.1 地图集成高德地图接入步骤申请开发者Key安装AMap插件npm install amap/amap-jsapi-loader --save组件封装template div idmap-container/div /template script import AMapLoader from amap/amap-jsapi-loader export default { data() { return { map: null, markers: [] } }, mounted() { this.initMap() }, methods: { async initMap() { try { const AMap await AMapLoader.load({ key: your-amap-key, version: 2.0, plugins: [AMap.MarkerClusterer] }) this.map new AMap.Map(map-container, { zoom: 12, center: [116.397428, 39.90923] }) this.addMarkers(this.houses) } catch (error) { console.error(地图加载失败:, error) } }, addMarkers(houses) { // 清除旧标记 this.markers.forEach(marker marker.setMap(null)) this.markers [] // 添加新标记 houses.forEach(house { const marker new AMap.Marker({ position: new AMap.LngLat(house.longitude, house.latitude), title: house.title }) marker.setMap(this.map) this.markers.push(marker) }) } } } /script4.2 即时通讯功能基于Socket.IO的实现服务端设置const http require(http) const socketIO require(socket.io) const server http.createServer(app) const io socketIO(server, { cors: { origin: http://localhost:8080, methods: [GET, POST] } }) io.on(connection, socket { console.log(新用户连接) socket.on(join_room, roomId { socket.join(roomId) }) socket.on(send_message, ({ roomId, message }) { io.to(roomId).emit(receive_message, message) }) socket.on(disconnect, () { console.log(用户断开连接) }) })前端封装// src/utils/socket.js import io from socket.io-client let socket null export function connectSocket(token) { socket io(http://localhost:3000, { auth: { token } }) return socket } export function joinRoom(roomId) { if (socket) socket.emit(join_room, roomId) } export function sendMessage(roomId, message) { if (socket) socket.emit(send_message, { roomId, message }) } export function onMessageReceived(callback) { if (socket) socket.on(receive_message, callback) }5. 性能优化实践5.1 前端性能提升路由懒加载配置const routes [ { path: /, component: () import(/views/Home.vue) }, { path: /list, component: () import(/views/List.vue) } ]图片懒加载指令// main.js Vue.directive(lazy, { inserted(el, binding) { const observer new IntersectionObserver((entries) { entries.forEach(entry { if (entry.isIntersecting) { el.src binding.value observer.unobserve(el) } }) }) observer.observe(el) } })使用示例img v-lazyhouse.image alt房源图片5.2 后端性能优化数据库查询优化// 使用populate关联查询 House.find() .populate(landlord, name avatar) .lean() // 转换为普通JS对象 .exec() // 添加索引 houseSchema.index({ title: text, address.city: 1 })Redis缓存实现const redis require(redis) const client redis.createClient() async function getHousesWithCache() { const cacheKey houses:all return new Promise((resolve, reject) { client.get(cacheKey, async (err, data) { if (data) return resolve(JSON.parse(data)) const houses await House.find().lean() client.setex(cacheKey, 3600, JSON.stringify(houses)) resolve(houses) }) }) }6. 安全防护措施6.1 常见攻击防护XSS防护// 使用helmet中间件 app.use(helmet()) // 前端输入过滤 function sanitizeInput(input) { return input.replace(/[^]*?/gm, ) }CSRF防护// 使用csurf中间件 const csrf require(csurf) app.use(csrf({ cookie: true })) // 前端获取token axios.interceptors.request.use(config { if (csrfToken) { config.headers[X-CSRF-Token] csrfToken } return config })SQL注入防护// 使用参数化查询 House.find({ title: { $regex: new RegExp(keyword, i) } })6.2 认证与授权JWT认证实现const jwt require(jsonwebtoken) // 生成token function generateToken(user) { return jwt.sign( { id: user._id, role: user.role }, process.env.JWT_SECRET, { expiresIn: 7d } ) } // 验证中间件 function authMiddleware(req, res, next) { const token req.header(Authorization)?.replace(Bearer , ) if (!token) return res.status(401).send(Access denied) try { const decoded jwt.verify(token, process.env.JWT_SECRET) req.user decoded next() } catch (err) { res.status(400).send(Invalid token) } }RBAC权限控制// 角色定义 const ROLES { ADMIN: admin, LANDLORD: landlord, TENANT: tenant } // 权限中间件 function checkRole(requiredRole) { return (req, res, next) { if (req.user.role ! requiredRole) { return res.status(403).send(Forbidden) } next() } } // 路由使用示例 router.post(/houses, authMiddleware, checkRole(ROLES.LANDLORD), createHouse )7. 部署与监控7.1 生产环境部署Docker容器化方案# 前端Dockerfile FROM node:16 as build-stage WORKDIR /app COPY package*.json ./ RUN npm install COPY . . RUN npm run build FROM nginx:stable-alpine as production-stage COPY --frombuild-stage /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD [nginx, -g, daemon off;]Nginx配置示例server { listen 80; server_name yourdomain.com; location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; } location /api { proxy_pass http://backend:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }7.2 监控与日志ELK日志系统集成安装winston日志库npm install winston winston-elasticsearch日志配置const winston require(winston) const { ElasticsearchTransport } require(winston-elasticsearch) const esTransport new ElasticsearchTransport({ level: info, clientOpts: { node: http://localhost:9200 } }) const logger winston.createLogger({ transports: [ new winston.transports.Console(), esTransport ] }) // 使用示例 logger.info(Server started, { port: 3000 })性能监控使用PM2# 安装PM2 npm install pm2 -g # 启动应用并监控 pm2 start server.js --name house-rental --watch # 查看监控 pm2 monit8. 项目扩展方向8.1 移动端适配响应式设计实现// variables.scss $breakpoint-mobile: 768px; mixin mobile { media (max-width: $breakpoint-mobile) { content; } } // 使用示例 .house-card { width: 30%; include mobile { width: 100%; } }PWA支持// vue.config.js module.exports { pwa: { name: 房屋租赁系统, themeColor: #4DBA87, msTileColor: #000000, appleMobileWebAppCapable: yes, appleMobileWebAppStatusBarStyle: black, } }8.2 数据分析功能用户行为追踪// 前端埋点 export function trackEvent(category, action, label) { if (window.ga) { ga(send, event, category, action, label) } // 同时发送到后端 axios.post(/api/analytics, { category, action, label, timestamp: Date.now() }) } // 组件使用示例 mounted() { trackEvent(HouseDetail, view, this.houseId) }数据可视化template div classchart-container line-chart :chart-datapriceTrendData/line-chart /div /template script import { Line } from vue-chartjs export default { extends: Line, props: [chartData], mounted() { this.renderChart(this.chartData, { responsive: true, maintainAspectRatio: false }) } } /script9. 开发经验总结在实际开发过程中有几个关键点值得特别注意表单验证的完整性前端验证提供即时反馈后端验证确保数据安全使用共享验证规则保持一致性图片处理最佳实践// 图片上传处理 const sharp require(sharp) async function processImage(buffer) { return sharp(buffer) .resize(800, 600, { fit: inside }) .jpeg({ quality: 80 }) .toBuffer() }错误处理统一方案// 前端错误拦截 axios.interceptors.response.use( response response, error { if (error.response.status 401) { router.push(/login) } return Promise.reject(error) } ) // 后端错误分类 class AppError extends Error { constructor(message, statusCode) { super(message) this.statusCode statusCode this.isOperational true Error.captureStackTrace(this, this.constructor) } } // 使用示例 throw new AppError(房源不存在, 404)持续集成流程# .github/workflows/ci.yml name: CI Pipeline on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkoutv2 - uses: actions/setup-nodev2 with: node-version: 16 - run: npm install - run: npm test deploy: needs: test runs-on: ubuntu-latest if: github.ref refs/heads/main steps: - uses: actions/checkoutv2 - run: docker-compose up -d --build
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。