使用 Vue3、Node.js、MySQL、Electron 和 Express 实现用户登录、文章管理和截屏功能

在现代 Web 开发中,前后端分离的架构已经成为主流。本文将详细介绍如何使用 Vue3、Node.js、MySQL、Electron 和 Express 实现一个完整的用户登录、文章管理和截屏功能的应用。我们将从项目的初始化开始,逐步实现各个功能模块,并提供详细的代码示例。

项目初始化

前端:Vue3

首先,我们使用 Vue CLI 创建一个新的 Vue3 项目:

bash 复制代码
npm install -g @vue/cli
vue create vue-electron-app
cd vue-electron-app

选择默认配置或根据需要进行自定义配置。

后端:Node.js 和 Express

在项目根目录下创建一个新的文件夹 server,并在其中初始化一个新的 Node.js 项目:

bash 复制代码
mkdir server
cd server
npm init -y
npm install express mysql body-parser cors

创建 server.js 文件并设置基本的 Express 服务器:

javascript 复制代码
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const app = express();
const port = 3000;

app.use(cors());
app.use(bodyParser.json());

app.listen(port, () => {
  console.log(`Server running on port ${port}`);
});

数据库:MySQL

创建一个新的 MySQL 数据库和表:

sql 复制代码
CREATE DATABASE vue_electron_app;

USE vue_electron_app;

CREATE TABLE users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  username VARCHAR(255) NOT NULL,
  password VARCHAR(255) NOT NULL
);

CREATE TABLE articles (
  id INT AUTO_INCREMENT PRIMARY KEY,
  title VARCHAR(255) NOT NULL,
  content TEXT NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

实现用户登录功能

后端:用户登录 API

server 文件夹中创建一个新的文件 auth.js,并实现用户注册和登录功能:

javascript 复制代码
const express = require('express');
const router = express.Router();
const mysql = require('mysql');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');

const db = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: 'password',
  database: 'vue_electron_app'
});

router.post('/register', (req, res) => {
  const { username, password } = req.body;
  const hashedPassword = bcrypt.hashSync(password, 10);

  db.query('INSERT INTO users (username, password) VALUES (?, ?)', [username, hashedPassword], (err, result) => {
    if (err) return res.status(500).send(err);
    res.status(201).send('User registered');
  });
});

router.post('/login', (req, res) => {
  const { username, password } = req.body;

  db.query('SELECT * FROM users WHERE username = ?', [username], (err, results) => {
    if (err) return res.status(500).send(err);
    if (results.length === 0) return res.status(404).send('User not found');

    const user = results[0];
    const isPasswordValid = bcrypt.compareSync(password, user.password);

    if (!isPasswordValid) return res.status(401).send('Invalid password');

    const token = jwt.sign({ id: user.id }, 'secret_key', { expiresIn: '1h' });
    res.status(200).send({ token });
  });
});

module.exports = router;

server.js 中引入并使用该路由:

javascript 复制代码
const authRoutes = require('./auth');
app.use('/auth', authRoutes);

前端:用户登录页面

在 Vue 项目中创建一个新的组件 Login.vue

vue 复制代码
<template>
  <div>
    <h2>Login</h2>
    <form @submit.prevent="login">
      <div>
        <label for="username">Username:</label>
        <input type="text" v-model="username" required />
      </div>
      <div>
        <label for="password">Password:</label>
        <input type="password" v-model="password" required />
      </div>
      <button type="submit">Login</button>
    </form>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      username: '',
      password: ''
    };
  },
  methods: {
    async login() {
      try {
        const response = await axios.post('http://localhost:3000/auth/login', {
          username: this.username,
          password: this.password
        });
        localStorage.setItem('token', response.data.token);
        this.$router.push('/dashboard');
      } catch (error) {
        console.error('Login failed:', error);
      }
    }
  }
};
</script>

实现文章管理功能

后端:文章管理 API

server 文件夹中创建一个新的文件 articles.js,并实现文章的 CRUD 操作:

javascript 复制代码
const express = require('express');
const router = express.Router();
const mysql = require('mysql');
const jwt = require('jsonwebtoken');

const db = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: 'password',
  database: 'vue_electron_app'
});

const authenticate = (req, res, next) => {
  const token = req.headers['authorization'];
  if (!token) return res.status(401).send('Access denied');

  jwt.verify(token, 'secret_key', (err, decoded) => {
    if (err) return res.status(401).send('Invalid token');
    req.userId = decoded.id;
    next();
  });
};

router.post('/articles', authenticate, (req, res) => {
  const { title, content } = req.body;

  db.query('INSERT INTO articles (title, content) VALUES (?, ?)', [title, content], (err, result) => {
    if (err) return res.status(500).send(err);
    res.status(201).send('Article created');
  });
});

router.get('/articles', authenticate, (req, res) => {
  db.query('SELECT * FROM articles', (err, results) => {
    if (err) return res.status(500).send(err);
    res.status(200).send(results);
  });
});

router.put('/articles/:id', authenticate, (req, res) => {
  const { id } = req.params;
  const { title, content } = req.body;

  db.query('UPDATE articles SET title = ?, content = ? WHERE id = ?', [title, content, id], (err, result) => {
    if (err) return res.status(500).send(err);
    res.status(200).send('Article updated');
  });
});

