前(vue3)后(node.js)端项目实战

1、前端技术栈:Vue 3 + Pinia + Vite + TypeScript + Element-Plus + Axios + Eslint + Sass + 其它…

  • Pinia 不需要 Vuex 自定义复杂的类型去支持 TypeScript,天生对类型推断就非常友好,并且对 Vue Devtool 的支持也非常好,被称为下一代 Vuex。
  • 学习 TypeScript 推荐视频(黑马程序员)

2、后端技术栈:Node.js + Koa 2 + MySQL + 其它…

项目演示地址

一、前端模块

前端的项目链接

小剧场

  • 报错
    GET http://127.0.0.1:5173/index/means1.png 404 (Not Found)
  • 报错截图
    示意图
  • 相关代码
    示意图
  • 问题
    在使用 v-for 循环渲染 <img /> 标签的时候,图片资源无法渲染。
  • 分析问题
  1. 可能是相对路径或者绝对路径问题导致图片资源加载失败。
  2. 可能是 vue 3 中对静态资源方式进入做了更改。
  3. 可能是其它问题。
  • 解决问题 排除了路径原因后;使用 require 导入图片,失败;最后使用 new URL 解决了问题。
  • 解决问题具体操作 如下图:写法绕了一些,但确实是解决了问题。在这里插入图片描述
    搞定 !

如何使用 element-plus 表单验证单个字段

示意图
以上是整个表单。
一般情况下,我们使用 element-plus 框架提供的 validate 方法会对整个表单都进行校验。
我希望在填写 “电话” 的时候,只使用校验规则的电话部分;在填写 “邮箱” 的时候,只使用校验规则的邮箱部分…
此时,我们可以使用 element-plus 提供的 validateField 方法,就能很好地解决问题。
同时,使用 clearValidate 方法可以达到清除部分校验规则的目的。
使用方法如下:

<el-form ref="ruleFormRef" :model="form" :rules="rules" label-width="110px" label-position="left">
	<el-form-item label="电话" prop="phone">
		<el-input v-model="form.phone" placeholder="请输入电话" />
        <el-button type="primary" @click="saveValue('phone', ruleFormRef)">保存</el-button>
        <el-button @click="inputValue('phone', 'close')">取消</el-button>
	</el-form-item>
	<el-form-item label="邮箱" class="item" prop="email">
		<el-input v-model="form.email" placeholder="请输入邮箱" />
        <el-button type="primary" @click="saveValue('email', ruleFormRef)">保存</el-button>
        <el-button @click="inputValue('email', 'close')">取消</el-button>
	</el-form-item>
</el-form>

<script lang="ts" setup>
import { reactive, ref } from "vue";
import type { FormInstance, FormRules } from "element-plus";

import { validateEmailNotEmpty, validatePhoneNotEmpty } from "@/utils/validator";

/* src/utils/validator.ts

export const validatePhoneNotEmpty = (rule: any, value: any, callback: any) => {
  if (value === "") {
    callback(new Error("Phone can not be empty"));
  } else {
    const reg =
      /^(0|86|17951)?(13[0-9]|15[012356789]|166|17[3678]|18[0-9]|14[57])[0-9]{8}$/;
    if (reg.test(value)) {
      // 正确
      callback();
    } else {
      // 错误
      callback(new Error("Wrong format! Please check and enter again"));
    }
  }
};

export const validateEmailNotEmpty = (rule: any, value: any, callback: any) => {
  if (value === "") {
    callback(new Error("Email can not be empty"));
  } else {
    const reg = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
    if (reg.test(value)) {
      // 正确
      callback();
    } else {
      // 错误
      callback(new Error("Wrong format! Please check and enter again"));
    }
  }
};
*/

const ruleFormRef = ref<FormInstance>();

const form = reactive({
	phone: "", // 电话
	email: "", // 邮箱
})

// 校验规则
const rules = reactive<FormRules>({
  phone: [
    {
      trigger: "blur",
      validator: validatePhoneNotEmpty,
    },
  ],
  email: [
    {
      trigger: "blur",
      validator: validateEmailNotEmpty,
    },
  ]
})

// 重置该表单项,并移除校验结果
const clearValidate = (formEl: FormInstance | undefined) => {
  if (!formEl) return;
  formEl.clearValidate();
};

// 保存
const saveValue = async (item: string, formEl: FormInstance | undefined) => {
  if (!formEl) return;
  if (item === "phone") {
    formEl.validateField("phone", () => null); // 对单一字段 phone 进行校验
  } else if (item === "email") {
    formEl.validateField("email", () => null); // 对单一字段 email 进行校验
  }
};

// 取消
const inputValue = (item: string, bool: string) => {
	if(item === "phone"){
		form.phone = "";
      	clearValidate(ruleFormRef.value); // 清除 phone 的校验规则
	} else if(item === "email"){
		form.email= "";
      	clearValidate(ruleFormRef.value); // 清除 email 的校验规则
	}
}
</script>

分割图

二、后端模块

后端的项目链接

小剧场

写多条 SQL 语句的时候,不能嵌套着用 *,否则在做数据合并时,如果字段重复,会报冲突的错误。
错误写法:示意图
推荐写法:
示意图


小剧场

数据库的时间是正确的,但是获取的时候,时间少了 8 小时。如图:
示意图
MySQL 时间正确,但是后端获取到的时间就是错误的,所以在后端连接 MySQL 的配置中加了 timezone: "08:00" 这样解决了后端获取时间错误的问题。搞定!在这里插入图片描述


