以简单的登录功能为例子
1.在util中创建loginValidators.ts
import { ref, reactive } from 'vue'
interface User{
email: string;
password: string;
}
export const loginUser=reactive<User>({
email: '',
password: ''
})
interface Rules{
email: {
required: boolean;
message: string;
trigger: string;
}[];
password: ({
required: boolean;
message: string;
trigger: string;
min?: undefined;
max?: undefined;
} | {
min: number;
max: number;
message: string;
trigger: string;
required?: undefined;
})[];
}
export const rules=reactive<Rules>({
email: [
{ required: true, message: '密码不得为空', trigger: 'blur' }
// {
// required: true,
// type: 'email',
// message: 'email格式错误',
// trigger: 'blur'
// }
],
password: [
{ required: true, message: '密码不得为空', trigger: 'blur' },
{ min: 6, max: 30, message: '密码长度必须在6到30之间', trigger: 'blur' }
]
})
2.在登录页面中引用刚才创建的验证ts
3.创建登录组件
传入得参数(此步骤在登录界面引用登录组件后传入的参数:查看第4步骤)
就可以使用ts中创建的参数
登录组件代码(可看可不看)
<template>
<!-- 登录 -->
<el-form
:model="loginUser"
:rules="rules"
ref="loginForm"
label-width="100px"
class="login-form sign-in-form"
>
<el-form-item label="邮箱" prop="email">
<el-input v-model="loginUser.email" placeholder="Enter Email..." />
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input
v-model="loginUser.password"
type="password"
placeholder="Enter Password..."
/>
</el-form-item>
<el-form-item>
<el-button
@click="handleLogin('loginForm')"
type="primary"
class="submit-btn"
>提交</el-button
>
</el-form-item>
<!-- 找回密码 -->
<el-form-item>
<p class="tiparea">忘记密码<a>立即找回</a></p>
</el-form-item>
</el-form>
</template>
<script lang="ts">
import { getCurrentInstance } from 'vue'
import { useRouter } from 'vue-router'
import { login } from '@/api/login'
export default {
name: 'LoginForm',
props: {
loginUser: {
type: Object,
required: true
},
rules: {
type: Object,
required: true
}
},
setup(props: any) {
const router = useRouter()
// 通过解构getCurrentInstance,获取this,这里的this就是ctx
// @ts-ignore
const { ctx,proxy } = getCurrentInstance()
// 触发登录方法
const handleLogin = (formName: string) => {
console.log(ctx)
ctx.$refs[formName].validate(async (valid: boolean) => {
if (valid) {
//await是等待的意思
const res = await login(props.loginUser)
// if(res==false){
// proxy.$message.warning("res是方法返回来的数据")
// }else{
// proxy.$message.success("123")
// router.push('/home')
// }
proxy.$message.success("123")
router.push('/home')
} else {
console.log('error submit!')
return false
}
})
}
return { handleLogin }
}
}
</script>
<style scoped>
/* register */
.login-form,
.register-form {
background-color: #fff;
padding: 50px 80px 20px 20px;
border-radius: 5px;
box-shadow: 0px 5px 10px #cccc;
}
.submit-btn {
width: 100%;
}
.tiparea {
text-align: right;
font-size: 12px;
color: #333;
width: 100%;
}
.tiparea a {
color: #409eff;
}
</style>
4.在登录页面中引入登录组件
登录界面代码(可看可不看)
<template>
<div class="container" :class="{ 'sign-up-mode': signUpMode }">
<!-- form表单容器 -->
<div class="form-container">
<div class="signin-signup">
<!-- 登录 -->
<LoginForm :loginUser="loginUser" :rules="rules"></LoginForm>
<!-- 注册 -->
<RegisterForm :registerUser="registerUser" :registerRules="registerRules"></RegisterForm>
</div>
</div>
<!-- 左右切换动画 -->
<div class="panels-container">
<div class="panel left-panel">
<div class="content">
<h3>Row,row,row your boat</h3>
<p>Gentlely down the stream</p>
<button @click="signUpMode = !signUpMode" class="btn transparent">
注册
</button>
</div>
<!-- <img src="@/assets" alt=""> -->
</div>
<div class="panel right-panel">
<div class="content">
<h3>Merrily,merrily,merrily,merrily,</h3>
<p>Life is but a dream</p>
<button @click="signUpMode = !signUpMode" class="btn transparent">
登录
</button>
</div>
<!-- <img src="@/assets" alt=""> -->
</div>
</div>
<!-- <el-form
:model="loginUser"
:rules="rules"
ref="loginForm"
label-width="100px"
class="login-form sign-in-form"
>
<el-form-item label="邮箱" prop="email">
<el-input v-model="loginUser.email" placeholder="Enter Email..." />
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input
v-model="loginUser.password"
type="password"
placeholder="Enter Password..."
/>
</el-form-item>
<el-form-item>
<el-button type="primary" class="submit-btn" @click="handleLogin('loginForm')">提交</el-button>
</el-form-item>
<el-form-item>
<p class="tiparea">忘记密码<a>立即找回</a></p>
</el-form-item>
</el-form> -->
</div>
</template>
<script lang="ts">
import {ref,reactive,getCurrentInstance } from 'vue'
import {loginUser,rules} from '@/utils/loginValidators' //登录验证规则
import {registerUser ,registerRules } from '@/utils/registerValidator' //注册验证规则
import LoginForm from '@/components/LoginForm.vue' //登录组件
import RegisterForm from '@/components/RegisterForm.vue' //注册组件
export default {
name: 'LoginRegister',
components:{LoginForm,RegisterForm},
setup() {
// 登录/注册模式
const signUpMode = ref(false)
// 通过解构getCurrentInstance,获取this,这里的this就是ctx
// @ts-ignore
// const { ctx } = getCurrentInstance()
// const loginUser=reactive({
// email:'',
// password:''
// })
// //校验规则
// const rules=reactive({
// email:[
// {
// required: true,
// type: 'email',
// message: 'email格式错误',
// trigger: 'blur'
// }
// ],
// password:[
// {required:true,message:'密码不能为空',trigger:'blur'},
// { min: 6, max: 30, message: '密码长度必须在6到30之间', trigger: 'blur' }
// ]
// })
//提交
// const handleLogin=(formName:string)=>{
// console.log( ctx.loginUser.password)
// ctx.$refs[formName].validate((valid:boolean)=>{
// if (valid) {
// console.log("提交吧")
// }else{
// console.log("不提交了")
// return false
// }
// })
// }
return {signUpMode,loginUser,rules,registerUser,registerRules}
}
}
</script>
<style scoped>
.container {
position: relative;
width: 100%;
min-height: 100vh;
background-color: #fff;
overflow: hidden;
}
.form-container {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
.signin-signup {
position: relative;
top: 50%;
left: 75%;
transform: translate(-50%, -50%);
width: 44%;
transition: 1s 0.7s ease-in-out;
display: grid;
grid-template-columns: 1fr;
z-index: 5;
}
/* 左右切换动画 */
.social-text {
padding: 0.7rem 0;
font-size: 1rem;
}
.social-media {
display: flex;
justify-content: center;
}
.social-icon {
height: 46px;
width: 46px;
display: flex;
justify-content: center;
align-items: center;
margin: 0 0.45rem;
color: #333;
border-radius: 50%;
border: 1px solid #333;
text-decoration: none;
font-size: 1.1rem;
transition: 0.3s;
}
.social-icon:hover {
color: #4481eb;
border-color: #4481eb;
}
.btn {
width: 150px;
background-color: #5995fd;
border: none;
outline: none;
height: 49px;
border-radius: 49px;
color: #fff;
text-transform: uppercase;
font-weight: 600;
margin: 10px 0;
cursor: pointer;
transition: 0.5s;
}
.btn:hover {
background-color: #4d84e2;
}
.panels-container {
position: absolute;
height: 100%;
width: 100%;
top: 0;
left: 0;
display: grid;
grid-template-columns: repeat(2, 1fr);
}
.container:before {
content: '';
position: absolute;
height: 2000px;
width: 2000px;
top: -10%;
right: 48%;
transform: translateY(-50%);
background-image: linear-gradient(-45deg, #4481eb 0%, #04befe 100%);
transition: 1.8s ease-in-out;
border-radius: 50%;
z-index: 6;
}
.image {
width: 100%;
transition: transform 1.1s ease-in-out;
transition-delay: 0.4s;
}
.panel {
display: flex;
flex-direction: column;
align-items: flex-end;
justify-content: space-around;
text-align: center;
z-index: 6;
}
.left-panel {
pointer-events: all;
padding: 3rem 17% 2rem 12%;
}
.right-panel {
pointer-events: none;
padding: 3rem 12% 2rem 17%;
}
.panel .content {
color: #fff;
transition: transform 0.9s ease-in-out;
transition-delay: 0.6s;
}
.panel h3 {
font-weight: 600;
line-height: 1;
font-size: 1.5rem;
}
.panel p {
font-size: 0.95rem;
padding: 0.7rem 0;
}
.btn.transparent {
margin: 0;
background: none;
border: 2px solid #fff;
width: 130px;
height: 41px;
font-weight: 600;
font-size: 0.8rem;
}
.right-panel .image,
.right-panel .content {
transform: translateX(800px);
}
/* ANIMATION */
.container.sign-up-mode:before {
transform: translate(100%, -50%);
right: 52%;
}
.container.sign-up-mode .left-panel .image,
.container.sign-up-mode .left-panel .content {
transform: translateX(-800px);
}
.container.sign-up-mode .signin-signup {
left: 25%;
}
.container.sign-up-mode form.sign-up-form {
opacity: 1;
z-index: 2;
}
.container.sign-up-mode form.sign-in-form {
opacity: 0;
z-index: 1;
}
.container.sign-up-mode .right-panel .image,
.container.sign-up-mode .right-panel .content {
transform: translateX(0%);
}
.container.sign-up-mode .left-panel {
pointer-events: none;
}
.container.sign-up-mode .right-panel {
pointer-events: all;
}
@media (max-width: 870px) {
.container {
min-height: 800px;
height: 100vh;
}
.signin-signup {
width: 100%;
top: 95%;
transform: translate(-50%, -100%);
transition: 1s 0.8s ease-in-out;
}
.signin-signup,
.container.sign-up-mode .signin-signup {
left: 50%;
}
.panels-container {
grid-template-columns: 1fr;
grid-template-rows: 1fr 2fr 1fr;
}
.panel {
flex-direction: row;
justify-content: space-around;
align-items: center;
padding: 2.5rem 8%;
grid-column: 1 / 2;
}
.right-panel {
grid-row: 3 / 4;
}
.left-panel {
grid-row: 1 / 2;
}
.image {
width: 200px;
transition: transform 0.9s ease-in-out;
transition-delay: 0.6s;
}
.panel .content {
padding-right: 15%;
transition: transform 0.9s ease-in-out;
transition-delay: 0.8s;
}
.panel h3 {
font-size: 1.2rem;
}
.panel p {
font-size: 0.7rem;
padding: 0.5rem 0;
}
.btn.transparent {
width: 110px;
height: 35px;
font-size: 0.7rem;
}
.container:before {
width: 1500px;
height: 1500px;
transform: translateX(-50%);
left: 30%;
bottom: 68%;
right: initial;
top: initial;
transition: 2s ease-in-out;
}
.container.sign-up-mode:before {
transform: translate(-50%, 100%);
bottom: 32%;
right: initial;
}
.container.sign-up-mode .left-panel .image,
.container.sign-up-mode .left-panel .content {
transform: translateY(-300px);
}
.container.sign-up-mode .right-panel .image,
.container.sign-up-mode .right-panel .content {
transform: translateY(0px);
}
.right-panel .image,
.right-panel .content {
transform: translateY(300px);
}
.container.sign-up-mode .signin-signup {
top: 5%;
transform: translate(-50%, 0);
}
}
@media (max-width: 570px) {
form {
padding: 0 1.5rem;
}
.image {
display: none;
}
.panel .content {
padding: 0.5rem 1rem;
}
.container {
padding: 1.5rem;
}
.container:before {
bottom: 72%;
left: 50%;
}
.container.sign-up-mode:before {
bottom: 28%;
left: 50%;
}
}
/* 控制login & register显示 */
form {
padding: 0rem 5rem;
transition: all 0.2s 0.7s;
overflow: hidden;
}
form.sign-in-form {
z-index: 2;
}
form.sign-up-form {
opacity: 0;
z-index: 1;
}
/* register */
.loginForm,
.registerForm {
margin-top: 20px;
background-color: #fff;
padding: 20px 40px 20px 20px;
border-radius: 5px;
box-shadow: 0px 5px 10px #cccc;
}
.submit-btn {
width: 100%;
}
.tiparea {
text-align: right;
font-size: 12px;
color: #333;
width: 100%;
}
.tiparea a {
color: #409eff;
}
</style>
5.创建接口login.ts
自定义方法和接口方法 对应注释的部分
import axios from '@/utils/http'
// 注册接口
//接口方法
export function login(params: any) {
return axios({
url: '/api/v1/auth/register',
method: 'post',
headers: {
'Content-Type': 'application/json;charset=UTF-8'
},
data: params
})
}
//自定义方法
// export function login(params: any) {
// console.log(params)
// if(params.email=="123456" && params.password=="123456"){
// return true
// }else{
// return false
// }
// }
6.提交方法(引用ts)
对应注释的部分