🙈作者简介:练习时长两年半的Java up主
🙉个人主页:程序员老茶
🙊 ps:点赞👍是免费的,却可以让写博客的作者开心好久好久😎
📚系列专栏:Java全栈,计算机系列(火速更新中)
💭 格言:种一棵树最好的时间是十年前,其次是现在
🏡动动小手,点个关注不迷路,感谢宝子们一键三连
目录
- [课程名:Vue 3](#课程名:Vue 3)
课程名:Vue 3
内容/作用:知识点/设计/实验/作业/练习
学习:Vue3+Vant开发:登录功能
1、创建登录路由
npm install vue-router@4
以上安装了最新版本的vue-router
.
下面在src
目录下面创建router
目录,在该目录下面创建index.js
文件,在该文件中完成路由的配置。
index.js
文件中代码如下所示:()
在下面的代码中,首先从vue-router
中导入createRouter
以及createWebHashHistory
.
createRouter
用来创建路由实例
createWebHashHistory
创建hash
路由
Layout
组件用来完成整个后台管理页面的布局。
在routes
数组中,定义了相应的路由规则
js
import { createRouter, createWebHashHistory } from "vue-router";
const routes = [
{
path: "/login",
name: "login",
component: () => import("../views/login/index.vue"),
},
];
//创建路由实例
const router = createRouter({
//history模式:createWebHistory
history: createWebHashHistory(), //使用hash模式
routes,
});
export default router;
下面在src
目录下面创建views
目录,在该目录下面创建login
目录,然后在创建index.vue
.
该组件中的内容如下所示:
vue
<template>
<div>登录</div>
</template>
<script>
export default {};
</script>
<style></style>
下面,返回到main.js
文件中使用创建好的路由对象
js
import { createApp } from "vue";
import App from "./App.vue";
import Vant from "vant";
import "vant/lib/index.css";
import "amfe-flexible";
import router from "./router"; //导入路由对象
createApp(App).use(Vant).use(router).mount("#app"); //使用路由
同时在App.vue
文件中,添加router-view
,指定路由的出口。
vue
<template>
<router-view></router-view>
</template>
<script setup></script>
<style></style>
在浏览器中输入http://localhost:3000/#/login
查看效果。
2、实现登录布局结构
vue
<template>
<div class="login-container">
<!-- 导航栏 -->
<van-nav-bar title="登录" />
<!-- 导航栏结束 -->
<!-- 登录表单 -->
<van-form>
<van-field name="userName" placeholder="请输入用户名" />
<van-field name="userPwd" placeholder="请输入密码" />
<div style="margin: 16px">
<van-button block type="primary" native-type="submit">
提交
</van-button>
</div>
</van-form>
<!-- 登录表单结束 -->
</div>
</template>
<script>
export default {};
</script>
<style></style>
3、登录布局实现
这里我们首先设置一下,导航栏的样式。由于很多页面都会用到导航栏,所以可以将样式定义在全局的文件中,而不是单独的定义在登录组件中。
在src
目录下面创建styles
目录,在该目录下面创建index.css
文件,该文件中的代码如下所示:
css
.page-nav-bar {
background-color: #3296fa;
}
.page-nav-bar .van-nav-bar__title {/* 这里的van-nav-bar__title,可以查看原有的导航栏的样式*/
color: #fff;
}
在登录组件的导航栏中使用该样式。(在main.js
文件中导入import "./styles/index.css";
)
vue
<van-nav-bar title="登录" class="page-nav-bar" />
下面给登录表单的文本框与密码框添加对应的图标。
对应的官网:
https://vant-contrib.gitee.io/vant/v3/#/zh-CN/field
vue
<van-form>
<van-field name="userName" placeholder="请输入用户名" left-icon="manager" />
<van-field name="userPwd" placeholder="请输入密码" left-icon="lock"/>
</van-field>
<div style="margin: 16px">
<van-button block type="primary" native-type="submit">
提交
</van-button>
</div>
</van-form>
这里给手机号与验证码添加了left-icon
设置了图标。同时设置了"发送验证码"的按钮
4、实现基本登录功能
注意:这里只是实现基本登录效果,把服务端返回的内容打印出来,不涉及到登录状态的提示与登录状态的存储操作。
首先在src
目录下面创建api
目录,在该目录下面创建user.js
文件,该文件中封装了用户请求的相关处理模块。
js
// 封装用户相关的请求模块
import request from "../utils/request";
export const login = (data) => {
return request({
method: "POST",
url: "/user/login",
data,
});
};
下面修改login.vue
组件中的内容
vue
<div class="login-container">
<!-- 导航栏 -->
<van-nav-bar title="登录" class="page-nav-bar" />
<!-- 导航栏结束 -->
<!-- 登录表单 -->
<van-form @submit="onSubmit">
<van-field
name="userName"
placeholder="请输入用户名"
v-model="userName"
left-icon="manager"
:rules="userFormRules.userName"
/>
<van-field
name="userPwd"
placeholder="请输入密码"
v-model="userPwd"
left-icon="lock"
:rules="userFormRules.userPwd"
>
</van-field>
<div style="margin: 16px">
<van-button block type="primary" native-type="submit">
登录
</van-button>
</div>
</van-form>
<!-- 登录表单结束 -->
</div>
给每个van-field
绑定了v-model
,同时给van-form
添加了@submit
事件。
js
<script>
import { reactive, toRefs } from "vue";
import { login } from "../../api/user"; //导入login方法,进行请求的发送
function useSubmit(user) {
const onSubmit = async () => {
//1、获取表单数据
//2、表单验证
//3、提交表单请求
Toast.loading({
message: "登录中...",
forbidClick: true, //禁用背景点击
duration: 0, //持续时间,默认是2000毫秒,如果为0则持续展示
});
const res = await login(user);
if (res.data.code === 0) {
store.commit("setUser", res.data);
Toast.success("用户登录成功");
} else {
Toast.fail("用户名或密码错误");
}
//4、根据请求响应结果处理后续操作。
};
return {
onSubmit,
};
}
export default {
setup() {
const user = reactive({
userName: "", //用户名
userPwd: "", //用户密码
});
return {
...toRefs(user),
...useSubmit(user),
};
},
};
</script>
在setup
方法中,定义user
响应式对象,最后返回。同时将外部定义的useSubmit
方法进行调用。
5、登录状态提示
js
const onSubmit = async () => {
//1、获取表单数据
//2、表单验证
//3、提交表单请求
Toast.loading({
message: "登录中...",
forbidClick: true, //禁用背景点击
duration: 0, //持续时间,默认是2000毫秒,如果为0则持续展示
});
const res = await login(user);
if (res.data.code === 0) {
store.commit("setUser", res.data);
Toast.success("用户登录成功");
} else {
Toast.fail("用户名或密码错误");
}
//4、根据请求响应结果处理后续操作。
};
return {
onSubmit,
};
}
这里使用了Toast
组件,同时需要进行导入:
js
import { Toast } from "vant";
由于网络比较快,可能看不到登录中...
这个提示,所以可以把网络设置慢一些。
可以修改NetWork
中的No throttling
中的Slow 3G
6、表单验证功能
在setup
函数中定义校验规则,并且将其返回。
js
setup() {
const user = reactive({
userName: "", //用户名
userPwd: "", //用户密码
});
//定义校验规则
const userFormRules = {
userName: [{ required: true, message: "请填写用户名" }],
userPwd: [
{
required: true,
message: "请填写密码",
},
{
pattern: /^\d{6}$/,
message: "密码格式错误",
},
],
};
return {
...toRefs(user),
...useSubmit(user),
userFormRules, //返回校验规则
};
},
在表单中使用校验规则:
vue
<van-field
name="userName"
placeholder="请输入用户名"
v-model="userName"
left-icon="manager"
:rules="userFormRules.userName"
/>
<van-field
name="userPwd"
placeholder="请输入密码"
v-model="userPwd"
left-icon="lock"
:rules="userFormRules.userPwd"
>
</van-field>
7、处理用户Token
用户登录成功以后,会返回token
数据。
Token
是用户登录成功之后服务端返回的一个身份令牌,在项目中经常要使用。
例如:访问需要授权的API
接口。
校验页面的访问权限等。
同时,这里我们还需要将token
数据进行存储,这样在访问其它的页面组件的时候,就可以获取token
数据来进行校验。
关于token
数据存储在哪儿呢?
可以存储到本地:
存储到本地的问题是,数据不是响应式的。
存储到Vuex
中,获取方便,并且是响应式的。但是存储到Vuex
中也是有一定的问题的,就是当我们刷新浏览器的时候,数据就会丢失,所以还是需要把token
数据存放到本地,存储到本地的目的就是为了进行持久化。
所以这里我们需要在登录成功以后,把token
数据存储到vuex
中,这样可以实现响应式,在本地存储就是为了解决持久化的问题。
安装最新版本的Vuex
npm install vuex@next --save
下面在src
目录下面创建store
目录,在store
目录中index.js
文件,该文件中的代码如下所示:
js
import { createStore } from "vuex";
const store = createStore({
state: {
//存储当前登录用户信息,包含token等数据
user: null,
},
mutations: {
setUser(state, data) {
state.user = data;
},
},
});
export default store;
在上面的代码中,创建了store
容器,同时指定了state
对象,在该对象中定义user
属性存储登录用户信息。
在mutations
中定义setUser
方法,完成用户信息的更新。
下面,要实现的就是,当登录成功以后,更新user
这个状态属性。
当然,这里首先要做的就是把store
注入到Vue
的实例中。
js
import { createApp } from "vue";
import App from "./App.vue";
import Vant from "vant";
import "vant/lib/index.css";
import "amfe-flexible";
import "./styles/index.css";
import router from "./router";
import store from "./store"; //导入store
createApp(App).use(Vant).use(router).use(store).mount("#app"); //完成store的注册操作
在main.js
文件中,我们导入了store
,并且注册到了Vue
实例中。
下面返回到views/login/index.vue
页面中,把登录的信息存储到store
容器中。
js
import { reactive, toRefs, ref } from "vue";
import { login, sendSms } from "../../api/user";
import { Toast } from "vant";
import { useStore } from "vuex"; //导入useStore
在上面的代码中导入useStore
.
js
export default {
setup() {
const loginForm = ref();
//获取store
const store = useStore();
在setup
函数中,调用useStore
方法,获取store
容器。
js
return {
...toRefs(user),
...useSubmit(user, store),//在调用useSubmit方法的时候传递store容器
userFormRules,
loginForm,
};
js
//用户登录
function useSubmit(user, store) {
const onSubmit = async () => {
//1、获取表单数据
//2、表单验证
//3、提交表单请求
Toast.loading({
message: "登录中...",
forbidClick: true, //禁用背景点击
duration: 0, //持续时间,默认是2000毫秒,如果为0则持续展示
});
const res = await login(user);
if (res.data.code === 0) {
store.commit("setUser", res.data);
Toast.success("用户登录成功");
} else {
Toast.fail("用户名或密码错误");
}
//4、根据请求响应结果处理后续操作。
};
return {
onSubmit,
};
}
登录成功以后,获取到返回的数据,同时调用store
中的commit
方法完成数据
的保存
现在,我们虽然把登录成功的数据,存储到Vuex
中,但是当我们刷新浏览器的时候,Vuex
中的数据还是会丢失的。所以这里,我们还需要将其存储到本地中。
下面修改一下store/index.js
文件中的代码:
js
import { createStore } from "vuex";
const TOKEN_KEY = "TOUTIAO_USER";
const store = createStore({
state: {
//存储当前登录用户信息,包含token等数据
// user: null,
user: JSON.parse(window.localStorage.getItem(TOKEN_KEY)),
},
mutations: {
setUser(state, data) {
state.user = data;
window.localStorage.setItem(TOKEN_KEY, JSON.stringify(state.user));
},
},
});
export default store;
在mutations
中的setUser
方法中,将登录成功的用户数据存储到了localStorage
中,在存储的时候,将数据转成了字符串。
同时在state
中获取数据的时候,就从localStorage
中获取,当然获取的时候,再将其转换成对象的形式。
下面,我们可以在App.vue
中做一下测试:
vue
<template>
<div>
<router-view></router-view>
</div>
</template>
<script>
import { useStore } from "vuex";
export default {
setup() {
const store = useStore();
console.log(store.state.user);
},
};
</script>
<style></style>
通过查看浏览器的控制台,可以查看到对应的登录用户的token
数据
8、封装本地存储操作
在我们的项目中,有很多的地方都需要获取本地存储的数据,如果每次都写:
JSON.parse(window.localStorage.getItem(TOKEN_KEY)),
window.localStorage.setItem(TOKEN_KEY, JSON.stringify(state.user));
就比较麻烦了。所以这里我们建议把操作本地数据单独的封装到一个模块中。
在utils
目录下面创建storage.js
文件,该文件中的代码如下所示:
js
// 存储数据
export const setItem = (key, value) => {
//将数组,对象类型的数据转换为JSON格式的字符串进行存储
if (typeof value === "object") {
value = JSON.stringify(value);
}
window.localStorage.setItem(key, value);
};
//获取数据
export const getItem = (key) => {
const data = window.localStorage.getItem(key);
//这里使用try..catch的,而不是通过if判断一下是否为json格式的字符串,然后在通过parse进行转换呢,目的就是是为了方便处理,因为对字符串进行判断看一下是否为json格式的字符串,比较麻烦一些。还需要通过正则表达式来完成。而通过try..catch比较方便
// 如果data不是一个有效的json格式字符串,JSON.parse就会出错。
try {
return JSON.parse(data);
} catch (e) {
return data;
}
};
//删除数据
export const removeItem = (key) => {
window.localStorage.removeItem(key);
下面返回到store/index.js
文件中,修改对应的代码,这里使用我们上面封装好的代码。
js
import { createStore } from "vuex";
import { getItem, setItem } from "../utils/storage";
const TOKEN_KEY = "TOUTIAO_USER";
const store = createStore({
state: {
//存储当前登录用户信息,包含token等数据
// user: null,
// user: JSON.parse(window.localStorage.getItem(TOKEN_KEY)),
user: getItem(TOKEN_KEY),
},
mutations: {
setUser(state, data) {
state.user = data;
setItem(TOKEN_KEY, state.user);
// window.localStorage.setItem(TOKEN_KEY, JSON.stringify(state.user));
},
},
});
export default store;
在上面的代码中,我们导入getItem
和setItem
两个方法,然后在存储登录用户信息,和获取登录用户信息的时候,直接使用这两个方法,这样就非常简单了。
下面返回浏览器进行测试。
把以前localStorage
中存储的内容删除掉。
然后重新输入用户名和密码,发现对应的localStorage
中存储了对应的数据。
总结
感谢小伙伴们一键三连,咱们下期文章再见~
往期专栏 |
---|
Java全栈开发 |
数据结构与算法 |
计算机组成原理 |
操作系统 |
数据库系统 |
物联网控制原理与技术 |