超详细的前后端实战项目(Spring系列加上vue3)前端篇(一)(一步步实现+
最近想着一步步搭建一个前后端项目,将每一步详细的做出来。(如果有不足或者发起,也盼望大佬们指出哦)前端初始化
1.根据vue脚手架创建vue项目
这里可以用很多方法创建vue项目,大家看着创建吧,只要能创建出来就可以了(用的vue3)
https://i-blog.csdnimg.cn/blog_migrate/b5867700d3f2b80fb4e49d7b107c4e60.png
https://i-blog.csdnimg.cn/blog_migrate/f62cf316edb4595a61ac35557aec44cb.png
https://i-blog.csdnimg.cn/blog_migrate/32fee4b161593feb3fa6354f8e027c5e.png
https://i-blog.csdnimg.cn/blog_migrate/ff95c712e01c477967a792cfc4c57dfd.png
这里我加了router和vuex,emm,就不消ts了(感觉还是js用的更好一点)
https://i-blog.csdnimg.cn/blog_migrate/ac481d286ce273abb6dcc4b4f854d40d.png
OK,项目创建完毕,即可开始写前端代码了。
2.安装依赖:
1.挑一个自己喜好的组件库引用一手,这里我选用arco design(也没必要只用Element-ui,可以试试其他的)
npm install --save-dev @arco-design/web-vue OKOK,开始下载
https://i-blog.csdnimg.cn/blog_migrate/55796d2e4db36feda2dbf00d9ec187dc.png
安装好了之后,我们还要安装一些必要的依赖,好比axios,sass这些,emmmm,目前就安装这几个吧。
npm install axios
npm install sass -D
https://i-blog.csdnimg.cn/blog_migrate/0147f28ac9ebb6085aadee0781d54759.png
然后根据组件库官网的操作进行引入
import { createApp } from 'vue'
import ArcoVue from '@arco-design/web-vue';
import App from './App.vue';
import '@arco-design/web-vue/dist/arco.css';
const app = createApp(App);
app.use(ArcoVue);
app.mount('#app'); 改造一下main.js中的代码
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import ArcoVue from '@arco-design/web-vue';
import '@arco-design/web-vue/dist/arco.css';
createApp(App).use(store).use(ArcoVue).use(router).mount('#app')
留意留意:引入组件库之后,可以找个组件看看能不能使用该组件库,以防万一;
呐,这里我们就去官网看看
https://i-blog.csdnimg.cn/blog_migrate/f54b4b19a813262769c5183e98646839.png
很好,就是你了,表单布局,我们点击其下方代码,将其放入App.vue试试能不能用
https://i-blog.csdnimg.cn/blog_migrate/1d35e30a0f19cbdd778acbbc12b96248.pnghttps://i-blog.csdnimg.cn/blog_migrate/c99292f0053469e62a677246bc44ab5a.png
好嘞,随机找一串串代码放到App.vue中试试(不要试着从图片中照抄我的哈,自己去官网找一个试试Arco Design Vue)咱,主打一个快速。
https://i-blog.csdnimg.cn/blog_migrate/90a4012ff9f1fcf4f5ef258081b7ebcd.png
嚯,出现了!那么组件库是能用哒!
好,第二步也就完成了。
这里我发起每做几步就开启调试一下。
3.调解目次,初始化项目:
1.清空components(把HelloWorld.vue删了)
2.新建目次api,utils,views
3.把App.vue中用不到的代码都给删了,留一个 <router-view />就好了,然后,把router的index.js的代码全给解释了(emmm,直接删了感觉太贫苦,解释了背面写起来好做参照)
https://i-blog.csdnimg.cn/blog_migrate/49c4f12d9a37a396ad55349844b286ba.png目前的目次结构就是如许了;
https://i-blog.csdnimg.cn/blog_migrate/2bae0db1d94c2b60f9cf79285d4933d3.png(App.vue就变成如许啦)
4.定义请求工具:
大家不要一开始写前端就直奔优美的”可跳转“页面,这边先整体规定一个向后端发请求的工具request.js
在utils目次下创建request.js文件:
import axios from 'axios';//导入axios
//定义前缀
const URL = 'http://localhost:8080';
const instance = axios.create({URL})
//来一个响应拦截器
instance.interceptors.response.use(
result=>{
if(result.data.code == 0){
return result.data;
}
//如果不为0则表示失败
alert(result.data.message||'出现错误')
return Promise.reject(err);//异步的状态转化成失败的状态
},
err=>{
alert('服务异常');
return Promise.reject(err);//异步的状态转化成失败的状态
}
)
export default instance; 表明一下这段代码:引入发请求的axios,然后定义一个开辟时期的请求必有前缀(这里直接写http://localhost:8080着实是有题目的,对于背面出现的跨域题目....emmmm,着实前端后端都有方式办理,看情况吧,背面再讲),做一个相应拦截器,对结果进行判断,然后导出
(这里需要提示一下统一相应有哪些(不然可能会不太好理解))
后端那一块统一相应数据:code:0表现乐成,1表现失败;msg: 提示信息;data:数据
前端代码编写开始!!
OK啊各位,初始化完成我们便要开始编写代码了。
首先,我们先明白一波步骤:
确定布局 --> 添补各部分代码 --> 后端插入
(如果涉及与后端的交互,遵照以下步骤
1.搭建页面(html,css)-> 2.绑定数据与事件 -> 3.调用后端接口)
好嘞,认识了吗各位,不熟练也没事,我们先找一个练练手。
先从组件库这里找到布局:
https://i-blog.csdnimg.cn/blog_migrate/7cd5a2e94aec5f3778cd8f5fd49c82e1.png
这布局,看似普通,实则帅的雅痞,就它了。引入代码
回到目次component下,创建一个新的文件GlobalPage.vue
(众所周知的小技巧:<vue>可快速构建vue文件)
<template>
<a-layout style="height: 400px;">
<a-layout-header>Header</a-layout-header>
<a-layout>
<a-layout-sider theme="dark">Sider</a-layout-sider>
<a-layout-content>Content</a-layout-content>
</a-layout>
<a-layout-footer>Footer</a-layout-footer>
</a-layout>
</template>
<script>
export default {
}
</script>
<style scoped>
.layout-demo :deep(.arco-layout-header),
.layout-demo :deep(.arco-layout-footer),
.layout-demo :deep(.arco-layout-sider-children),
.layout-demo :deep(.arco-layout-content) {
display: flex;
flex-direction: column;
justify-content: center;
color: var(--color-white);
font-size: 16px;
font-stretch: condensed;
text-align: center;
}
.layout-demo :deep(.arco-layout-header),
.layout-demo :deep(.arco-layout-footer) {
height: 64px;
background-color: var(--color-primary-light-4);
}
.layout-demo :deep(.arco-layout-sider) {
width: 206px;
background-color: var(--color-primary-light-3);
}
.layout-demo :deep(.arco-layout-content) {
background-color: rgb(var(--arcoblue-6));
}
</style> 然后我们改一下index.js文件(将GlobalPage引入)(要是看着那些注解感觉不美观的话就直接删了)
import { createRouter, createWebHashHistory } from 'vue-router'
import MainPage from '../components/GlobalPage.vue'
const routes = [
// {
// path: '/',
// name: 'home',
// component: HomeView
// },
// {
// path: '/about',
// name: 'about',
// // route level code-splitting
// // this generates a separate chunk (about..js) for this route
// // which is lazy-loaded when the route is visited.
// component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
// }
{
path: '/',
name: 'mainPage',
component: MainPage
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router
运行一手看看(记得每次有一些大改就要看看情况,改多再看就会很贫苦,bug也不好排查)
https://i-blog.csdnimg.cn/blog_migrate/0f980828295d33b887fe016011e75091.png运行出来就是这么个界面
搭建Header和Footer代码
先把头部和尾部的代码办理了。
先来尾部吧,我觉得这个比较简朴(哈)
一样平常来说,网站的底部都是一些网站运营的介绍什么的(大多都是哈,也不一定全是)
https://i-blog.csdnimg.cn/blog_migrate/a3977313e934f772b59fe764d4ca5882.png
这里我就以大家都爱的4399为例(大多都是哈,也不一定全是,哈哈哈)
emmm,这里我们可以把Footer这一块封装为一个组件,因为固然定义的GlobalPage属于是全局的页面,但万一之后会跳转到其他的页面呢,这里我觉得封装成组件更好一些(看起来也更轻巧一些)
在views目次下创建GlobalFooter.vue
<template>
<div id="header">由Heath ceTide 创作的网站 XXX 有限公司</div>
</template>
<script>
export default {};
</script>
<style>
#header {
font-family: "Satisfy", cursive;
font-size: 16px;
color: rgb(102, 149, 164);
margin-right: 20px;
}
</style> 差不多了,将其更换掉GlobalPage的header
<template>
<a-layout style="height: 400px;">
<a-layout-header>Header</a-layout-header>
<a-layout>
<a-layout-sider theme="dark">Sider</a-layout-sider>
<a-layout-content>Content</a-layout-content>
</a-layout>
<a-layout-footer>
<global-footer></global-footer>
</a-layout-footer>
</a-layout>
</template>
<script>
import GlobalFooter from '../views/GlobalFooter.vue'
export default {
components: { GlobalFooter },
}
</script> https://i-blog.csdnimg.cn/blog_migrate/79c79ca3b9046cf2dee7e861a1198c4c.png
展示出了样式就行了,(之后可以美化以下),好,然后我们开始整Header,
这一块导航栏,我觉得吧,还是用组件比较合适(倒不是不会整,究竟也贫苦,不消自己手敲的绝不自己手敲代码)
https://i-blog.csdnimg.cn/blog_migrate/382e5dd48b850f845f26d5b1a54d3097.png
就选这个深色模式导航啦,新建GlobalHeader.vue文件把代码用CV大法放进去
<template>
<div class="menu-demo">
<a-menu mode="horizontal" theme="dark" :default-selected-keys="['1']">
<a-menu-item key="0" :style="{ padding: 0, marginRight: '38px' }" disabled>
<div
:style="{
width: '80px',
height: '30px',
background: 'var(--color-fill-3)',
cursor: 'text',
}"
/>
</a-menu-item>
<a-menu-item key="1">Home</a-menu-item>
<a-menu-item key="2">Solution</a-menu-item>
<a-menu-item key="3">Cloud Service</a-menu-item>
<a-menu-item key="4">Cooperation</a-menu-item>
</a-menu>
</div>
</template>
<style scoped>
.menu-demo {
box-sizing: border-box;
width: 100%;
background-color: var(--color-neutral-2);
}
</style>
<template>
<a-layout style="height: 400px">
<a-layout-header><global-header></global-header></a-layout-header>
<a-layout>
<a-layout-sider theme="dark">Sider</a-layout-sider>
<a-layout-content>Content</a-layout-content>
</a-layout>
<a-layout-footer>
<global-footer class="footer"></global-footer>
</a-layout-footer>
</a-layout>
</template>
<script>
import GlobalFooter from "../views/GlobalFooter.vue";
import GlobalHeader from "../views/GlobalHeader.vue";
export default {
components: { GlobalFooter, GlobalHeader },
};
</script>
<style scoped>
.layout-demo :deep(.arco-layout-header),
.layout-demo :deep(.arco-layout-footer),
.layout-demo :deep(.arco-layout-sider-children),
.layout-demo :deep(.arco-layout-content) {
display: flex;
flex-direction: column;
justify-content: center;
color: var(--color-white);
font-size: 16px;
font-stretch: condensed;
text-align: center;
}
.layout-demo :deep(.arco-layout-header),
.layout-demo :deep(.arco-layout-footer) {
height: 64px;
background-color: var(--color-primary-light-4);
}
.layout-demo :deep(.arco-layout-sider) {
width: 206px;
background-color: var(--color-primary-light-3);
}
.layout-demo :deep(.arco-layout-content) {
background-color: rgb(var(--arcoblue-6));
}
.footer {
background-color: aliceblue;
padding: 16px;
position: sticky;
bottom: 0;
left: 0;
right: 0;
text-align: center;
letter-spacing: 3px;
}
</style> https://i-blog.csdnimg.cn/blog_migrate/16796cc717c8c551ebbf88834ceae784.png
着实这个空的区域可以加一个logo或者其他什么的
https://i-blog.csdnimg.cn/blog_migrate/b67b0f9998fe9da40bff0d0be67ef254.png
呐,就像如许
OK,目前的页面就是这个样子了;
搭建搜索页面
好的,下面整一个全局的搜索框页面吧
创建一个SearchPage.vue 文件
从组件库中找到一个合适的搜索框
https://i-blog.csdnimg.cn/blog_migrate/8af33e57d2ea992daa0fe7b043221d57.png
<!--SearchPage.vue代码-->
<template>
<a-space direction="vertical" size="large">
<a-input-search
:style="{ width: '320px' }"
placeholder="Please enter something"
button-text="Search"
search-button
/>
</a-space>
</template>
<script>
export default {};
</script>
<style>
</style> 将新组件放到GlobalPage中(临时的,之后还是要处理路由的)
<template>
<a-layout style="height: 400px">
<a-layout-header><global-header></global-header></a-layout-header>
<a-layout>
<a-layout-sider theme="dark">Sider</a-layout-sider>
<a-layout-content><search-page></search-page></a-layout-content>
</a-layout>
<a-layout-footer>
<global-footer class="footer"></global-footer>
</a-layout-footer>
</a-layout>
</template>
<script>
import GlobalFooter from "../views/GlobalFooter.vue";
import GlobalHeader from "../views/GlobalHeader.vue";
import SearchPage from '../views/SearchPage.vue';
export default {
components: { GlobalFooter, GlobalHeader, SearchPage },
};
</script> https://i-blog.csdnimg.cn/blog_migrate/d75ddc63f7ee5cadf44af446e7e493df.png
如今搜索框就出来了,(这里最右边加了一点点小细节(不紧张)之后会把代码发出来)
这里着实可以加一个搜索框等候结果
<template>
<div id="search">
<a-space direction="vertical" size="large">
<a-input-search
:style="{ width: '320px' }"
placeholder="Please enter something"
button-text="Search"
search-button
/>
</a-space>
<a-space direction="vertical" size="large">
<a-input-search
:style="{ width: '320px' }"
placeholder="Please enter something"
button-text="Search"
search-button
loading
/>
</a-space>
</div>
</template>
<script>
export default {};
</script>
<style>
</style> 这里着实是复制了两个搜索框代码,不外别的一个加上了loading属性,如许就能表现出等候中的结果
https://i-blog.csdnimg.cn/blog_migrate/5a6a4726650c1d7300b956eca085a437.png
呐呐呐,就是如许,然后我们再用v-if定义一下它的表现和隐蔽就可以了
ok,演示一下:
先设置script 为setup,然后引入ref
<script setup>
import {ref} from 'vue'; 还记得之前说的三部曲吗: 1.搭建页面(html,css)-> 2.绑定数据与实践 -> 3.调用后端接口)
那我们以及写好了搜索框了,也该进行数据绑定了(这里临时不进行后端接口调用,(究竟还没开辟))
对于一个组件的表现和隐蔽我们直接写
<script setup>
import {ref} from 'vue';const isSearch = ref(false) 然后呢,两个搜索框绑定该属性(一个是isSearch,一个是!isSearch),如许就能保持一个表现,一个隐蔽了。那么,怎样实现转换呢,平时在搜索的时间,当我们点击了搜索按钮的时间就会出现转换结果,如果网比较好的话,估计也就直接跳转了,(如果网不好的话,搜索框转圈转了一会儿就会恢复原样)
那么,我们定义一个函数,在正常情况下点击搜索的时间触发,转换为搜索中的样式,然后过几秒就恢复原状。
那么开始定义吧;
<script setup>
import {ref} from 'vue';const isSearch = ref(false)const onSearch = () => {isSearch.value = true;setTimeout(() => { isSearch.value = false;}, 5000);};</script> 这里定义了一个函数,点击之后,isSearch改变,比及五秒之后,值恢复。来试试吧
<template><div id="search"> <a-space direction="vertical" size="large" v-if="!isSearch"> <a-input-search :style="{ width: '320px' }" placeholder="Please enter something" button-text="Search" search-button @click=onSearch /> </a-space> <a-space direction="vertical" size="large" v-if="isSearch"> <a-input-search :style="{ width: '320px' }" placeholder="Please enter something" button-text="Search" search-button loading /> </a-space></div></template><script setup>
import {ref} from 'vue';const isSearch = ref(false)const onSearch = () => {isSearch.value = true;setTimeout(() => { isSearch.value = false;}, 5000);};</script> https://i-blog.csdnimg.cn/blog_migrate/047efe230f550bd178a6cc705ceb0d43.pnghttps://i-blog.csdnimg.cn/blog_migrate/22e2d4a3dc4d3507b95df2f6e1f4299c.png
乐成了,那再来美满一下
有搜索框,固然要有表现搜索内容的区域,
再去组件库看看有没有什么合适的
https://i-blog.csdnimg.cn/blog_migrate/4fdbaec41d675edec1b8206545b1b789.png
就用这个吧,
<template>
<div id="searchPage">
<div class="search">
<a-space direction="vertical" size="large" v-if="!isSearch">
<a-input-search
:style="{ width: '620px' }"
placeholder="Please enter something"
button-text="Search"
search-button
@click="onSearch"
/>
</a-space>
<a-space direction="vertical" size="large" v-if="isSearch">
<a-input-search
:style="{ width: '620px' }"
placeholder="Please enter something"
button-text="Search"
search-button
loading
/>
</a-space>
</div>
<a-space direction="vertical" size="large">
<a-radio-group v-model="type" type="button">
<a-radio value="line">Line</a-radio>
<a-radio value="card">Card</a-radio>
<a-radio value="card-gutter">Card Gutter</a-radio>
<a-radio value="text">Text</a-radio>
<a-radio value="rounded">Rounded</a-radio>
<a-radio value="capsule">Capsule</a-radio>
</a-radio-group>
<a-radio-group v-model="size" type="button">
<a-radio value="mini">Mini</a-radio>
<a-radio value="small">Small</a-radio>
<a-radio value="medium">Medium</a-radio>
<a-radio value="large">Large</a-radio>
</a-radio-group>
<a-tabs :type="type" :size="size">
<a-tab-pane key="1" title="Tab 1"> Content of Tab Panel 1 </a-tab-pane>
<a-tab-pane key="2" title="Tab 2"> Content of Tab Panel 2 </a-tab-pane>
<a-tab-pane key="3" title="Tab 3"> Content of Tab Panel 3 </a-tab-pane>
</a-tabs>
</a-space>
</div>
</template>
<script setup>
import { ref } from "vue";
const isSearch = ref(false);
const onSearch = () => {
isSearch.value = true;
setTimeout(() => {
isSearch.value = false;
}, 5000);
};
</script>
<style scoped>
.search{
margin: 30px auto;
}
</style> 添加代码并做一些优化
https://i-blog.csdnimg.cn/blog_migrate/b59a350e536f143bb03bac92d294c197.png
目前就是这个样子了。
emmm,感觉不太对,好像有点快了,要不还是做一个登录注册页面吧。。。
搭建登录注册页面
创建LoginPage.vue
这一块我觉得还挺容易的,先给个示例代码吧
<template>
<div class="container">
<div class="login-box">
<!-- Login Form -->
<form action="">
<h2>Login</h2>
<div class="input-box">
<span class="icon"><i class="fa-solid fa-envelope"></i></span>
<input type="email" required placeholder="Email" />
</div>
<div class="input-box">
<span class="icon"><i class="fa-solid fa-lock"></i></span>
<input type="password" placeholder="Password" required />
</div>
<div class="remember-forget">
<label><input type="checkbox" />Remember Me</label>
<a href="#">Forgot Password?</a>
</div>
<button type="submit">Login</button>
<div class="register-link">
<a href="#">Don't have an account? Create Now!</a>
</div>
</form>
</div>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Poppins", sans-serif;
}
.container {
width: 100%;
height: 100vh;
background: url("../assets/background.jpg") no-repeat;
background-size: cover;
background-position: center;
display: flex;
justify-content: center;
align-items: center;
}
.container .login-box {
position: relative;
width: 390px;
height: 420px;
background-color: transparent;
border: 2px solid rgba(255, 255, 255, 0.5);
border-radius: 20px;
display: flex;
justify-content: center;
align-items: center;
backdrop-filter: blur(15px);
}
.login-box h2 {
font-size: 28px;
color: #fff;
text-align: center;
}
.login-box .input-box {
position: relative;
width: 310px;
margin: 30px 0;
border-bottom: 2px solid #fff;
}
.input-box input {
width: 100%;
height: 50px;
background: transparent;
border: none;
outline: none;
font-size: 16px;
color: #fff;
padding: 0 35px 0 5px;
}
.input-box input::placeholder {
color: #f9f9f9;
}
.input-box .icon {
position: absolute;
right: 8px;
color: #fff;
font-size: 18px;
line-height: 50px;
}
.login-box .remember-forget {
margin: -15px 0 15px;
font-size: 15px;
color: #fff;
display: flex;
justify-content: space-between;
}
.remember-forget label input {
margin-right: 3px;
}
.login-box button {
width: 100%;
height: 40px;
background: #fff;
border: none;
outline: none;
border-radius: 40px;
cursor: pointer;
font-size: 16px;
color: #000;
transition: all 0.5s;
}
.login-box button:hover {
background: #1f73c9;
color: #fff;
}
.login-box .register-link {
font-size: 15px;
color: #fff;
text-align: center;
margin: 20px 0 10px;
}
.remember-forget a,
.register-link a {
color: #fff;
text-decoration: none;
}
.remember-forget a:hover,
.register-link a:hover {
text-decoration: underline;
}
/* Responsive Design */
@media (max-width: 460px) {
.container .login-box {
width: 350px;
}
.login-box .input-box {
width: 290px;
}
}
@media (max-width: 360px) {
.container .login-box {
width: 100%;
height: 100vh;
border: none;
}
}
</style> 这一块代码是之前找到的一个登录页代码,我觉着就还挺好https://i-blog.csdnimg.cn/blog_migrate/f655d96e3fdc8c040930d08b5aa6e68f.png
不外吧,我决定还是不消这个代码,去组件库上找找吧(主要还是要加深一下组件库的使用)
好了就用这个
https://i-blog.csdnimg.cn/blog_migrate/6f047519c6804f1ff917d190216d26f3.png
小改一下吧;
<template>
<div class="container">
<div class="login-box">
<a-form
:model="form"
:style="{ width: '600px' }"
@submit="handleSubmit"
class="input-box"
>
<h2 style="margin-bottom: 60px">Login</h2>
<a-form-item
field="name"
tooltip="Please enter username"
label="账号"
class="element"
>
<a-input
v-model="form.name"
placeholder="please enter your username..."
style="margin-right: 40px"
/>
</a-form-item>
<a-form-item field="post" label="密码" class="element">
<a-input
v-model="form.post"
placeholder="please enter your password..."
style="margin-right: 40px"
/>
</a-form-item>
<a-form-item field="isRead">
<a-checkbox v-model="form.isRead">
I have read the manual
</a-checkbox>
</a-form-item>
<a-form-item>
<a-button html-type="submit" class="input-box">Submit</a-button>
</a-form-item>
<div class="register-link">
<a href="#">Don't have an account? Create Now!</a>
</div>
</a-form>
</div>
</div>
</template>
<script>
</script>
<style scoped>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Poppins", sans-serif;
display: flex;
justify-content: center;
}
.container {
width: 100%;
height: 100vh;
background: url("../assets/background.jpg") no-repeat;
background-size: cover;
background-position: center;
display: flex;
justify-content: center;
align-items: center;
}
.container .login-box {
position: relative;
width: 500px;
height: 580px;
background-color: transparent;
border: 2px solid rgba(255, 255, 255, 0.5);
border-radius: 20px;
display: flex;
justify-content: center;
align-items: center;
backdrop-filter: blur(15px);
}
.login-box h2 {
font-size: 28px;
color: #fff;
text-align: center;
}
.login-box .input-box {
position: relative;
width: 310px;
margin: 30px 0;
}
.input-box input {
width: 80%;
height: 60px;
background: transparent;
border: none;
outline: none;
font-size: 16px;
color: #fff;
padding: 0 2px 0 5px;
}
.input-box input::placeholder {
color: #f9f9f9;
}
.input-box .icon {
position: absolute;
right: 8px;
color: #fff;
font-size: 16px;
line-height: 25px;
}
.login-box .remember-forget {
margin: -15px 0 15px;
font-size: 15px;
color: #fff;
display: flex;
justify-content: space-between;
}
.remember-forget label input {
margin-right: 30px;
}
.login-box button {
width: 100%;
height: 40px;
background: #fff;
border: none;
outline: none;
border-radius: 40px;
cursor: pointer;
font-size: 16px;
color: #000;
transition: all 0.5s;
}
.login-box button:hover {
background: #1f73c9;
color: #fff;
}
.login-box .register-link {
font-size: 15px;
color: #fff;
text-align: center;
margin: 5px 0 5px;
}
.remember-forget a,
.register-link a {
color: #fff;
text-decoration: none;
}
.remember-forget a:hover,
.register-link a:hover {
text-decoration: underline;
}
/* Responsive Design */
@media (max-width: 460px) {
.container .login-box {
width: 350px;
}
.login-box .input-box {
width: 290px;
}
}
@media (max-width: 360px) {
.container .login-box {
width: 100%;
height: 100vh;
border: none;
}
}
.element {
margin: 20px 0;
}
</style> emmm,这代码可谓一坨(发出来也需要些勇气啊。。)
大家如果有自己的写的规范代码就用自己的(hhh)
那么,我们开始前面的三部曲:搭建页面以及完成,可以开始绑定数据与事件了。
<script setup>
import {ref} from 'vue';const loginData = ref({ username: '', password: '', isRead: false,}) 先引入ref,然后创建loginData,然后v-model绑定数据
<template><div class="container"> <div class="login-box"> <a-form :model="loginData" :style="{ width: '600px' }" @submit="handleSubmit" class="input-box" > <h2 style="margin-bottom: 60px">Login</h2> <a-form-item field="name" tooltip="Please enter username" label="账号" class="element" :rules= "rules" > <a-input v-model="loginData.username" placeholder="please enter your username..." style="margin-right: 40px" /> </a-form-item> <a-form-item field="post" label="密码" class="element" :rules= "rules"> <a-input v-model="loginData.password" placeholder="please enter your password..." style="margin-right: 40px" /> </a-form-item> <a-form-item field="isRead"> <a-checkbox v-model="loginData.isRead"> I have read the manual </a-checkbox> </a-form-item> <a-form-item> <a-button html-type="submit" class="input-box">Submit</a-button> </a-form-item> <div class="register-link"> <a href="#">Don't have an account? Create Now!</a> </div> </a-form> </div></div></template><script setup>
import {ref} from 'vue';const loginData = ref({ username: '', password: '', isRead: false,})const rules = [{ validator: (value, cb) => { return new Promise(resolve => { window.setTimeout(() => { if (value !== ' ') { cb('content not empty') } resolve() }, 1000) }) } }];</script><style scoped>* {margin: 0;padding: 0;box-sizing: border-box;font-family: "Poppins", sans-serif;display: flex;justify-content: center;}.container {width: 100%;height: 100vh;background: url("../assets/background.jpg") no-repeat;background-size: cover;background-position: center;display: flex;justify-content: center;align-items: center;}.container .login-box {position: relative;width: 500px;height: 580px;background-color: transparent;border: 2px solid rgba(255, 255, 255, 0.5);border-radius: 20px;display: flex;justify-content: center;align-items: center;backdrop-filter: blur(15px);}.login-box h2 {font-size: 28px;color: #fff;text-align: center;}.login-box .input-box {position: relative;width: 310px;margin: 30px 0;}.input-box input {width: 80%;height: 60px;background: transparent;border: none;outline: none;font-size: 16px;color: #fff;padding: 0 2px 0 5px;}.input-box input::placeholder {color: #f9f9f9;}.input-box .icon {position: absolute;right: 8px;color: #fff;font-size: 16px;line-height: 25px;}.login-box .remember-forget {margin: -15px 0 15px;font-size: 15px;color: #fff;display: flex;justify-content: space-between;}.remember-forget label input {margin-right: 30px;}.login-box button {width: 100%;height: 40px;background: #fff;border: none;outline: none;border-radius: 40px;cursor: pointer;font-size: 16px;color: #000;transition: all 0.5s;}.login-box button:hover {background: #1f73c9;color: #fff;}.login-box .register-link {font-size: 15px;color: #fff;text-align: center;margin: 5px 0 5px;}.remember-forget a,.register-link a {color: #fff;text-decoration: none;}.remember-forget a:hover,.register-link a:hover {text-decoration: underline;}/* Responsive Design */@media (max-width: 460px) {.container .login-box { width: 350px;}.login-box .input-box { width: 290px;}}@media (max-width: 360px) {.container .login-box { width: 100%; height: 100vh; border: none;}}.element {margin: 20px 0;}</style> 这里可以添加一个校验规则,
https://i-blog.csdnimg.cn/blog_migrate/ec494325c042c5d3764af42e6b82a754.png在组件库这里找一下表单的校验规则
<script setup>
import {ref} from 'vue';const loginData = ref({ username: '', password: '', isRead: false,})const rules = [{ validator: (value, cb) => { return new Promise(resolve => { window.setTimeout(() => { if (value === ' ') { cb('content not empty') } resolve() }, 1000) }) } }];</script> 任意定义了一个,大家可以自己定义看看,(emmm,这里我感觉element-ui的校验规则更好一丢丢)。
好了,既然定义好了登录界面,就可以试试向后端发起请求了。
这里开始在api文件夹下面创建一个文件user.js然后编写一个登录接口函数
https://i-blog.csdnimg.cn/blog_migrate/267106593534df020cc69cb0c01c6258.png
import request from '../utils/request'
//创建一个调用登录接口函数
export const userLoginService = (loginData) =>{
//用urlSearchParams完成传递
const params = new URLSearchParams()
for(let key in loginData){
params.append(key,loginData);
}
return request.post('/user/login',params);
} 定义之后就去登录页调用
<a-form-item>
<a-button html-type="submit" class="input-box" @click="login"
>Submit</a-button
>
</a-form-item> 在submit提交这里加上@click="login"
然后定义方法:(获取信息,如果msg提示信息不为0,则表现消息,为0就表现登岸乐成)
const login = async()=>{
let result = await userLoginService(loginData.value);
alert(result.msg?result.msg:'登录成功');
} 不外,这里用欣赏器默认的alert感觉不太美观啊,究竟都用组件库了,
https://i-blog.csdnimg.cn/blog_migrate/fa4efcb1689c9f8b0f8d235ecc1bf040.png
消息类型:就决定是你了!
引入一手修改代码,
<script setup>
import { h } from 'vue';
import { IconExclamationCircleFill } from '@arco-design/web-vue/es/icon';
import { ref } from "vue";
import {userLoginService} from '../api/user'
const loginData = ref({
username: "",
password: "",
isRead: false,
});
const rules = [
{
validator: (value, cb) => {
return new Promise((resolve) => {
window.setTimeout(() => {
if (value !== " ") {
cb("content not empty");
}
resolve();
}, 1000);
});
},
},
];
const renderIcon = () => h(IconExclamationCircleFill);
const login = async()=>{
let result = await userLoginService(loginData.value);
renderIcon(result.msg?result.msg:'登录成功');
}
</script>
好,感觉如许也就差不多了,下面展示一下登录页代码
<template><div class="container"> <div class="login-box"> <a-form :model="loginData" :style="{ width: '600px' }" @submit="handleSubmit" class="input-box" > <h2 style="margin-bottom: 60px">Login</h2> <a-form-item field="name" tooltip="Please enter username" label="账号" class="element" :rules="rules" > <a-input v-model="loginData.username" placeholder="please enter your username..." style="margin-right: 40px" /> </a-form-item> <a-form-item field="post" label="密码" class="element" :rules="rules"> <a-input v-model="loginData.password" placeholder="please enter your password..." style="margin-right: 40px" /> </a-form-item> <a-form-item field="isRead"> <a-checkbox v-model="loginData.isRead"> I have read the manual </a-checkbox> </a-form-item> <a-form-item>
<a-button html-type="submit" class="input-box" @click="login"
>Submit</a-button
>
</a-form-item> <div class="register-link"> <a href="#">Don't have an account? Create Now!</a> </div> </a-form> </div></div></template><script setup>
import { h } from 'vue';
import { IconExclamationCircleFill } from '@arco-design/web-vue/es/icon';
import { ref } from "vue";
import {userLoginService} from '../api/user'
const loginData = ref({
username: "",
password: "",
isRead: false,
});
const rules = [
{
validator: (value, cb) => {
return new Promise((resolve) => {
window.setTimeout(() => {
if (value !== " ") {
cb("content not empty");
}
resolve();
}, 1000);
});
},
},
];
const renderIcon = () => h(IconExclamationCircleFill);
const login = async()=>{
let result = await userLoginService(loginData.value);
renderIcon(result.msg?result.msg:'登录成功');
}
</script><style scoped>* {margin: 0;padding: 0;box-sizing: border-box;font-family: "Poppins", sans-serif;display: flex;justify-content: center;}.container {width: 100%;height: 100vh;background: url("../assets/background.jpg") no-repeat;background-size: cover;background-position: center;display: flex;justify-content: center;align-items: center;}.container .login-box {position: relative;width: 500px;height: 580px;background-color: transparent;border: 2px solid rgba(255, 255, 255, 0.5);border-radius: 20px;display: flex;justify-content: center;align-items: center;backdrop-filter: blur(15px);}.login-box h2 {font-size: 28px;color: #fff;text-align: center;}.login-box .input-box {position: relative;width: 310px;margin: 30px 0;}.input-box input {width: 80%;height: 60px;background: transparent;border: none;outline: none;font-size: 16px;color: #fff;padding: 0 2px 0 5px;}.input-box input::placeholder {color: #f9f9f9;}.input-box .icon {position: absolute;right: 8px;color: #fff;font-size: 16px;line-height: 25px;}.login-box .remember-forget {margin: -15px 0 15px;font-size: 15px;color: #fff;display: flex;justify-content: space-between;}.remember-forget label input {margin-right: 30px;}.login-box button {width: 100%;height: 40px;background: #fff;border: none;outline: none;border-radius: 40px;cursor: pointer;font-size: 16px;color: #000;transition: all 0.5s;}.login-box button:hover {background: #1f73c9;color: #fff;}.login-box .register-link {font-size: 15px;color: #fff;text-align: center;margin: 5px 0 5px;}.remember-forget a,.register-link a {color: #fff;text-decoration: none;}.remember-forget a:hover,.register-link a:hover {text-decoration: underline;}/* Responsive Design */@media (max-width: 460px) {.container .login-box { width: 350px;}.login-box .input-box { width: 290px;}}@media (max-width: 360px) {.container .login-box { width: 100%; height: 100vh; border: none;}}.element {margin: 20px 0;}</style> 好了,本日的前端就忙碌到这里吧(下一篇文章再见)。
总结一下:1.完成了前端初始化4步,2.完成了全局页面的布局,3.完成了搜索页的代码,和登录页的代码。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]