二、Vue3+Ts+Vite+AntdUI构建后台基础模板——登录页开发

2,167 阅读1分钟

1. 在src/views目录下新建Login目录

2. 在Login目录新建index.vue

// @/views/Login/index.vue
<template>
	<h1>login</h1>
</template>

<script lang="ts">
	import {defineComponent} from 'vue'	
	export default defineComponent({
		name: 'login',
	})
</script>

<style lang="less" scoped>

</style>

3. 修改路由

// @/router/index.ts
import { createRouter,createWebHashHistory} from "vue-router";

const routes = [
  {
    path: "/",
    name: "home",
    component:  () => import('../views/Home/index.vue'),
	meta:{
		title:'首页',
	}
  },
  {
    path: "/login",
    name: "Login",
    component:  () => import('../views/Login/index.vue'),
	meta:{
		title:'登录',
	}
  },
]

const router = createRouter({
  history: createWebHashHistory(),
  routes: routes
})

export default router;

4. 修改App.vue

//@/App.vue
<template>
	<router-view />
</template>

<script lang="ts">
	import {defineComponent} from 'vue'	
	export default defineComponent({
		name: 'App',
		components: {},
	})
</script>

<style>
</style>

5. 修改home页

// @/Home/index.vue
<template>
	<h1>home</h1>
</template>

<script lang="ts">
	import {defineComponent} from 'vue'	
	export default defineComponent({
		name: 'home',
	})
</script>

<style lang="less" scoped>
</style>

6. 切换浏览器地址

7. 页面布局

// @/views/Login/index.vue
<template>
	<a-row class="layout" type="flex" justify="center" align="middle">
		<a-card class="login_card" bodyStyle="height:100%;padding:unset;" hoverable>
			<div class="card_body">
				<div class="login_img">
					<img src="https://via.placeholder.com/320x180/fff.png?text=Tian-Admin">
					<p>Tian-Admin</p>
				</div>
				<div class="login_form">
					<a-form class="form" layout="vertical">
						<a-form-item label="账号:">
							<a-input size="large"/>
						</a-form-item>
						<a-form-item label="密码:">
							<a-input size="large"/>
						</a-form-item>
						<a-form-item>
							<a-button type="primary" block>提交</a-button>
						</a-form-item>
					</a-form>
				</div>
			</div>
		</a-card>
	</a-row>
</template>

<script lang="ts">
	import {
		defineComponent
	} from 'vue'
	export default defineComponent({
		name: 'login',
	})
</script>

<style lang="less" scoped>
	.layout {
		width: 100%;
		height: 100%;
		background: #f5f5fa;

		.login_card {
			width: 100%;
			height: 100%;
			max-width: 1000px;
			max-height: 550px;
			border-radius: 10px;
			background: #fff;
		}
		
		.card_body{
			width: 100%;
			height: 100%;
			display: flex;
			justify-content: space-between;
		}

		.login_img {
			background: #1890ff;
			width: 40%;
			display: flex;
			flex-direction: column;
			justify-content: center;
			align-items: center;

			img {
				padding: 10px;
				background: #fff;
				max-width: 160px;
			}

			p {
				margin: 20px 0;
				font-size: 22px;
				color: #fff;
			}
		}

		.login_form {
			width: 60%;
			display: flex;
			justify-content: center;
			align-items: center;

			.form {
				width: 100%;
				max-width: 380px;
			}
		}
	}
</style>

8. 加入表单验证

// @/views/Login/index.vue
<template>
	<a-row class="layout" type="flex" justify="center" align="middle">
		<a-card class="login_card" bodyStyle="height:100%;padding:unset;" hoverable>
			<div class="card_body">
				<div class="login_img">
					<img src="https://via.placeholder.com/320x180/fff.png?text=Tian-Admin">
					<p>Tian-Admin</p>
				</div>
				<div class="login_form">
					<a-form class="form" ref="loginFormRef" layout="vertical" :rules="loginRules" :model="loginForm">
						<a-form-item label="账号:" name="username">
							<a-input v-model:value="loginForm.username" size="large"/>
						</a-form-item>
						<a-form-item label="密码:" name="password">
							<a-input v-model:value="loginForm.password" size="large"/>
						</a-form-item>
						<a-form-item>
							<a-button type="primary" size="large" block @click="onSubmit">提交</a-button>
						</a-form-item>
					</a-form>
				</div>
			</div>
		</a-card>
	</a-row>
</template>

<script lang="ts">
	import {defineComponent,reactive,ref,toRaw} from 'vue'
	//表单的类型
	interface formState {
		username:string,
		password:string,
	}
	export default defineComponent({
		name: 'login',
		setup(){
			//表单的ref属性
			const loginFormRef = ref();

			//登录表单
			const loginForm: formState = reactive({
				username: '',
				password: '',
			});

			//登录验证规则
			const loginRules = {
				username: [
					{ required: true, message: '请输入用户名', trigger: 'blur' },
				],
				password: [
					{ required: true, message: '请输入密码', trigger: 'blur' },
				],
			};

			//提交表单
			const onSubmit = ()=>{
				loginFormRef.value.validate().then(()=>{
					console.log(toRaw(loginForm));
				})
			};

			return{
				loginFormRef,
				loginForm,
				loginRules,
				onSubmit
			}
		}
	})
</script>

