后台管理的项目搭建过程(第一课)
第一部分 认识项目的搭配环境开发
第二部分 项目的创建需要的环境依赖如下
- Element - The world's most popular Vue UI framework ElementUl组件库
- Sass世界上最成熟、稳定和强大的CSS扩展语言 | Sass中文网 Sass预处理器
- Sass世界上最成熟、稳定和强大的CSS扩展语言 | Sass中文网] Less预处理器
- CSS Tools: Reset CSS Css样式重置
- Font Awesome,一套绝佳的图标字体库和CSS框架 图标库的使用
- npm i -S axios axiox 网络请求的知识 Vue(第十七课)AXIOS对JSON数据的增删改查_星辰镜的博客-CSDN博客
- npm i vue-router -S 路由的安装 Vue3框架中路由的使用和局部刷新的功能(第十一课)_星辰镜的博客-CSDN博客_vue3 路由局部刷新
- json-server 的安装 Vue(第十六课)JSON-SERVE和POSTMAN技术中对数据的增删改查_星辰镜的博客-CSDN博客
- Vue框架学习(第十三课)Vuex状态管理中的store和state属性_星辰镜的博客-CSDN博客_vue store 状态管理 vuex
本案例的安装不在示范 之前有说到
App.vue
<template>
<div>首页</div>
<!-- 路由出口 -->
<router-view/>
</template>
<style lang="scss">
</style>
Main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// 引用elementui组件库
// import ElementPlus from 'element-plus'
// import 'element-plus/dist/index.css'
// 引用elementui组件库
// .use(ElementPlus)
createApp(App).use(store).use(router).mount('#app')
index.ts
data.json
{
"students": [
{
"name": "我修改的数据",
"age": "27",
"id": 1003
},
{
"id": 1004,
"name": "王者荣耀",
"sex": "男",
"height": "190",
"weight": "67",
"job": "Web开发工程师"
},
{
"name": "硝酸",
"sex": "男",
"height": "178",
"weight": "58",
"job": "前端开发工程师",
"id": 1005
},
{
"name": "小黄入",
"sex": "男",
"height": "198",
"weight": "78",
"job": "王者",
"id": 1006
},
{
"name": "小黄",
"sex": "男",
"height": "198",
"weight": "78",
"job": "王者",
"id": 1007
},
{
"name": "小黄",
"sex": "男",
"height": "198",
"weight": "78",
"job": "王者",
"id": 1008
},
{
"name": "小黄",
"sex": "男",
"height": "198",
"weight": "78",
"job": "王者",
"id": 1011
},
{
"id": 1012
},
{
"name": "小黄",
"sex": "男",
"height": "198",
"weight": "78",
"job": "王者",
"id": 1013
},
{
"name": "我是增加的数据在studens中",
"sex": "男",
"height": "200",
"weight": "18",
"job": "吃鸡",
"id": 1014
},
{
"name": "AAA",
"sex": "男",
"height": "198",
"weight": "78",
"job": "王者",
"id": 1015
}
],
"teachers": [
{
"id": 102,
"name": "王米",
"sex": "女",
"subject": "前端开发工程师"
},
{
"id": 104
},
{
"name": "我是数据",
"sex": "男",
"subject": "墙隔断",
"id": 105
},
{
"name": "小明",
"sex:男": "",
"subject:随口": "",
"id": 106
},
{
"name": "我叫立尚三",
"sex:男": "",
"subject:王者荣耀": "",
"id": 107
},
{
"name": "我叫李珊四",
"sex:男": "",
"subject:王者荣耀": "",
"id": 108
}
],
"profile": {
"name": "typicode"
}
}
store/index.ts
import { createStore } from 'vuex'
export default createStore({
state: {
},
getters: {
},
mutations: {
},
actions: {
},
modules: {
}
})
<template>
<el-form
ref="ruleFormRef"
:model="ruleForm"
status-icon
:rules="rules"
label-width="120px"
class="demo-ruleForm"
>
<el-form-item label="Password" prop="pass">
<el-input v-model="ruleForm.pass" type="password" autocomplete="off" />
</el-form-item>
<el-form-item label="Confirm" prop="checkPass">
<el-input
v-model="ruleForm.checkPass"
type="password"
autocomplete="off"
/>
</el-form-item>
<el-form-item label="Age" prop="age">
<el-input v-model.number="ruleForm.age" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm(ruleFormRef)"
>Submit</el-button
>
<el-button @click="resetForm(ruleFormRef)">Reset</el-button>
</el-form-item>
</el-form>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import type { FormInstance } from 'element-plus'
const ruleFormRef = ref<FormInstance>()
const checkAge = (rule: any, value: any, callback: any) => {
if (!value) {
return callback(new Error('Please input the age'))
}
setTimeout(() => {
if (!Number.isInteger(value)) {
callback(new Error('Please input digits'))
} else {
if (value < 18) {
callback(new Error('Age must be greater than 18'))
} else {
callback()
}
}
}, 1000)
}
const validatePass = (rule: any, value: any, callback: any) => {
if (value === '') {
callback(new Error('Please input the password'))
} else {
if (ruleForm.checkPass !== '') {
if (!ruleFormRef.value) return
ruleFormRef.value.validateField('checkPass', () => null)
}
callback()
}
}
const validatePass2 = (rule: any, value: any, callback: any) => {
if (value === '') {
callback(new Error('Please input the password again'))
} else if (value !== ruleForm.pass) {
callback(new Error("Two inputs don't match!"))
} else {
callback()
}
}
const ruleForm = reactive({
pass: '',
checkPass: '',
age: '',
})
const rules = reactive({
pass: [{ validator: validatePass, trigger: 'blur' }],
checkPass: [{ validator: validatePass2, trigger: 'blur' }],
age: [{ validator: checkAge, trigger: 'blur' }],
})
const submitForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.validate((valid) => {
if (valid) {
console.log('submit!')
} else {
console.log('error submit!')
return false
}
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
}
</script>
main.css
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
html, body {
width: 100%;
height: 100%;
font-family: 'PingFangSC-Light', 'PingFang SC', 'STHeitiSC-Light', 'Helvetica-Light', 'Arial', 'sans-serif';
}
serviceAxios.js
import axios from 'axios'
// 创建拦截器
const service=axios.create()
// 请求拦截和响应拦截
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
return response;
}, function (error) {
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么
return Promise.reject(error);
});
export default service
登录注册的样式
<style lang="scss">
.login-con {
align-content: center;
margin: auto;
display: flex;
}
.menu-tab {
li {
display: line-break;
justify-content: center;
width: 100px;
height: 55px;
font-size: 30px;
line-height: 55px;
font-size: 14px;
text-align: center;
color: rgb(255, 0, 21);
border-radius: 12px;
cursor: pointer;
}
}
.current {
width: 200px;
font-size: 16px;
font-weight: 600;
color: rgb(0, 255, 72);
cursor: pointer;
margin: 20px;
height: 55px;
line-height: 55px;
text-align: center;
border: none;
background-size: 300% 100%;
border-radius: 50px;
// transition: all 0.4s ease-in-out;
background-image: linear-gradient(
to right,
#25aae1,
#4481eb,
#04befe,
#3f86ed
);
box-shadow: 0 4px 15px 0 rgba(65, 132, 234, 0.75);
}
.demo-ruleForm {
width: 30%;
margin: 50px auto;
label {
display: block;
margin-bottom: 3px;
font-size: 14px;
color: rgb(13, 195, 255);
}
}
.block {
display: block;
width: 100%;
border-radius: 12px;
}
.login-btn {
margin-top: 20px;
}
h1 {
font-weight: 900;
text-align: center;
}
.big {
width: 100%;
height: 100px;
color: black;
}
.big .son {
margin: auto;
width: 60%;
height: 100px;
color: rgb(9, 1, 1);
}
</style>
<template>
<div class="big">
<div class="big son">
<div class="login">
<div class="login-con">
<ul class="menu-tab">
<li
v-for="v in MenuData"
:class="{ current: v.current }"
:key="v.type"
@click="clickMenu(v)"
>
{{ v.txt }}
</li>
</ul>
</div>
</div>
</div>
</div>
<!-- 表单部分 -->
<el-form
ref="ruleFormRef"
:model="ruleForm"
status-icon
:rules="rules"
class="demo-ruleForm"
>
<h1 v-show="model === 'register'">注册页面</h1>
<h1 v-show="model === 'login'">登录页面</h1>
<el-form-item prop="Name" v-show="model === 'register'">
<label>用户名</label>
<el-input v-model="ruleForm.Name" type="text" autocomplete="off" />
</el-form-item>
<el-form-item prop="Phone" v-show="model === 'register'">
<label>手机号</label>
<el-input v-model="ruleForm.Phone" type="text" autocomplete="off" />
</el-form-item>
<!-- -->
<el-form-item prop="username">
<label>邮箱</label>
<el-input v-model="ruleForm.username" type="text" autocomplete="off" />
</el-form-item>
<el-form-item prop="password">
<label>密码</label>
<el-input
v-model="ruleForm.password"
type="password"
autocomplete="off"
/>
</el-form-item>
<el-form-item prop="passwords" v-show="model === 'register'">
<label>重复密码</label>
<el-input v-model.number="ruleForm.passwords" />
</el-form-item>
<el-form-item>
<el-button
type="primary"
class="login-btn block"
@click="submitForm(ruleFormRef)"
>{{ model === "login" ? "登录按钮" : "注册按钮" }}</el-button
>
<el-button @click="resetForm(ruleFormRef)" class="login-btn block"
>按钮重置</el-button
>
</el-form-item>
</el-form>
</template>
<script lang="ts" setup>
// 创建复杂数据的类型
import { reactive, ref, onMounted } from "vue";
import type { FormInstance } from "element-plus";
import * as ck from "../../util/verfifcation.js";
import link from "../../api/Link.js";
import apiUrl from "../../api/url.js";
const ruleFormRef = ref<FormInstance>();
onMounted(() => {
console.log(process.env.VUE_APP_API);
});
const MenuData = reactive([
{ txt: "登录", current: false, type: "login" },
{ txt: "注册", current: false, type: "register" },
]);
let model = ref("login");
let clickMenu = (item: any) => {
MenuData.forEach((elemt) => {
elemt.current = false;
});
item.current = true;
// 修改状态
model.value = item.type;
};
//表单模块
// 用户名正则验证
const checkuserName = (rule: any, value: any, callback: any) => {
let reg = /^[\w-]{4,16}$/;
if (!value) {
return callback(new Error("用户名不能为空!"));
} else if (!reg.test(value)) {
return callback(new Error("用户你好你输入的用户名格式步正确"));
} else {
callback();
}
};
//手机号验证
const checkuserPhone = (rule: any, value: any, callback: any) => {
if (!value) {
return callback(new Error("手机号的不能为空!"));
} else if (ck.ckPhone(value)) {
return callback(new Error("用户你好你输入的手机号格式步正确"));
} else {
callback();
}
};
//邮箱
const checkuser = (rule: any, value: any, callback: any) => {
if (!value) {
return callback(new Error("邮箱的不能为空!"));
} else if (ck.CkEmail(value)) {
return callback(new Error("用户你好你输入的邮箱格式步正确"));
} else {
callback();
}
};
// 密码的正则表达式
const validatePass = (rule: any, value: any, callback: any) => {
if (value === "") {
callback(new Error("密码不能为空"));
} else if (ck.CkPass(value)) {
callback(new Error("用户输入的密码格式有误请重新输入"));
} else {
callback();
}
};
const validatePass2 = (rule: any, value: any, callback: any) => {
// 因为登录的时候没有密码的核对 所以在登录的时候曲线重复的代码核对
if (model.value === "login") {
callback();
}
if (value === "") {
callback(new Error("用户重复的密码不能为空"));
} else if (value !== ruleForm.password) {
callback(new Error("俩次输入密码必须相同"));
} else {
callback();
}
};
const ruleForm = reactive({
Name: "",
Phone: "",
username: "",
password: "",
passwords: "",
pass: "",
checkPass: "",
age: "",
});
// 设置以那种方式发生函数
const rules = reactive({
password: [{ validator: validatePass, trigger: "blur" }],
passwords: [{ validator: validatePass2, trigger: "blur" }],
username: [{ validator: checkuser, trigger: "blur" }],
Name: [{ validator: checkuserName, trigger: "blur" }],
Phone: [{ validator: checkuserPhone, trigger: "blur" }],
});
// 注册
const submitForm = (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate((valid) => {
if (valid) {
console.log("submit!");
link(apiUrl).then((ok: any) => {
console.log(ok);
});
} else {
console.log("error submit!");
return false;
}
});
};
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.resetFields();
};
</script>
<style lang="scss">
@import "./src/styles/reset.scss";
</style>