前端实例Vue创建Vue的实例流程
康弟弟一、环境准备
1.1 创建vue工程
1.2 安装插件
1.安装element-plus
1 2 3 4 5
| 1.1 执行命令: npm install element-plus --save 1.2 在main.js中做如下配置 import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' app.use(ElementPlus)
|
2.安装axios
1.3 目录调整
删除components目录下的内容
删除App.vue中的内容,只保留script和template标签
2. 页面搭建
2.1 文件介绍
index.html是最初始的页面,可以在这里定义页面的title这类的页面基础标签,其中映入了一个叫App.vue的文件,所有的vue项目都是建立在这里html渲染的,如果在创建的vue项目的所有页面都有一个白框,只需要将index.html的margin设置为0px,因为自带的element属性中会有一个默认的margin=8px

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <!DOCTYPE html> <html lang="">
<head> <meta charset="UTF-8"> <link rel="icon" href="/favicon.ico"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vite App</title> </head>
<body style="margin: 0px;"> <div id="app"></div> <script type="module" src="/src/main.js"></script> </body>
</html>
|
main.js文件和上述的html一样,是对所有vue文件的一个全局属性,当我们需要对所有的vue项目导入同一个属性的时候,就可以到这里进行统一处理,例如将Element的js和css导入几句可以在这里进行注入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import { createApp } from 'vue' import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' import router from '@/router' import App from './App.vue' import {createPinia} from 'pinia' import { createPersistedState } from 'pinia-persistedstate-plugin' import locale from 'element-plus/dist/locale/zh-cn.js'
const app = createApp(App); const pinia = createPinia(); const persist = createPersistedState(); pinia.use(persist) app.use(pinia) app.use(router) app.use(ElementPlus,{locale}); app.mount('#app')
|
App.vue是所有vue项目展示的位置,为了将页面渲染到当前页面,我们就需要在这里设置将我们需要的页面渲染在这里:
1 2 3 4 5 6 7 8 9 10 11 12
| <script setup> </script>
<template> <router-view></router-view> </template>
<style scoped>
</style>
|
2.2 路由
在App.vue中,不能同时展示Login.vue和Layout.vue,实际的需求是用户第一次访问程序,先展示登录页面,当用户登录成功后,再展示主页面,如果要达成这个需求,需要用到vue提供的路由相关的知识
路由,从起点到终点时,决定从起点到终点的路径的进程,在前端工程中,路由指的是根据不同的访问路径,展示不同组件的内容。Vue Router是Vue.js的官方路由,它与Vue.js深度集成,让Vue.js构建单页面应用变得更加轻而易举
2.2.1 安装路由
1
| npm install vue-router@4j
|
2.2.2 创建路由
在src/router目录下,定义一个js文件,起名为index.js。这样名字的js文件在导入时,可以不写文件名,只要定位到文件所在的文件夹即可,使用起来很方便
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| import { createRouter, createWebHistory } from 'vue-router';
import LoginVue from '@/views/Login.vue'; import LayoutVue from '@/views/Layout.vue'; import BookCategory from '@/views/book/BookCategory.vue'; import BookManage from '@/views/book/BookManger.vue'; import UserManage from '@/views/user/UserManger.vue'; import UserAdd from '@/views/user/UserAdd.vue'; import UserEdit from '@/views/user/UserEdit.vue';
const routes = [ { path: '/login', component: LoginVue }, { path: '/', component: LayoutVue, redirect: '/book/category/', children: [ { path: 'book/category', component: BookCategory }, { path: 'book/manage', component: BookManage }, { path: 'user/manage', component: UserManage }, { path: 'user/add', component: UserAdd }, { path: 'user/edit/:id', component: UserEdit, props: true, name: 'UserEdit' }, ] } ];
const router = createRouter({ history: createWebHistory(), routes: routes });
export default router;
|
2.2.3 在vue应用实例中使用router
在2.1中介绍的main.js中加入这些:
1 2 3
| import router from '@/router'
app.use(router)
|
2.2.4 使用路由
在上面定义好路由后,继续在我们想要使用页面转跳的时候,使用如下,在中引入路由:
1 2
| import { useRouter } from 'vue-router' const router = useRouter();
|
在需要转跳的地方如下编写,相当与会转跳到‘‘/‘’这个路径之下:
2.2.5 子路由
在咱们的主页面中,当用户点击左侧的菜单时,右侧主区域的内容需要发生变化,将来每切换一个菜单,右侧需要加载对应组件的内容进行展示,像这样的场景咱们也需要使用路由来完成
由于这些组件都需要在Layout.vue中展示, 而Layout.vue本身已经参与了路由,因此我们需要在Layout.vue中通过子路由的方式来完成组件的切换
2.3 注册页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
| <template> <div class="container"> <div class="wrapper"> <form @submit.prevent="handleLogin"> <h1>登录</h1> <div class="input-box"> <input v-model="LoginData.adminName" type="text" required /> <label>用户名</label> </div> <div class="input-box"> <input v-model="LoginData.adminPass" type="password" required /> <label>密码</label> </div>
<div class="row"> <a @click="forgotPassword">忘记密码?</a> </div>
<button type="submit" class="btn">登录</button> <div class="signup-link"> <p>还没有账号?<a href="#" @click="showSignUpAlert">创建一个。</a></p> </div> </form> </div> </div> </template>
<script> import { ref } from 'vue'; // 引入 Vue 的 ref 函数用于响应式数据 import { mangerLoginService } from '@/api/manger'; // 导入登录服务 API import { ElMessage } from 'element-plus'; // 导入 Element Plus 消息组件 import { useRouter } from 'vue-router'; // 引入 Vue Router 用于页面导航 import { useTokenStore } from '@/stores/token'; // 导入 token 存储管理
export default { setup() { const tokenStore = useTokenStore(); // 获取 token 存储 const router = useRouter(); // 获取路由对象 const LoginData = ref({ adminName: '', // 用户名 adminPass: '', // 密码 });
// 处理登录的函数 const handleLogin = async () => { let result = await mangerLoginService(LoginData.value); // 调用登录 API if (result.code == 200) { // 判断返回的状态码 console.log('登入成功,用户名是:', result.data.adminName); // localStorage.setItem('userInfo', JSON.stringify(result.data.adminName)); // 可选:存储用户信息 ElMessage.success('登录成功!'); // 显示成功消息 console.log('登入的token值是:', tokenStore); tokenStore.setToken(result.data); // 存储 token router.push('/'); // 登录成功后重定向到主页 } else { ElMessage.error('账号或密码错误!'); // 显示错误消息 } };
// 处理忘记密码的函数 const forgotPassword = () => { ElMessage.info('请联系管理员重置密码。'); // 提示信息 };
// 显示注册提示的函数 const showSignUpAlert = () => { // 这里可以添加注册逻辑或提示 };
return { LoginData, // 返回响应式数据 handleLogin, // 返回登录处理函数 forgotPassword, // 返回忘记密码处理函数 showSignUpAlert, // 返回注册提示函数 }; }, }; </script>
<style scoped> * { font-family: "Poppins", sans-serif; /* 设置全局字体 */ margin: 0; /* 去除默认外边距 */ padding: 0; /* 去除默认内边距 */ box-sizing: border-box; /* 包含边框和内边距在内的宽高计算 */ }
html, body { height: 100%; /* 使 html 和 body 填满整个视口 */ margin: 0; /* 去除默认外边距 */ }
.container { height: 100vh; /* 使 container 填满整个视口高度 */ display: flex; /* 使用 flex 布局 */ align-items: center; /* 垂直居中 */ justify-content: center; /* 水平居中 */ background: #282a37; /* 设置背景颜色 */ }
.wrapper { width: 400px; /* 设置 wrapper 宽度 */ height: 450px; /* 设置 wrapper 高度 */ background: #3e404d; /* 设置背景颜色 */ border-radius: 20px; /* 设置圆角 */ display: flex; /* 使用 flex 布局 */ flex-direction: column; /* 垂直排列子元素 */ align-items: center; /* 水平居中子元素 */ justify-content: center; /* 垂直居中子元素 */ backdrop-filter: blur(15px); /* 背景模糊效果 */ }
.wrapper:hover { box-shadow: 0 0 40px rgba(255, 255, 255, 0.5); /* 鼠标悬停时的阴影效果 */ background: #46474e; /* 鼠标悬停时的背景颜色 */ }
.wrapper h1 { font-size: 2em; /* 设置标题字体大小 */ color: #fff; /* 设置标题颜色 */ text-align: center; /* 设置标题居中 */ }
.wrapper .input-box { position: relative; /* 相对定位用于 label 的绝对定位 */ width: 310px; /* 设置输入框宽度 */ margin: 30px 0; /* 设置上下外边距 */ border-bottom: 2px solid #fff; /* 底部边框 */ }
.wrapper .input-box input { width: 100%; /* 输入框宽度填满父元素 */ height: 50px; /* 设置输入框高度 */ background: transparent; /* 输入框背景透明 */ outline: none; /* 去除输入框焦点样式 */ border: none; /* 去除输入框边框 */ font-size: 1em; /* 设置字体大小 */ color: #fff; /* 设置字体颜色 */ padding: 0 40px 0 5px; /* 设置内边距 */ }
.wrapper .input-box label { position: absolute; /* 绝对定位 */ top: 50%; /* 垂直居中 */ left: 5px; /* 左边距 */ transform: translateY(-50%); /* 垂直居中调整 */ font-size: 1em; /* 设置字体大小 */ color: #fff; /* 设置字体颜色 */ pointer-events: none; /* 禁用标签的鼠标事件 */ transition: 0.5s; /* 标签移动动画 */ }
.wrapper .input-box input:focus~label, .wrapper .input-box input:valid~label { top: -5px; /* 聚焦或有效输入时标签上移 */ }
.wrapper .input-box .icon { position: absolute; /* 绝对定位 */ right: 8px; /* 右边距 */ color: #fff; /* 设置颜色 */ font-size: 1.2em; /* 设置字体大小 */ line-height: 57px; /* 使图标垂直居中 */ }
.wrapper .row { margin: -15px 0 15px; /* 设置上下外边距 */ font-size: 0.9em; /* 设置字体大小 */ color: #fff; /* 设置字体颜色 */ display: flex; /* 使用 flex 布局 */ justify-content: space-between; /* 子元素水平分散对齐 */ }
.wrapper .row a { color: #fff; /* 设置链接颜色 */ text-decoration: none; /* 去除链接下划线 */ }
.wrapper .btn { width: 100%; /* 按钮宽度填满父元素 */ height: 40px; /* 设置按钮高度 */ background: #fff; /* 设置按钮背景颜色 */ border: none; /* 去除按钮边框 */ border-radius: 40px; /* 设置圆角 */ cursor: pointer; /* 设置鼠标悬停时光标为手型 */ font-size: 1em; /* 设置字体大小 */ color: #000; /* 设置字体颜色 */ margin-top: 10px
|
3. 跨域
由于发起ajax请求的域为http://localhost:5173, 而后台服务器的域为 http://localhost:8080, 所以浏览器会限制该请求的发送, 这种问题称为跨域问题, 跨域问题可以在服务器端解决,也可以在浏览器端解决, 咱们这一块通过配置代理的方式解决
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
import axios from 'axios';
import { ElMessage } from 'element-plus'
const baseURL = 'http://localhost:8080'; const instance = axios.create({ baseURL })
import {useTokenStore} from '@/stores/token.js'
instance.interceptors.request.use( (config)=>{ const tokenStore = useTokenStore(); if(tokenStore.token){ config.headers.Authorization = tokenStore.token } return config; }, (err)=>{ Promise.reject(err) } )
import router from '@/router'
instance.interceptors.response.use( result => { if(result.data.code===200){ return result.data; }
ElMessage.error(result.data.msg?result.data.msg:'服务异常') return Promise.reject(result.data) }, err => { if(err.response.status===401){ ElMessage.error('请先登录') router.push('/login') }else{ ElMessage.error('服务异常') } return Promise.reject(err); } )
export default instance;
|
4. 接口
接口是和后端进行交互的地址, 在src/api/统一定义接口路径
例如:登入接口:
1 2 3 4 5 6 7 8 9 10 11
| import request from '@/utils/request';
export const mangerLoginService = (loginData) => { const params = {}; for(let key in loginData){ params[key] = loginData[key]; } console.log('登入api参数:', params); return request.post('/manger/login',params) }
|
那么我们可以在需要转跳的vue项目中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| //引入接口 import { mangerLoginService } from '@/api/manger'; //调用接口并接收返回值 const handleLogin = async () => { let result = await mangerLoginService(LoginData.value) if (result.code == 200) { console.log('登入成功,用户名是:', result.data.adminName); // localStorage.setItem('userInfo', JSON.stringify(result.data.adminName)); // 存储用户信息 ElMessage.success('登录成功!') console.log('登入的token值是:', tokenStore); tokenStore.setToken(result.data); router.push('/') } else { ElMessage.error('账号或密码错误!') } }
|
等待学习:
上传图片
见最新
图片回显
见最新
文件上传