后台管理的项目搭建过程(第一课)
第一部分 认识项目的搭配环境开发
第二部分 项目的创建需要的环境依赖如下
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>