MySQL 语句

多表合并查询

应用:(根据某相同字段)查询多个表中数据的集合。

语法:select 字段,字段,字段 from 表a,表b where 表a.字段=表b.字段

例:select username,password,phone,note from user,message where user.id=message.user_id

或:select * from user,message where user.id=message.user_id

分隔图
多表查询

1. 内联接

释义:A={ 1, 2, 3, 4, 5 } B= { 2, 5, 8 } A∩B = { 2, 5 }

sql 简单写法:

select a.1, a.2, b.1, b.2 
from A a, B b
where a.主键 = b.外键

A:表名
B:表名

sql 标准写法:

select a.1, a.2, b.1, b.2 
from A a 
inner join B b 
on a.主键 = b.外键

2. 外联接

左外联接
左边有的,右边没有的以 null 填充

sql 写法:

select ...
from ...
left join ...
on ...

例:

select S.studentName,R.subjectNo,R.student.Result
from student as s
left join result as R
on s.studentNo=R.studentNo;

右外联接
右边有的,左边没有的以 null 填充

3. 交叉联接(全联接 | 笛卡尔积)

释义:A={ A, B, C } B= { a, b } A*B = { Aa, Ab, Ba, Bb, Ca, Cb }

sql 简单写法:

select a.*, b.* 
from A a, B b

sql 标准写法:

select a.*, b.* 
from A a CROSS join B b

分割图

三、部署

此推荐和本文无直接关系:
番外:如何上线你的项目?这里提供了代码,可以快速体验项目上线的快感

云服务器上安装系统

示意图

点击这里可查看如何进入宝塔:

示意图

前后端项目部署到服务器

  1. 完成前端打包相关配置
    示意图

  2. 打包完成后会生成 dist 文件夹
    示意图

  3. 将打包后的 dist 文件夹整个粘贴到后端项目的 public 文件夹下

示意图

  1. 在服务器的 /www/wwwroot 目录下新建一个文件夹,用于存放项目文件
    示意图

  2. 将 【第3步提及到的】后端文件整个压缩,然后直接拖到【第4步提及到的】服务器新建的文件夹中,并解压(压缩包可删除)
    示意图

  3. 至此,前后端均已上传到服务器上。下面的操作,要将项目跑起来,在浏览器中可以在线查看

  4. 在服务器的宝塔操作面板上,添加 Node 项目 → 选择项目目录【第4步创建的】

示意图
8. 启动服务

示意图

  1. ip + 端口 即为项目的访问路径

示意图

示意图

  1. 完毕

连接服务器数据库

  1. 将本地的数据库导出
    示意图
  2. 导出到任意位置
    示意图

番外:导入本地 txt 文件到 MySQL 表中

  1. 在服务器的控制台中,在宝塔面板 → 数据库 中,添加数据库
    示意图

  2. 点击 phpMyAdmin 后,访问线上数据库
    示意图

  3. 导入
    示意图

  4. 选择刚刚导出到本地的 .sql 文件,执行
    示意图

  5. 稍等一会儿,就导入完毕了。

导入完毕后可能发会遇到一些报错,暂时不要理。

  1. 点击权限,选择所有人(不安全)
    示意图

  2. 在本地创建新连接
    在这里插入图片描述

  3. 对应输入信息后,如果测试连接成功,点击确定
    示意图

  4. 已在本地连接上了服务器上的数据库
    示意图

问题:部署到服务器上之前,在本地跑没有问题;打包部署到服务器上的时候,可以访问前端页面,但是一进行刷新操作,页面就会一片空白。

原因:前端路由配置有问题。
解决:调整前端的路由模式。
核心操作:修改 router 配置中的 createWebHistory 为 createWebHashHistory
示意图


问题:图片上传失败,并且在前端展示失败

解决办法:

  1. 在宝塔下载 Nginx → 点击设置 → 配置参数 → 保存
    示意图
		listen 8066; # 没有被占用的端口
        server_name localhost; # 固定 localhost
        index index.html index.htm index.php; # 不用改
        root  /www/wwwroot/koa2/public; # 服务器上的图片资源路径
        try_files $uri $uri/ /index.html; # 固定内容,没有请自行添加
  1. 重启 nginx 服务
    示意图
  2. 完毕后,以后的图片资源都可以在 :【1. 中 没有被占用的端口】/图片路径读取到图片资源。如:
  • 网站为:
    示意图
  • 头像为:
    示意图
  • 拼接起来,即可成功访问到服务器中的图片:
    示意图

要点:上传图片的到服务器时候,用的依旧是 api 接口的端口号;从服务器获取图片的时候,用的是 Nginx 配置中的端口号。


问题:隐藏域名后面的端口号

背景:绑定后域名,要加上端口号才能正常访问到网页。想要去除端口后,网页也能正常访问到。怎么优化?

示意图
方法:

  1. 在宝塔的网站模块,点击设置,配置一下
    示意图

80 端口是默认端口,默认不显示。访问到 80 端口时,代理到了 8088 端口,实现了去除域名后+端口才能访问网页的问题。

  1. 保存配置,重启下服务,即可!

示意图

项目演示地址
前端的项目链接 (⑅˃◡˂⑅) 记得在 github 点赞收藏哦!
后端的项目链接 (⑅˃◡˂⑅) 记得在 github 点赞收藏哦!

分割图

  • 6
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值