router.delete('/articles/:id', authenticate, (req, res) => {
  const { id } = req.params;

  db.query('DELETE FROM articles WHERE id = ?', [id], (err, result) => {
    if (err) return res.status(500).send(err);
    res.status(200).send('Article deleted');
  });
});

module.exports = router;

server.js 中引入并使用该路由:

javascript 复制代码
const articleRoutes = require('./articles');
app.use('/api', articleRoutes);

前端:文章管理页面

在 Vue 项目中创建一个新的组件 ArticleManager.vue

vue 复制代码
<template>
  <div>
    <h2>Article Manager</h2>
    <form @submit.prevent="createArticle">
      <div>
        <label for="title">Title:</label>
        <input type="text" v-model="title" required />
      </div>
      <div>
        <label for="content">Content:</label>
        <textarea v-model="content" required></textarea>
      </div>
      <button type="submit">Create Article</button>
    </form>
    <ul>
      <li v-for="article in articles" :key="article.id">
        <h3>{{ article.title }}</h3>
        <p>{{ article.content }}</p>
        <button @click="deleteArticle(article.id)">Delete</button>
        <button @click="editArticle(article)">Edit</button>
      </li>
    </ul>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      title: '',
      content: '',
      articles: []
    };
  },
  async created() {
    await this.fetchArticles();
  },
  methods: {
    async fetchArticles() {
      try {
        const response = await axios.get('http://localhost:3000/api/articles', {
          headers: { Authorization: localStorage.getItem('token') }
        });
        this.articles = response.data;
      } catch (error) {
        console.error('Failed to fetch articles:', error);
      }
    },
    async createArticle() {
      try {
        await axios.post('http://localhost:3000/api/articles', {
          title: this.title,
          content: this.content
        }, {
          headers: { Authorization: localStorage.getItem('token') }
        });
        this.title = '';
        this.content = '';
        await this.fetchArticles();
      } catch (error) {
        console.error('Failed to create article:', error);
      }
    },
    async deleteArticle(id) {
      try {
        await axios.delete(`http://localhost:3000/api/articles/${id}`, {
          headers: { Authorization: localStorage.getItem('token') }
        });
        await this.fetchArticles();
      } catch (error) {
        console.error('Failed to delete article:', error);
      }
    },
    editArticle(article) {
      this.title = article.title;
      this.content = article.content;
      // Implement update logic here
    }
  }
};
</script>

实现截屏功能

Electron:截屏功能

在项目根目录下安装 Electron:

bash 复制代码
npm install electron --save-dev

创建 main.js 文件并配置 Electron 主进程:

javascript 复制代码
const { app, BrowserWindow, ipcMain, desktopCapturer } = require('electron');
const path = require('path');

function createWindow() {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      contextIsolation: true,
      enableRemoteModule: false,
      nodeIntegration: false
    }
  });

  win.loadURL('http://localhost:8080');
}

app.whenReady().then(createWindow);

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', () => {
  if (BrowserWindow.getAllWindows().length === 0) {
    createWindow();
  }
});

ipcMain.handle('capture-screen', async () => {
  const sources = await desktopCapturer.getSources({ types: ['screen'] });
  return sources[0].thumbnail.toDataURL();
});

创建 preload.js 文件并配置预加载脚本:

javascript 复制代码
const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('electron', {
  captureScreen: () => ipcRenderer.invoke('capture-screen')
});

前端:截屏功能页面

在 Vue 项目中创建一个新的组件 ScreenCapture.vue

vue 复制代码
<template>
  <div>
    <h2>Screen Capture</h2>
    <button @click="captureScreen">Capture Screen</button>
    <img v-if="screenshot" :src="screenshot" alt="Screenshot" />
  </div>
</template>

<script>
export default {
  data() {
    return {
      screenshot: null
    };
  },
  methods: {
    async captureScreen() {
      try {
        this.screenshot = await window.electron.captureScreen();
      } catch (error) {
        console.error('Failed to capture screen:', error);
      }
    }
  }
};
</script>

结语

通过本文,我们详细介绍了如何使用 Vue3、Node.js、MySQL、Electron 和 Express 实现一个完整的用户登录、文章管理和截屏功能的应用。希望这篇文章能为你提供有价值的参考,帮助你更好地理解和实现前后端分离的应用开发。

如果你有任何问题或建议,欢迎在评论区留言讨论。Happy coding!

相关推荐
xp_fangfei1 小时前
MySQL第10讲--约束的介绍
数据库·mysql
qq31785355713 小时前
Mysql集群技术
android·数据库·mysql·adb
阿船·3 小时前
MySQL调优
数据库·mysql
计算机学姐3 小时前
基于SSM的超市管理系统
java·mysql·spring·tomcat·mybatis
haozihua3 小时前
Spring6梳理5——基于XML管理Bean环境搭建
java·开发语言·mysql
观止study4 小时前
【MySQL】Explain执行计划(十七)
数据库·mysql
一身傲骨@4 小时前
sql-labs56-60通关攻略
数据库·sql·mysql
橘橙黄又青5 小时前
MySQL数据库增删查改(基础)CRUD
数据库·mysql
ziyu_jia6 小时前
Mysql常见问题汇总【持续更新】
数据库·mysql
Potter6 小时前
Electron 项目实战 01:主进程与渲染进程通信
前端·javascript·electron