<style lang="less" scoped>
	.layout {
		width: 100%;
		height: 100%;
		background: #f5f5fa;

		.login_card {
			width: 100%;
			height: 100%;
			max-width: 1000px;
			max-height: 550px;
			border-radius: 10px;
			background: #fff;
		}

		.card_body{
			width: 100%;
			height: 100%;
			display: flex;
			justify-content: space-between;
		}

		.login_img {
			background: #1890ff;
			width: 40%;
			display: flex;
			flex-direction: column;
			justify-content: center;
			align-items: center;

			img {
				padding: 10px;
				background: #fff;
				max-width: 160px;
			}

			p {
				margin: 20px 0;
				font-size: 22px;
				color: #fff;
			}
		}

		.login_form {
			width: 60%;
			display: flex;
			justify-content: center;
			align-items: center;
			.form {
				width: 100%;
				max-width: 380px;
			}
		}
	}
</style>

9. 项目中引入mock用于接口模拟

10. mock安装执行命令

npm install mockjs -d
npm install vite-plugin-mock -d
npm install cross-env -d

11. 修改package.json

// @/package.json
{
   "scripts": {
        // 修改dev构建脚本的命令
        "dev": "cross-env NODE_ENV=development vite",
        "build": "vue-tsc --noEmit && vite build",
        "serve": "vite preview"
    },
}

12. 修改vite.config.ts,同时设置一下src目录别名,方便文件的引入。

// @/vite.config.ts
import vue from "@vitejs/plugin-vue";
import path from "path";
import {defineConfig} from "vite";
import {viteMockServe} from "vite-plugin-mock";

export default defineConfig({
    plugins: [
        vue(),
        viteMockServe({
            supportTs: true
        })
    ],
	resolve: {
	    alias: {
	      "@": path.resolve(__dirname, "src"),
	    },
	},
});

13. 在项目根目录新建mock目录(与src同级)

14. 在mock下新建login.ts文件

// /mock/login.ts
import Mock from 'mockjs'
export default [
    {
		//http://mockjs.com/examples.html
        url: "/mock/api/login",
        method: "post",
		// timeout: 500,
		// statusCode: 500,
        response: ({}) => {
            return {
                code: 200,
                message: "ok",
                data: {
			'token': Mock.Random.string('lower',200),
		},
            }
        },
    },
];

15. 请求登录接口,执行成功后跳转

 // @/views/Login/index.vue
 
import {defineComponent,ref,reactive,toRaw} from 'vue'
import {useRouter} from 'vue-router'
import axiso from "axios"
......
const router = useRouter();
const loginFormRef = ref();
......
const onSubmit = () => {
	loginFormRef.value.validate().then(() => {
		axios({
			url: '/mock/api/login',
			method: 'POST',
			data: toRaw(loginForm),
		}).then(res => {
			console.log(res.data);
            router.push({
                path:'/'
            })
		})
	})
};

......

16.完整代码

<template>
    <a-row class="layout" type="flex" justify="center" align="middle">
        <a-card class="login_card" bodyStyle="height:100%;padding:unset;" hoverable>
            <div class="card_body">
                <div class="login_img">
                    <img src="https://via.placeholder.com/320x180/fff.png?text=Tian-Admin" />
                    <p>Tian-Admin</p>
                </div>
                <div class="login_form">
                    <a-form class="form" ref="loginFormRef" layout="vertical" :rules="loginRules" :model="loginForm">
                        <a-form-item label="账号:" name="username">
                            <a-input v-model:value="loginForm.username" size="large" />
                        </a-form-item>
                        <a-form-item label="密码:" name="password">
                            <a-input-password v-model:value="loginForm.password" size="large" />
                        </a-form-item>
                        <a-form-item>
                            <a-button type="primary" size="large" block @click="onSubmit">提交</a-button>
                        </a-form-item>
                    </a-form>
                </div>
            </div>
        </a-card>
    </a-row>
</template>

<script lang="ts">
import { defineComponent, reactive, ref, toRaw } from 'vue';
import { useRouter } from 'vue-router';
import axios from 'axios';

interface formState {
    username: string;
    password: string;
}
export default defineComponent({
    name: 'login',
    setup() {
        const router = useRouter();
        const loginFormRef = ref();
        const loginForm: formState = reactive({
            username: '',
            password: '',
        });
        const loginRules = {
            username: [
                {
                    required: true,
                    message: '请输入用户名',
                    trigger: 'blur',
                },
            ],
            password: [
                {
                    required: true,
                    message: '请输入密码',
                    trigger: 'blur',
                },
            ],
        };

        const onSubmit = () => {
            loginFormRef.value.validate().then(() => {
                axios({
                    url: '/mock/api/login',
                    method: 'POST',
                    data: toRaw(loginForm),
                }).then((res) => {
                    console.log(res.data);
                    router.push({ path: '/' });
                });
            });
        };
        return {
            loginFormRef,
            loginForm,
            loginRules,
            onSubmit,
        };
    },
});
</script>

<style lang="less" scoped>
.layout {
    width: 100%;
    height: 100%;
    background: #f5f5fa;

    .login_card {
        width: 100%;
        height: 100%;
        max-width: 1000px;
        max-height: 550px;
        border-radius: 10px;
        background: #fff;
    }

    .card_body {
        width: 100%;
        height: 100%;
        display: flex;
        justify-content: space-between;
    }

    .login_img {
        background: #1890ff;
        width: 40%;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;

        img {
            padding: 10px;
            background: #fff;
            max-width: 160px;
        }

        p {
            margin: 20px 0;
            font-size: 22px;
            color: #fff;
        }
    }

    .login_form {
        width: 60%;
        display: flex;
        justify-content: center;
        align-items: center;

        .form {
            width: 100%;
            max-width: 380px;
        }
    }
}
</style>

17.视频演示及源码

本文演示视频:点击浏览

更多前端内容欢迎关注公众号:天小天个人网