3.11 实现登录功能
用所学知识来做一个简单的登录功能吧。首先创建一个Login.vue组件,然后再router.js中添加一个路由路径:
<!-- Login.vue -->
<template>
<h1>登录页</h1>
<form>
<div>
<label for="username">用户名:</label>
<input id="username" type="text" />
</div>
<div>
<label for="password">密码:</label>
<input id="password" type="password" />
</div>
<button>登录</button>
</form>
</template>
const router = createRouter({
history:createWebHashHistory(),
routes:[
{path:"/",component:Home},
{path:'/blog/:id',component:Blog},
{path:'/login',component:Login}
]
})
好了,现在我们能够在我们的网址后面手动加上login就可以跳转到登录页了。
接下来实现在登录页,点击登录后 跳转到首页的方法:
<!-- Login.vue -->
<template>
<h1>登录页</h1>
<!-- 记得我们的form有默认事件嘛,需要用prevent取消默认事件 -->
<form @submit.prevent="login">
<div>
<label for="username">用户名:</label>
<input id="username" type="text" v-model="username" />
</div>
<div>
<label for="password">密码:</label>
<input id="password" type="password" v-model="password" />
</div>
<button>登录</button>
</form>
</template>
<script>
export default {
data(){
return{
username:'',
password:''
}
},
methods:{
login(){ //本应该是由后端进行判定,这里就先在前端写一个函数来判定
if(this.username==='admin'&&this.password==='123456'){
//如果满足以上条件,登陆成功,会跳转到首页
this.$router.push("/")
}else{
//否则就会提示
alert("用户名或密码错误")
}
}
}
}
</script>
3.11.1 token验证登录状态
这里要知道一个概念是localStorage本地存储。我们可以通过localStorage.setItem('token','111')在本地设置一个token,并在每个页面都能用localStorage.getItem("token")可以拿到‘111’这个值。但真正在开发中,这个token一般是后端发送给前端的一个十六进制很长的一个字符串。
这里可以在前端模拟一下,我们登录完成后设置一个token:
login(){ //本应该是由后端进行判定,这里就先在前端写一个函数来判定
if(this.username==='admin'&&this.password==='123456'){
this.$router.push("/")
//设置token
localStorage.setItem("token","111")
}else{
alert("用户名或密码错误")
}
}
下面要介绍一个路由守卫(也可以叫做导航守卫,路由拦截):
//router.js
//每次路由切换都会执行一次这个函数beforeEach()
router.beforeEach((to,from,next)=>{//可以不写next
//三个参数分别代表 去哪个url 从哪个url来 如果在参数里面写了next而下方不用它 页面就不会跳转了
console.log(to)
console.log(from)
next() //若参数里写了next,这里不执行,那么页面将不跳转
})
我们知道了路由守卫,在每次路由切换时都会执行,就可以在这里面检测我们的token。如果有token说明登录成功了,就允许他到达首页,而如果没有token 就把他强制跳转到登录页。这是为了防止没有登录就直接通过修改网址跳到主页去。
//router.js
//路由守卫
router.beforeEach((to,_from,next)=>{//这里的from下面不使用它的话,这里可以在前面加_
//验证token,只有存在token的时候,才能跳转到其他页面,否则只能去登录页
let token = localStorage.getItem("token")
if(token || to.path==='/login'){
next()
}else{
next('/login')
}
})
这样就是先纯前端的一个登陆验证的功能,当然实际项目是要跟后端配合的。
3.12 组合api
3.12.1 响应式变量
首先回顾一下之前写的vue代码:
<template>
<h1>{{msg}}</h1>
</template>
<script>
export default {
data(){
return{
msg:'hello'
}
},
methods:{
changeMsg(){
this.msg = 'hello world'
}
}
}
</script>
这里我们是将一个一个的属性,传给到当前组件里,这个呢就是option api(选项api)的语法。
现在要学习的是composition api(组合api) :把所有东西写到一个setup( ){ }里面。
<template>
<h1>{{title}}</h1>
<button @click="sayHi">按钮</button>
</template>
<script>
export default {
setup(){
let title = 'hello world'
const sayHi = ()=>{
alert('hello vue')
}
return { //把数据暴露出来给上面的模板用
title,sayHi
}
}
}
</script>
以上就是基本写法,那么如果想要通过点击按钮,改变title的值呢,如果直接在sayHi里面改,会发现根本没有改变,这里就要讲到响应式了。
因为我们以上代码中的title只是一个普通变量,不是一个响应式变量,因此就算在sayHi中将其赋值为其他字符串也不会在页面显示改变:
<template>
<h1>{{title}}</h1>
<button @click="sayHi">按钮</button>
</template>
<script>
//引入vue的ref
import {ref} from 'vue'
export default {
setup(){
//title变为响应式变量,会拥有一个value属性
let title = ref('hello world')
const sayHi = ()=>{
title.value = 'hello vue'
}
return { //把数据暴露出来给上面的模板用
title,sayHi
}
}
}
</script>
那么上面代码中,是使用vue中的ref将一个字符串变成了响应式变量,vue中还有一个reactive可以将对象变成响应式对象:
<template>
<h1>{{student.name}}</h1>
<button @click="changeName">按钮</button>
</template>
<script>
//引入vue的reactive
import {reactive} from 'vue'
export default {
setup(){
//将student变成一个响应式对象
const student = reactive({name:'小明',age:2})
const changeName = ()=>{
student.name = '大明'
}
return {
student,changeName
}
}
}
</script>
这样在页面就可以实时修改页面的展示数据了。
3.12.2 组件的生命周期
这里有几个常用生命周期的对应写法:
| option api | composition api |
|---|---|
| beforeMount | onBeforeMount |
| mounted | onMounted |
| beforeUpdate | onBeforeUpdate |
| updated | onUpdated |
| beforeUnmount | onBeforeUnmount |
| unmounted | onUnmounted |
那我们会发现,beforeCreate和created咋没了捏,因为我们的setup() 运行的时间呢就是created的时间,他其实代替了created。
3.12.3 计算属性
需要从vue中引入{computed}
<template>
<h1>{{number}}</h1>
</template>
<script>
//引入vue的reactive
import {computed} from 'vue'
export default {
setup(){
const number = computed(()=>{ //computed是一个函数
return 100
})
return {
number
}
}
}
</script>
3.12.4 组合api的优势
我们先用选项api(composition api)写加减按钮的方法:
<template>
<button @click="minus">-</button>
<h1>{{num}}</h1>
<button @click="add">+</button>
</template>
<script>
export default {
data(){
return {
num:0
}
},
methods:{
add(){
this.num++
},
minus(){
this.num--
}
}
}
</script>
接着用组合api来写:
<template>
<button @click="minus">-</button>
<h1>{{num}}</h1>
<button @click="add">+</button>
</template>
<script>
import {ref} from 'vue'
export default {
setup(){
const num = ref(0) //响应式变量
const add = ()=>{
num.value++
}
const minus = ()=>{
num.value--
}
return {num,add,minus}
}
}
</script>
而且在使用组合api的时候,甚至可以把里面的东西拿到setup()外面来,到export外面来:
<template>
<button @click="minus">-</button>
<h1>{{num}}</h1>
<button @click="add">+</button>
</template>
<script>
import {ref} from 'vue'
const num = ref(0)
const add = ()=>{
num.value++
}
const minus = ()=>{
num.value--
}
export default {
setup(){
//就留 return 在里面
return {num,add,minus}
}
}
</script>
既然这样子,那我们甚至都不需要写到这里来,甚至是可以另起 js文件,从外部导入即可,比如我们在components文件夹下建立一个 count.js :
//count.js
export default function(num){ //暴露一个函数,接收一个参数num(是一个响应式变量)
const add = ()=>{
num.value++
}
const minus = ()=>{
num.value--
}
return{
add,minus //这个函数的返回值是add()和minus()
}
}
然后看看我们vue文件那边:
<template>
<button @click="minus">-</button>
<h1>{{num}}</h1>
<button @click="add">+</button>
</template>
<script>
import {ref} from 'vue'
import count from './components/count' // 引入刚写的count.js
export default {
setup(){
const num = ref(0)
//这种取值方式是 解构赋值
const {add,minus} = count(num) //这里为什么不能直接传num.value呢,因为响应式变量是num而不是num.value
return {num,add,minus}
}
}
</script>
这样子我们的代码就可以很简洁了。可以用组合api把之前写的水果列表重新实现一遍,会有所进步!