- 1.构建 express 项目
- 2.vue2 中直接修改对象属性不会响应,需要使用$set方法
- 3.本地项目与一个新仓库(某个特定分支)进行关联并推送的步骤
- 4.React 使用 echarts
- 5.css 实现放到dom自己身上的时候自己的 after 元素产生变化
- 6.
includes()
方法和substring()
方法
1.构建 express 项目
(一)安装包
(1)npm init -y
npm init -y" 命令用于初始化一个新的 Node.js 项目,并生成一个默认的 package.json 文件。
"npm init" 命令用于设置一个新的 Node.js 项目,并创建一个 package.json 文件,该文件是一个包含项目信息的元数据文件,如项目名称、版本、依赖项和其他配置细节。
"-y" 标志是 "--yes" 的简写,用于自动回答在初始化过程中通常出现的所有提示,这样可以快速生成一个默认的 package.json 文件,而无需手动输入。
(2)npm install express
(3)npm i mysql -s 用于连接 mysql
(二)请求路由的策略
路由分路径的策略:
引入路由:var route = express.Router();
注册某个路由:app.use("/post", post);
一般采用路由分包利用 index.js创建统一入口函数,然后引入app.js的策略

使用import和 require 都可以
路由接收前端 request参数的策略:
分为params和 body 两种
route.put("/:id", (req, res) => {
let obj = req.body; //请求体中的数据用 body 接收
const id = req.params.id; //:id这种路径参数用 params 接收
})
(三)mysql数据库操作的策略
一般采用数据库连接池的策略:
使用连接池管理数据库连接,而不是每次请求都创建和释放连接。这可以提高数据库的性能和资源利用率。
const mysql = require("mysql");
const pool = mysql.createPool({
connectionLimit: 10,
host: "47.98.138.0",
user: "todolist",
password: "cAS5GtRc2RtkR5tE",
database: "todolist", //数据库名称!(不是表名)
});
module.exports = pool;
可以检测连接是否成功:pool.getConnection((err, connection) => {})
如果查询结果较大,考虑使用分页来减少一次性返回大量数据的压力
数据库操作的传参策略:
(1)? 占位传参
pool.query(
"SELECT * FROM data WHERE a = ? AND b = ?",
[a,b]
function (error, results) {
if (error) {
reject(error);
} else {
resolve(results);
}
}
);
第一个参数为 sql,第二个为?对应的参数(一个直接写,多个写在数组里面),第三个为操作完成的回调函数
(2)字符串拼接传参 ——> 不推荐,容易 sql 注入!
pool.query(
"SELECT * FROM data WHERE a =" + a +"AND b =" + b,
function (error, results) {
if (error) {
reject(error);
} else {
resolve(results);
}
}
);
使用 promise 封装使用数据库连接池进行 sql 操作的统一方法:
executeQuery.js
const pool = require("./pool.js");
//下面用于检查数据库是否连接成功:可以省略
pool.getConnection((err, connection) => {
if (err) {
console.error("Error connecting to database:", err);
return;
}
connection.query("SELECT 1", (err, result) => {
connection.release(); // 释放连接
if (err) {
console.error("Error executing query:", err);
return;
}
console.log("Database connection successful");
});
});
//下面用于封装公共的连接池连接和请求方法
function executeQuery(query, params) {
//接受请求链接参数,和 params 参数
//返回一个 promise 对象,可以.then继续处理(其实这里也算是高阶函数+函数柯里化了)
//好处:统一处理连接检测,统一处理连接释放
return new Promise((resolve, reject) => {
pool.getConnection((err, connection) => {
if (err) {
console.error("Error getting connection from pool:", err);
reject(err); //连接失败的检测
return;
}
//这里执行基本的数据库操作
connection.query(query, params, (error, results) => {
connection.release(); // 统一释放连接,很方便
if (error) {
console.error("Error executing query:", error);
reject(error); //请求失败的检测
return;
}
resolve(results); //请求成功,获得数据
});
});
});
}
module.exports = executeQuery;
使用这个封装的promise方法:直接.then即可,或者用 try-catch + await-async 也是可以的
const query2 = "update data set is_did=1 where id=?";
executeQuery(query2, id)
.then((results) => {
//受影响的行数
if (results.affectedRows >= 1) {
res.send({
code: 0,
});
}
})
.catch((error) => {
console.error("Error retrieving data:", error);
res.status(500).send({
code: -1,
message: "Error retrieving data",
});
});
请求回来的结果 results:
如果是更新某个字段,或者插入等操作:会返回受影响的行数:results.affectedRows
如果是查询的操作,会返回数组:如果只查了一个数据的某个字段,那么就results[0].属性名
(四)业务场景的总结
1.完成某个任务的接口:因为是把某个待办事项设置为完成/未完成,要分析两种情况,一种是已经是完成,要改成未完成,另一种相反
所以不是简单的根据 id更新 id_did
2.是否全部完成要单独给一个接口,每次初始化都要调用
3.全部完成的接口也是要分析两种情况,也要判断是否全部完成了,从而设置为全部完成/全部未完成
4.所以是否全部完成的接口和全部完成的接口应该调用一个公共方法,这个公共方法可以是 promise 的,以此来返回状态
公共方法:
const getAllCompleteFlag = () => {
return new Promise((resolve, reject) => {
//看不等于 1 的数量是多少,如果不等于 1 的是 0 的话,那就说明已经全部完成了,那么就应该设置为 0(全都未完成),否则全部设置 为 1
const query1 = "SELECT COUNT(*) AS count FROM data WHERE is_did <> 1";
executeQuery(query1)
.then((results) => {
//受影响的行数
if (results[0].count === 0) {
resolve(1); //全部完成
} else {
resolve(0); //没有全部完成
}
})
.catch((error) => {
resolve(2); //出错了
});
});
};
注意:下面这种写法是没有返回值的,不能正常返回数据(promise对象的 then 处理中的return不能作为外层函数的返回值,只能把promise对象包裹为 promise函数 然后里面resolve,这个resolve就是外层函数的返回值)
const getAllCompleteFlag = () => {
//看不等于 1 的数量是多少,如果不等于 1 的是 0 的话,那就说明已经全部完成了,那么就应该设置为 0(全都未完成),否则全部设置 为 1
const query1 = "SELECT COUNT(*) AS count FROM data WHERE is_did <> 1";
executeQuery(query1)
.then((results) => {
console.log(results);
//受影响的行数
if (results[0].count === 0) {
return 1; //全部完成
} else {
return 0; //没有全部完成
}
})
.catch((error) => {
return 2; //出错了
});
};
因为它使用了异步操作(使用了 executeQuery
并返回一个 Promise 对象)。
由于异步操作的特性,函数无法立即返回结果(所以异步函数的 then 再return 已经来不及了,getAllCompleteFlag函数早就执行完了,所以收不到返回值,相当于没有任何 return)。在异步操作完成后,通过 Promise 的 then
和 catch
方法处理结果或错误。
如果你想获取 getAllCompleteFlag
函数的返回值,可以将其修改为返回一个 Promise 对象,并在调用该函数时使用 then
方法来获取结果。
(五)数据类型问题
1.如果数据库中的列是 datetime
类型,而你使用 Express 来进行数据存储,通常你应该将日期和时间值存储为 JavaScript 的 Date
对象
new Date();即可
2.在Date 类型进行前后端的数据传输时,会被转换为 string,并且会有精度损失!所以我们要自行进行 toString 转换,再进行传值
(1)所以前端要进行格式化的时候:要把 string 变为 Date
const timeString = "2023-06-20T10:30:00"; // 示例时间字符串 const time = new Date(timeString);
(2)前端在向后端传送 Date 对象的时候:要转换为 string
const date = new Date();
const dateString = date.toString();
(3)后端查出来的 Date 对象,可以用toISOString()转换为字符串
在 JavaScript 中,将日期对象转换为字符串时,使用默认的 toString()
方法会将日期对象转换为本地时区的日期和时间字符串。这可能会导致在显示时存在时区偏移,导致日期看起来比实际日期多一天。
为了避免这个问题,可以使用 toISOString()
方法将日期对象转换为 ISO 8601 格式的字符串,该格式表示日期和时间的标准。这样做可以确保在不同时区之间保持一致,并且不会引入时区偏移。
用date.toISOString()
(六)配置跨域
使用 cors 插件:npm i cors
const cors = require("cors");
//配置跨域,必须写在所有路由前面
//解决跨域的插件
app.use(cors());
直接配置:
//配置跨域,必须写在所有路由前面
app.all("*", function (req, res, next) {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
res.setHeader("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
next();
});
2.vue2 中直接修改对象属性不会响应,需要使用$set方法
3.本地项目与一个新仓库(某个特定分支)进行关联并推送的步骤
(一)最完整的流程
1.如果本地项目已经推送到过其他的仓库,那么就把文件复制到新的文件夹再进行推送!
一定不要用之前推送过到其他仓库的文件进行直接推送
要新建一个新的空白文件夹,把前面的项目所有文件拷贝过来,然后再进行推送
2.非常需要注意:一定要删除所有的.git文件,将所有提交记录清除,否则之前提交过的文件本次就提交不了了,导致文件提交推送的不全!
mac 中要用ls -a才可以看到 .git文件,执行以下命令删除 .git
文件夹:rm -rf .git
3.然后进行初始化 git init
4.然后切换本地的分支
git checkout -b 本地分支
5.如果本地和远程没有关联先用命令关联:(其实只要在 push 之前设置了即可)
移除与原仓库相关的远程仓库地址:
git remote remove origin
查看关联的远程链接:git remote -v

新增关联:
git remote add origin <新仓库的远程仓库地址>
git remote add origin http://gitlab.yx/general/react-manage-demo.git
注意:有时可能要用这个域名 git remote add origin http://gitlab.classba.com.cn/general/react-manage-demo.git
如果 vpn 不稳定的时候,这个域名可能更快
6.提交文件:
git add .
git commit -m “first commit”
这里一定要注意观察一下,提交的文件是否正确,是否有没有提交上去的文件
7.如果远程的空仓库只有一个 readme 文件(或者其他文件,如果有冲突的话推荐用 idea),那么提交之前一定要先拉取
直接拉取如果不行的话就用:
git pull origin 远程分支 --allow-unrelated-histories
git pull origin dev3 --allow-unrelated-histories
命令介绍:因为本地仓库没有接触过这个仓库,所以文件的历史没有任何相同的,必须用这个命令
git pull origin <远程分支> --allow-unrelated-histories
是一个 Git 命令,用于将远程仓库的更改合并到本地分支。--allow-unrelated-histories
参数是为了允许合并没有共同历史的两个分支。
当执行 git pull
命令时,Git 会尝试自动合并远程分支和本地分支的更改。然而,如果两个分支的提交历史没有共同的祖先,Git 默认会拒绝合并,因为它无法确定如何自动合并这些不相关的历史。这时需要使用 --allow-unrelated-histories
参数来告诉 Git 允许合并没有共同历史的分支。
注意:git pull origin 后面跟着的是远程分支名字
例如:远程仓库 origin
的 main
分支 应该是 origin main
注意:origin
只是一个默认的远程仓库名称,对应于 origin
这个远程仓库名称,默认情况下,它会在本地创建一个名为 origin
的远程仓库引用。这个本地引用充当了与远程仓库通信的桥梁。
git remote show
命令来查看本地仓库的远程引用列表:

8.有可能推送的时候需要用户名密码:
Username haowenhai
Password T5oRLaqylgQp
9.git push -u origin <本地分支名称>:<远程分支名称>
git push -u origin dev3:dev3
命令介绍:用于将本地分支的提交推送到远程仓库中的指定分支
git push
: 将本地的提交推送到远程仓库。-u origin
:-u
参数用于将本地分支与指定的远程仓库(origin
)关联起来,创建一个跟踪关系,以后可以直接使用git push
来推送代码,无需再指定远程仓库和分支。<本地分支名称>
: 指定要推送的本地分支的名称。:<远程分支名称>
: 指定将本地分支推送到远程仓库的哪个分支,可以是已存在的分支,也可以是新的分支名称。
注意:如果本地分支名称和远程一样,那么可以不用写<本地分支名称>:<远程分支名称>,直接写<分支名称>即可
比如git push -u origin master
是将本地的 master
分支的提交推送到远程仓库(通常是名为 origin
的默认远程仓库)的 master
分支,并且建立跟踪关系
git push -u origin dev
是将本地的 dev
分支的提交推送到远程仓库(通常是名为 origin
的默认远程仓库)的 dev
分支,并且建立跟踪关系。
注意:-u 就是建立跟踪关系的意思
在 git push -u origin dev
命令中,-u
是 --set-upstream
的简写形式。
--set-upstream
选项用于将本地分支与远程分支建立关联。当使用 -u
或 --set-upstream
选项时,Git 会将本地分支推送到远程仓库,并且将远程分支设置为该本地分支的上游(upstream)分支。
(只有第一次推送需要写这个,后面直接 git push 即可,不用加-u origin <分支名称>了)
10.如果以上流程失败了,我们要重来,之前做如下事情:
git文件包括了我们所有的提交记录,一旦出了提交的问题,我们应该先把这个文件删掉,再重新开始
可以在远程再新建一个分支,这个分支应该是空的,然后再重新走流程(否则需要覆盖远程的分支内容,或者进行 merge,比较麻烦)
(二)git clone的方法
还有一种方法是先 git clone远程的空项目(可能有一两个文件),然后再把文件该删的删该补的补,弄成我们希望的样子,然后最后再统一提交上去,可能也可以!并且相对简单一些!
(三)远程仓库提交的文件不对,我们不想要了,又不想在远程删除
我们可以用如下方法,把本次提交的完整的正确的内容覆盖远程的所有内容
执行以下命令,将仓库的 HEAD 重置为初始状态:清空.git文件的所有提交历史,让本地变成没有提交过的,并切换到一个新的分支
bashgit checkout --orphan <新分支名称>
执行以下命令,将当前的更改添加到新的分支并进行提交:
bashgit commit -m "Initial commit"
执行以下命令,删除其他分支(除了当前分支):
bashgit branch -D <分支名称>
将
branch_name
替换为你想删除的分支名称,可以多次执行该命令以删除多个分支。最后,执行以下命令来强制推送更改到远程仓库:(直接覆盖远程的)
bashgit push origin --force --all
这将覆盖远程仓库的提交记录。
完成以上步骤后,你的仓库将不再包含之前的提交记录,相当于清空了所有的提交历史。请谨慎执行以上操作,确保你已经备份了重要的代码和数据。
4.React 使用 echarts
不要用原生的 echarts,容易有 bug,并且不好用,因为还要操作 dom
而用封装的库不需要操作 dom
安装echarts-for-react
npm install --save echarts-for-react
使用
饼形图:
import React, { Component } from "react";
import "./index.css";
import ReactECharts from "echarts-for-react";
import { getPieData } from "../../api/analysis";
export default class Pie extends Component {
state = {
option: {},
};
getData = async () => {
try {
//await风格写法
let res = await getPieData(); //调用方法
let isDid = res.data[0];
let isNotDid = res.data[1];
let data = [
{
name: "已完成",
value: isDid,
},
{
name: "未完成",
value: isNotDid,
},
];
this.setState({
option: {
title: {
text: "完成/未完成百分比",
left: "center",
},
tooltip: {
trigger: "item",
},
legend: {
orient: "vertical",
left: "left",
},
series: [
{
name: "Access From",
type: "pie",
radius: "50%",
data: data,
roseType: "radius",
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: "rgba(0, 0, 0, 0.5)",
},
},
label: {
show: true,
formatter: function (e) {
return (
((e.value / (isDid + isNotDid)) * 100).toFixed(1) + "%"
);
},
},
},
],
},
});
} catch (error) {
console.log(error.message);
}
};
componentDidMount() {
this.getData();
}
render() {
return (
<div className="pie-container">
<ReactECharts option={this.state.option} />
</div>
);
}
}
5.css 实现放到dom自己身上的时候自己的 after 元素产生变化
.element::after {
content: "After Element";
/* 初始样式 */
}
.element:hover::after {
/* 悬停时的样式 */
/* 在这里定义 ::after 伪元素的样式变化 */
}
案例:实现鼠标放到导航上,下面的出现横条由中间向两边扩张的效果
<div className="data-wapper">
<MyNavLink to="/analysis/line">添加量时间分布</MyNavLink>
<MyNavLink to="/analysis/pie">完成量总体占比</MyNavLink>
</div>
.data-wapper>a {
width: 200px;
height: 50px;
color: #000000;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
transition: all 0.3s linear;
font-size: 15px;
position: relative;
}
.data-wapper>a:after {
width: 11px;
height: 2px;
background-color: #646cff;
content: "";
/* border: 1px #646cff solid; */
position: absolute;
bottom: 0;
opacity: 0;
transition: all 0.3s ease;
}
.data-wapper>a:hover {
color: #535bf2;
}
.data-wapper>a:hover:after {
opacity: 1;
transform: scaleX(10); /*关键代码*/
transform-origin: center; /*关键代码*/
}
6.includes()
方法和 substring()
方法
includes
str.includes("Hello")
array.includes(3)
可以判断字符串也可以判断数组是否包含某个元素,会返回布尔值
substring
这个方法是截取字符串的前 n 位,等价于 slice
注意:slice 方法可以用于数组也可以用于字符串截取