前(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 + 其它…

  • Koa 2 实现异步是通过 async/awaite,Koa 实现异步是通过 generator/yield,而 Express 实现异步是通过回调函数的方式。写 Node.js 建议使用 Koa2 > Koa > Express。
  • 学习 Koa 2 推荐文档(aka 老师) + 配套视频
    学习 Koa 2 推荐文档2(廖雪峰)

项目演示地址

一、前端模块

前端的项目链接

小剧场

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

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

前(vue3)后(node.js)端项目实战_第4张图片
以上是整个表单。
一般情况下,我们使用 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>

前(vue3)后(node.js)端项目实战_第5张图片

二、后端模块

后端的项目链接

小剧场

写多条 SQL 语句的时候,不能嵌套着用 *,否则在做数据合并时,如果字段重复,会报冲突的错误。
错误写法:前(vue3)后(node.js)端项目实战_第6张图片
推荐写法:
前(vue3)后(node.js)端项目实战_第7张图片


小剧场

数据库的时间是正确的,但是获取的时候,时间少了 8 小时。如图:
前(vue3)后(node.js)端项目实战_第8张图片
MySQL 时间正确,但是后端获取到的时间就是错误的,所以在后端连接 MySQL 的配置中加了 timezone: "08:00" 这样解决了后端获取时间错误的问题。搞定!前(vue3)后(node.js)端项目实战_第9张图片


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

前(vue3)后(node.js)端项目实战_第10张图片
多表查询

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

前(vue3)后(node.js)端项目实战_第11张图片

三、部署

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

云服务器上安装系统

前(vue3)后(node.js)端项目实战_第12张图片

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

前(vue3)后(node.js)端项目实战_第13张图片

前后端项目部署到服务器

  1. 完成前端打包相关配置
    前(vue3)后(node.js)端项目实战_第14张图片

  2. 打包完成后会生成 dist 文件夹
    前(vue3)后(node.js)端项目实战_第15张图片

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

前(vue3)后(node.js)端项目实战_第16张图片

  1. 在服务器的 /www/wwwroot 目录下新建一个文件夹,用于存放项目文件
    前(vue3)后(node.js)端项目实战_第17张图片

  2. 将 【第3步提及到的】后端文件整个压缩,然后直接拖到【第4步提及到的】服务器新建的文件夹中,并解压(压缩包可删除)
    前(vue3)后(node.js)端项目实战_第18张图片

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

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

前(vue3)后(node.js)端项目实战_第19张图片
8. 启动服务

前(vue3)后(node.js)端项目实战_第20张图片

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

前(vue3)后(node.js)端项目实战_第21张图片

前(vue3)后(node.js)端项目实战_第22张图片

  1. 完毕

连接服务器数据库

  1. 将本地的数据库导出
    前(vue3)后(node.js)端项目实战_第23张图片
  2. 导出到任意位置
    前(vue3)后(node.js)端项目实战_第24张图片

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

  1. 在服务器的控制台中,在宝塔面板 → 数据库 中,添加数据库
    前(vue3)后(node.js)端项目实战_第25张图片

  2. 点击 phpMyAdmin 后,访问线上数据库
    前(vue3)后(node.js)端项目实战_第26张图片

  3. 导入
    前(vue3)后(node.js)端项目实战_第27张图片

  4. 选择刚刚导出到本地的 .sql 文件,执行
    前(vue3)后(node.js)端项目实战_第28张图片

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

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

  1. 点击权限,选择所有人(不安全)
    前(vue3)后(node.js)端项目实战_第29张图片

  2. 在本地创建新连接
    前(vue3)后(node.js)端项目实战_第30张图片

  3. 对应输入信息后,如果测试连接成功,点击确定
    前(vue3)后(node.js)端项目实战_第31张图片

  4. 已在本地连接上了服务器上的数据库
    前(vue3)后(node.js)端项目实战_第32张图片

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

原因:前端路由配置有问题。
解决:调整前端的路由模式。
核心操作:修改 router 配置中的 createWebHistory 为 createWebHashHistory
前(vue3)后(node.js)端项目实战_第33张图片


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

解决办法:

  1. 在宝塔下载 Nginx → 点击设置 → 配置参数 → 保存
    前(vue3)后(node.js)端项目实战_第34张图片
		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 服务
    前(vue3)后(node.js)端项目实战_第35张图片
  2. 完毕后,以后的图片资源都可以在 :【1. 中 没有被占用的端口】/图片路径读取到图片资源。如:
  • 网站为:
    前(vue3)后(node.js)端项目实战_第36张图片
  • 头像为:
    示意图
  • 拼接起来,即可成功访问到服务器中的图片:
    前(vue3)后(node.js)端项目实战_第37张图片

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


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

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

前(vue3)后(node.js)端项目实战_第38张图片
方法:

  1. 在宝塔的网站模块,点击设置,配置一下
    前(vue3)后(node.js)端项目实战_第39张图片

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

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

前(vue3)后(node.js)端项目实战_第40张图片

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

前(vue3)后(node.js)端项目实战_第41张图片

你可能感兴趣的:(Vue,3.x,技术总结,javascript,typescript,node.js,mysql,vue3)