目录
后端Express 部分
一.express生成器
1.概述
应用程序生成器工具 (express-generator
) 可以快速创建应用程序框架。
2.全局安装express生成器
npm install -g express-generator
3.在当前工作目录中创建名为 myapp 的 Express 应用程序并将视图引擎将设置为 Pug
express --view=pug myapp
4.然后进入myapp根目录安装依赖项:
cd myapp
npm install
5.启动项
npm start
二.解决前后端跨域
1.通过安装cors模块 解决
npm i cors
2.app.js
const cors = require('cors')
app.use(cors())
三.连接、封装操作MySQL
// 1.导入mysql包
const mysql = require('mysql')
// 2.创建mysql连接
const pool = mysql.createPool({
connectionLimit: 150,
host:'localhost', // 主机
user: 'root', // 用户名
password: '', // 密码
database: 'hw3_1' // 数据库名称
})
// 3.连接mysql
function query (sql) {
return new Promise(function (resolve,reject) {
pool.getConnection(function (err, connection) {
if (err) return;
// 4. 执行sql
connection.query(sql, function (err, data) {
if (err) return;
resolve(data)
console.log(data);
// 5.释放连接
connection.release()
})
})
})
}
// 查询数据
module.exports=query
四.创建注册用户接口
使用mysql创建表格
//创建存储用户数据的表格
ALTER TABLE `hw3_1`.`user`
CHANGE `password` `password` INT NULL FIRST,
CHANGE `username` `username` CHAR (11) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL AFTER `password`;
routers/login.js
const express = require('express')
const router = express.Router()
const query = require('../db/query')
// 新增用户
//将用户名称 密码插入user表中 同一管理
router.post('/adduser', async function (req, res) {
// post 请求参数
const { username, password } = req.body
const sql = `insert into users(username,password) values( '${username}', '${password}')`
const insert= await query(sql)
console.log(req.body)
res.send({
status:200,
message:'数据插入成功',
insert
})
})
// 通过用户名创建存储用户数据的表
router.post('/formate', async function (req, res) {
// post 请求参数
const {username} = req.body
const sql = `CREATE TABLE ${username} (
id INT NOT NULL AUTO_INCREMENT,
formname VARCHAR(255) NOT NULL,
fordata TEXT,
PRIMARY KEY (id)
)`
const insert= await query(sql)
console.log(req.body)
res.send({
status:200,
message:'数据插入成功',
insert
})
})
//查询表
//用于判断表中是否有该用户用于登陆
router.post('/formate', async function (req, res) {
// post 请求参数
const {username} = req.body
const sql = `CREATE TABLE ${username} (
id INT NOT NULL AUTO_INCREMENT,
formname VARCHAR(255) NOT NULL,
fordata TEXT,
PRIMARY KEY (id)
)`
const insert= await query(sql)
console.log(req.body)
res.send({
status:200,
message:'数据插入成功',
insert
})
})
module.exports = router
使用sql创建图片表
CREATE TABLE `images` (
`switch` text NOT NULL,
`id` int NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
)
五.创建首页图片接口
home.js
查询首页图片表格
const express = require('express')
const router = express.Router()
const query = require('../db/query')
// 用于获取首页图片
router.get('/image',async function (req, res) {
const sql = 'SELECT * FROM images'
const data= await query(sql)
res.send({
status: 200,
message: '数据请求成功',
data
})
})
module.exports = router
六.创建笔记接口增删改查
const express = require('express')
const router = express.Router()
const query = require('../db/query')
// 笔记系统的增删改查
//查
router.post('/getformdata',async function (req, res) {
const{formnaem} = req.body
const sql = `SELECT * FROM ${formnaem}`
const insert= await query(sql)
res.send({
status: 200,
message: '数据请求成功',
insert
})
})
// 改
router.post('/updateformdata',async function (req, res) {
const{formnaem,fordata,formwhere} = req.body
const sql = `UPDATE ${formnaem} SET fordata='${fordata}' WHERE formname='${formwhere}'`
const insert= await query(sql)
res.send({
status: 200,
message: '数据修改成功',
insert
})
})
// 增加
router.post('/addformdata',async function (req, res) {
const{name,formnaem,fordata} = req.body
const sql = `INSERT INTO ${name} (formname,fordata) VALUES('${formnaem}','${fordata}')`
const insert= await query(sql)
res.send({
status: 200,
message: '数据增加成功',
insert
})
})
// 删除
router.post('/deleteformdata',async function (req, res) {
const{name,formname} = req.body
const sql = `DELETE FROM ${name} WHERE formname = '${formname}'`
const insert= await query(sql)
res.send({
status: 200,
message: '数据删除成功',
insert
})
})
module.exports = router;
前端 vue2
main.js 配置根路径
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import axios from 'axios'
import store from './store/index'
Vue.use(ElementUI)
Vue.config.productionTip = false
// 配置根路径
axios.defaults.baseURL = 'http://localhost:3000/'
new Vue({
store,
render: h => h(App),
router
}).$mount('#app')
配置request
//until/request
import axios from "axios";
// 创建 axios 实例对象
const service = axios.create({
timeout: 5000
})
export default service
配置路由 创建相应文件
//router/index.js
import Vue from 'vue';
import vueRouter from 'vue-router';
Vue.use(vueRouter)
const routes= [
{
path: '/home',
component: () => import('@/view/User-Home.vue'),
children:[{
path: '/',
component: () => import('@/view/home-Website')
},
{
path: 'Website',
component: () => import('@/view/home-Website')
},
{
path:'takenotes',
component: () => import('@/view/Take-notes')
},
{
path:'noterec',
component: () => import('@/view/Note-recommendation')
},
{
path:'sysstem',
component: () => import('@/view/System')
}
]
},
{
path: '/login',
component: () => import('@/view/User-login')
},
{
path: '',
redirect: '/login'
},
]
const router = new vueRouter({
routes,
mode:'history',
})
export default router;
配置用户接口
//api/lgoin.js
import request from '@/utils/request'
// 用户列表获取
export function getuser() {
return request({
url: 'login/usernaem'
})
}
// 用户注册
export function adduser(data) {
return request({
url: `login/adduser?${data}`,
method: 'post',
data
})
}
//通过用户创建用户表
export function addfome(data) {
return request({
url: `login/formate?${data}`,
method: 'post',
data
})
}
创建登陆界面
//view/user-login
<template>
<div class="login">
<div class="mylogin" align="center">
<div class="LoginModeSwitch">
<div @click="AccountLogin" :class="showlding ? '' : 'tabactive'">
账号登录
</div>
<div @click="VisitorLogin" :class="showlding ? 'tabactive' : ''">
注册账号
</div>
</div>
<!-- 账号登录界面 -->
<el-form
v-show="showlding"
:model="loginForm"
:rules="loginRules"
ref="loginForm"
label-width="0px"
>
<el-form-item label="" prop="account" style="margin-top: 10px">
<el-row>
<el-col :span="2">
<span class="el-icon-s-custom"></span>
</el-col>
<el-col :span="22">
<el-input
class="inps"
placeholder="用户名"
v-model="loginForm.account"
>
</el-input>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="" prop="passWord">
<el-row>
<el-col :span="2">
<span class="el-icon-lock"></span>
</el-col>
<el-col :span="22">
<el-input
class="inps"
type="password"
placeholder="密码"
v-model="loginForm.passWord"
></el-input>
</el-col>
</el-row>
</el-form-item>
<el-form-item style="margin-top: 55px">
<el-button type="primary" round class="submitBtn" @click="submitForm"
>登录
</el-button>
</el-form-item>
</el-form>
<!-- 账号注册界面 -->
<el-form
v-show="!showlding"
:model="loginForm"
:rules="loginRules"
ref="loginForm"
label-width="0px"
>
<el-form-item label="" prop="account" style="margin-top: 10px">
<el-row>
<el-col :span="2">
<span class="el-icon-s-custom"></span>
</el-col>
<el-col :span="22">
<el-input
class="inps"
placeholder="用户名"
v-model="loginForm.account"
>
</el-input>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="" prop="passWord">
<el-row>
<el-col :span="2">
<span class="el-icon-lock"></span>
</el-col>
<el-col :span="22">
<el-input
class="inps"
type="password"
placeholder="密码"
v-model="loginForm.passWord"
></el-input>
</el-col>
</el-row>
</el-form-item>
<el-form-item style="margin-top: 55px">
<el-button
type="primary"
round
class="submitBtn"
@click="submitregister"
>注册账号
</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
import { mapMutations } from "vuex";
import { getuser, adduser } from "@/api/login";
export default {
name: "Login",
data: function () {
return {
loginForm: {
account: "",
passWord: "",
},
loginRules: {
account: [{ required: true, message: "请输入账号", trigger: "blur" }],
passWord: [{ required: true, message: "请输入密码", trigger: "blur" }],
},
showlding: false,
res: "", //接受数据
logintoken: false, //判断账号密码
foem: false, // 判断是否注册 成功
};
},
created() {
this.getuser();
},
methods: {
...mapMutations(["changeLogin"]),
// 登录
submitForm() {
const userAccount = this.loginForm.account;
const userPassword = this.loginForm.passWord;
// 校验 规则
if (!userAccount) {
return this.$message({
type: "error",
message: "账号不能为空!",
});
}
if (!userPassword) {
return this.$message({
type: "error",
message: "密码不能为空!",
});
}
this.logintoken = this.res.some((item) => {
if (item.username == userAccount && item.password == userPassword) {
return true;
}
});
if (this.logintoken) {
this.$message.success("登录成功");
this.$router.push("/home");
console.log(this.res);
this.$store.commit("getuserinfo", { name: userAccount });
} else {
this.$message({
type: "error",
message: "登录失败",
});
}
},
// 注册
async submitregister() {
const userAccount = this.loginForm.account;
const userPassword = this.loginForm.passWord;
// 校验 规则
if (!userAccount) {
return this.$message({
type: "error",
message: "账号不能为空!",
});
}
if (!userPassword) {
return this.$message({
type: "error",
message: "不能将密码设为空",
});
}
await adduser({
username: `${userAccount}`,
password: `${userPassword}`,
})
.then(() => {
this.foem = true;
console.log(this.foem);
// 处理成功
this.$message.success("注册成功");
})
.catch((err) => {
// 报错
console.log(err);
this.$message({
type: "error",
message: "注册失败,请检查账号是否重复注册",
});
return;
});
if (this.foem) {
this.showlding = true
}
// 重新获取数据
let res = await getuser();
this.res = res.data.data;
},
// 登录显示隐藏
AccountLogin() {
this.showlding = true;
},
// 登录显示隐藏
VisitorLogin() {
this.showlding = false;
},
//获取数据
async getuser() {
let res = await getuser();
this.res = res.data.data;
},
},
};
</script>
<style>
.login {
background-size: cover;
background-repeat: no-repeat;
background-position: center center;
width: 101%;
height: 101%;
width: 100vw;
padding: 0;
margin: 0;
height: 100vh;
font-size: 16px;
background-position: left top;
background-color: #242645;
color: #fff;
font-family: "Source Sans Pro";
position: relative;
}
.mylogin {
width: 240px;
height: 280px;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
padding: 50px 40px 40px 40px;
box-shadow: -15px 15px 15px rgba(6, 17, 47, 0.7);
opacity: 1;
background: linear-gradient(
230deg,
rgba(53, 57, 74, 0) 0%,
rgb(0, 0, 0) 100%
);
}
.inps input {
border: none;
color: #fff;
background-color: transparent;
font-size: 12px;
}
.submitBtn {
background-color: transparent;
color: #39f;
width: 200px;
}
.tourist {
float: right;
}
.LoginModeSwitch {
display: flex;
justify-content: space-around;
}
.VisitorLogin {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.VisitorLoginsubmit {
background-color: transparent;
color: #39f;
width: 200px;
}
.VisitorLoginsubmitRouter {
text-decoration: none;
color: #fff;
}
.tabactive {
color: rgb(155, 155, 120);
}
</style>
下载element
npm i element-ui -S
// element官网
// https://element.eleme.cn/#/zh-CN
头部导航栏
//view/User-Home
<template>
<div>
<div>
<el-menu
:default-active="activeIndex2"
class="el-menu-demo"
mode="horizontal"
@select="handleSelect"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b"
>
<el-menu-item><span class="titleloge">NOTES</span></el-menu-item>
<el-menu-item index="1" @click="toWebsite" class="topnabbier">首页</el-menu-item>
<el-menu-item index="2" @click="takenotes" class="topnabbier">写笔记</el-menu-item>
<el-menu-item index="3" @click="noterec" class="topnabbier">笔记推荐</el-menu-item>
<el-menu-item index="4" @click="sysstem" class="topnabbier">技术栈</el-menu-item>
</el-menu>
</div>
<router-view></router-view>
</div>
</template>
<script>
export default {
data() {
return {
activeIndex: "1",
activeIndex2: "1",
};
},
methods: {
handleSelect(key, keyPath) {
console.log(key, keyPath);
},
// 导航跳转
toWebsite() {
this.$router.push("/home/Website");
},
takenotes() {
this.$router.push("/home/takenotes");
},
noterec() {
this.$router.push("/home/noterec");
},
sysstem() {
this.$router.push("/home/sysstem");
},
},
};
</script>
<style>
.titleloge {
font-size: 4vw;
}
.topnabbier{
font-size: 1.4vw;
}
</style>
首页
<template>
<div>
<el-carousel :interval="4000" type="card" height="250x" class="top">
<el-carousel-item v-for="item in images" :key="item.id">
<img :src="item.switch" alt="" class="carouselimaeg" />
</el-carousel-item>
</el-carousel>
<div class="login1">
<img src="@/img/166839387137969.png" alt="" />
</div>
<h3 class="topbox">
NOTE managenment 更好的方便用户管理信息,更加方便的整理自己的笔记,拥有方便的笔记分享平台,让你拥有更高效的笔记
</h3>
<el-row type="flex" class="row-bg">
<el-col :span="8">
<div class="row-bg-item">
<i class="el-icon-user"></i>
<p>用户:{{ this.$store.state.user.name }}</p>
</div>
</el-col>
<el-col :span="8">
<div class="row-bg-item">
<i class="el-icon-edit"></i>
<p>用户笔记</p>
</div>
</el-col>
<el-col :span="8">
<div class="row-bg-item">
<i class="el-icon-message"></i>
<p>用户信息</p>
</div>
</el-col>
</el-row>
</div>
</template>
<script>
import { getswiper } from "@/api/home";
import { addfome } from "@/api/login";
export default {
data() {
return {
images: "",
};
},
methods: {
async getswiper() {
try {
let { data: res } = await getswiper();
this.images = res.data;
await addfome({
username: this.$store.state.user.name,
});
} catch (err) {
console.log(err);
}
},
},
created() {
this.getswiper();
// console.log(`${this.$store.state.user.name}`);
},
};
</script>
<style>
.topbox{
margin-top:5vw ;
text-align: center;
width: 60vw;
margin: 0 auto ;
}
.login1 img{
padding-left:35vw ;
width: 40vw;
height: 10vw;
}
.el-carousel__item:nth-child(2n) {
background-color: #99a9bf;
}
.el-carousel__item:nth-child(2n + 1) {
background-color: #d3dce6;
}
.carouselimaeg {
width: 100%;
height: 100%;
}
.top {
margin-top: 10px;
}
<style > .el-col {
border-radius: 4px;
}
.bg-purple-dark {
background: #99a9bf;
}
.bg-purple {
background: #d3dce6;
}
.bg-purple-light {
background: #e5e9f2;
}
.grid-content {
border-radius: 4px;
min-height: 36px;
}
.row-bg {
padding-top: 5vw;
background-color: #f9fafc;
}
.row-bg-item {
text-align: center;
}
.row-bg {
width: 70vw;
margin: 0 auto;
font-size: 1.4vw;
}
</style>
创建弹框组件
<template>
<div>
<el-dialog title="NOTE" :visible.sync="dialogFormVisible">
<el-form :model="form">
<el-form-item label="新增笔记" :label-width="formLabelWidth">
<el-input v-model="form.name" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="btnCancel">取消</el-button>
<el-button type="primary" @click="btnok">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {addnote} from '@/api/note'
export default {
data() {
return {
dialogFormVisible: false,
showloding: false, // 控制页面
form: {
name: "",
},
formLabelWidth: "120px",
};
},
methods: {
async btnok() {
this.dialogFormVisible = false;
this.showloding = true;
this.$emit("change", this.showloding);
// console.log(this.$store.state.user.name);
// console.log(this.form.name);
// 增加表
await addnote({
name:`${this.$store.state.user.name}`,
formnaem:`${this.form.name}`,
fordata:``
});
// 获取 父组件方法重新渲染
this.$parent.getformdata()
// 将笔记名字重新置为空
this.form.name=''
},
btnCancel() {
this.dialogFormVisible = false;
this.showloding = false;
this.$emit("change", this.showloding);
},
},
};
</script>
<style>
</style>
新增笔记组件
安装wangEditor
npm install @wangeditor/editor-for-vue --save
官网地址 https://www.wangeditor.com/v5/installation.html#npm
//components/Note-Input.vue
<template>
<div style="border: 1px solid #ccc">
<Toolbar
style="border-bottom: 1px solid #ccc"
:editor="editor"
:defaultConfig="toolbarConfig"
:mode="mode"
/>
<Editor
style="height: 500px; overflow-y: hidden"
v-model="html"
:defaultConfig="editorConfig"
:mode="mode"
@onCreated="onCreated"
@onChange="onChange"
@onDestroyed="onDestroyed"
@onMaxLength="onMaxLength"
@onFocus="onFocus"
@onBlur="onBlur"
@customPaste="customPaste"
/>
</div>
</template>
<style src="@wangeditor/editor/dist/css/style.css"></style>
<script>
import Vue from "vue";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
export default Vue.extend({
components: { Editor, Toolbar },
data() {
return {
editor: null,
html: "<p>hello</p>",
toolbarConfig: {},
editorConfig: { placeholder: "请输入内容..." },
mode: "default", // or 'simple'
};
},
methods: {
onCreated(editor) {
this.editor = Object.seal(editor);
console.log("onCreated", editor);
},
onChange(editor) {
console.log("onChange", editor.children);
console.log(this.html); // 数据
this.$store.commit("gethtml", this.html);
},
onDestroyed(editor) {
console.log("onDestroyed", editor);
},
onMaxLength(editor) {
console.log("onMaxLength", editor);
},
onFocus(editor) {
console.log("onFocus", editor);
},
onBlur(editor) {
console.log("onBlur", editor);
},
customPaste(editor, event, callback) {
console.log("ClipboardEvent 粘贴事件对象", event);
// const html = event.clipboardData.getData('text/html') // 获取粘贴的 html
const text = event.clipboardData.getData('text/plain') // 获取粘贴的纯文本
// const rtf = event.clipboardData.getData('text/rtf') // 获取 rtf 数据(如从 word wsp 复制粘贴)
// 自定义插入内容
editor.insertText(text);
// 返回 false ,阻止默认粘贴行为
event.preventDefault();
callback(false); // 返回值(注意,vue 事件的返回值,不能用 return)
// 返回 true ,继续默认的粘贴行为
// callback(true)
},
insertText() {
const editor = this.editor; // 获取 editor 实例
if (editor == null) return;
// 调用 editor 属性和 API
editor.insertText("一段文字");
console.log(editor.children);
},
upinput () {
this.html = `${this.$store.state.input}`;
// console.log(this.html);
}
},
mounted() {
// 模拟 ajax 请求,异步渲染编辑器
setTimeout(() => {
this.html = `${this.$store.state.input}`;
}, 1500);
},
beforeDestroy() {
const editor = this.editor;
if (editor == null) return;
editor.destroy(); // 组件销毁时,及时销毁编辑器
},
});
</script>
笔记功能
//Take-notes.vue
<template>
<div class="big">
<!-- :class="showlding ? '' : 'tabactive'" -->
<el-container :class="!show ? '' : 'allblur'">
<!-- 左边导航栏 -->
<el-aside width="200px" style="background-color: rgb(238, 241, 246)">
<el-menu :default-openeds="['1', '2']">
<el-submenu index="1">
<template slot="title"
><i class="el-icon-message"></i>笔记工具</template
>
<el-menu-item-group>
<template slot="title">基础功能</template>
<!-- 新增功能 -->
<el-menu-item index="1-1" @click="showupdate"
>新增笔记</el-menu-item
>
<!-- 删除功能 -->
<el-menu-item index="1-2" @click="del"> 删除笔记 </el-menu-item>
<!-- 保存功能 -->
<el-menu-item index="1-3" @click="updatad">保存笔记</el-menu-item>
</el-menu-item-group>
<!-- 跟多工具 -->
<el-submenu index="1-4">
<template slot="title">更多工具</template>
<el-menu-item index="1-4-1">选项4-1</el-menu-item>
</el-submenu>
</el-submenu>
<!-- 笔记内容 -->
<el-submenu index="2">
<template slot="title"
><i class="el-icon-menu"></i>笔记内容</template
>
<el-menu-item-group>
<template slot="title">笔记栏</template>
<el-menu-item
v-for="(item, i) in formdata"
:key="item.id"
:index="`2-${i}`"
@click="updataformi(i)"
>{{ item.formname }}</el-menu-item
>
</el-menu-item-group>
</el-submenu>
</el-menu>
</el-aside>
<!-- 右侧内容 -->
<el-main>
<div v-show="!show">
<el-empty>
<el-button type="primary" @click="showupdate">新增笔记</el-button>
</el-empty>
</div>
<!-- 笔记 -->
<div v-show="show">
<noteinput ref="ChildComponents" inputvalue></noteinput>
</div>
</el-main>
</el-container>
<!-- 弹窗内容 -->
<addelement
class="addelement"
ref="child"
@change="costPlannedAmountChange($event)"
>
</addelement>
</div>
</template>
<script>
import addelement from "@/components/add-emplass.vue";
import noteinput from '@/components/Note-Input.vue'
import { getnote, delnote, noteupdata } from "@/api/note";
export default {
components: { addelement,noteinput},
data() {
return {
uniqueOpened: false,
textarea: "",
show: false, // 控制 笔记显示隐藏
formdata: "", // 保存请求数据
formi: 0, // 判断点击的下标
inputvalue: "", // 笔记内容
delshow: false, //判断删除是否成红
};
},
methods: {
updataformi(i) {
this.formi = i;
this.inputvalue = this.formdata[this.formi].fordata;
// console.log(this.inputvalue);
this.show = true;
this.$store.commit("getinput",this.inputvalue);
this.$refs.ChildComponents.upinput()
},
// 控制 显示隐藏
async showupdate() {
this.$refs.child.dialogFormVisible = true;
//this.$store.state.user.name
},
// 获取弹框组件数据
async costPlannedAmountChange(value) {
this.show = value;
},
// 获取数据接口
async getformdata() {
// console.log(this.$store.state.user.name,'111111111111');
var formdata = await getnote({
formnaem: `${this.$store.state.user.name}`,
});
this.formdata = formdata.data.insert;
// console.log(this.formdata, "222222222222222");
this.formi = this.formdata.length - 1;
this.inputvalue = this.formdata[this.formdata.length - 1].fordata;
this.$store.commit("getinput", this.inputvalue);
},
//删除
async del() {
// 删除玩重新获取
await delnote({
name: `${this.$store.state.user.name}`,
formname: `${this.formdata[this.formi].formname}`,
});
this.getformdata();
this.$message({ type: "success", message: "删除成功" });
this.show=false
},
//保存
async updatad() {
console.log(this.$store.state.html);
await noteupdata({
formnaem: `${this.$store.state.user.name}`,
fordata: `${this.$store.state.html}`,
formwhere: `${this.formdata[this.formi].formname}`,
});
this.getformdata();
this.$message({ type: "success", message: "保存" });
},
},
created() {
this.getformdata();
},
};
</script>
<style>
</style>