在上一篇文章中我们已经做好了Vue的路由跳转,接下来就可以进行注册页面的实现了。
基本设计
简易的注册页面很简单,只需要两个输入框分别输入用户名和密码,一个确定按钮就可以了。现在就可以搭建出来。
<template>
注册
<div>
用户名
<input/>
密码
<input/>
<button>注册</button>
</div>
</template>
但是目前它们并没有任何的功能。
v-model
首先我们需要解决一个问题:如何获取到输入框中的数据?使用HTML原生的获取元素还是比较麻烦的,因此我们这里介绍Vue响应式的另一个重要指令:v-model。v-model和v-bind最大的区别就是前者是双向的,可以通过template影响到script,而后者是单向的,只能通过script影响到template而不能反过来。
这里再稍微讲一下v-model的内部实现。其实v-model是v-bind和v-on的结合,当template端数据更新时,v-on会调用一个JavaScript语句,把更新后的值再传回v-on中,就像这样:
<input :value="searchText" @input="searchText = $event.target.value" />
使用v-model绑定后的代码如下,并且附带了一个小的检验函数。
<script setup>
import {ref} from 'vue'
let usernameInput = ref('');
let passwordInput = ref('');
function print(){
console.log(usernameInput.value);
}
</script>
<template>
注册
<div>
用户名
<!-- change事件会在输入框发生变化且失去焦点(按回车也可以)时触发 -->
<input v-model="usernameInput" @change="print"/>
密码
<input v-model="passwordInput"/>
<button @click="register">注册</button>
</div>
</template>
不过还有一个问题,为什么我们的v-model并没有说明我们要绑定的是输入框元素的哪个属性,但是依旧会奏效呢?这是因为Vue会对原生的输入对象进行一些设定好的内部绑定,因此不再需要我们手动去绑定对应的属性。不过对于其他的自定义元素就不能这样了,在以后的教程中我们会讲如何自定义绑定。
发送HTTP请求
接下来要进行按钮功能的实现。也就是向服务器发送我们输入的用户名和密码。可以使用HTML5原生的fetch操作进行,但是这里我们使用Axios包来进行异步操作。
import axios from 'axios'
function register(){
axios.post('/register',{
username: usernameInput,
password: passwordInput
})
.then((response)=>{
console.log(response);
})
.catch((err)=>{
console.log(err);
})
}
一个简单的异步函数就写好了,不用注释应该就可以看懂。但是链接url应该是什么?我们直接用后端接口访问试试,会报错:
Access to XMLHttpRequest at 'server/register' from origin 'http://127.0.0.1:5173' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
我们看到了一个词叫做CORS。CORS的全称是“跨域资源共享”,我们的前后端属于两台服务器,因此分别属于不同的域,浏览器为了我们的数据安全,当你的请求比较复杂的时候(参见跨源资源共享(CORS) - HTTP | MDN (mozilla.org))是默认不会把跨域的请求放进来的。
解决跨域问题有以下两种办法:第一种就是通过代理的方式让前端支持跨域;第二种就是通过修改后端的设置让后端支持跨域。这里我们先学习第一种方法,以后有机会会进行后者的讲解。
前端的代理设置
代理设置是在vite.config.js中进行定义的。我们在配置中添加对服务器的代理。
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
server:{
proxy:{
// 代理的简写链接
'/server':{
// 实际的链接
target: 'http://**.***.**.***:3000/',
// 是否把请求头修改为实际链接,这个是一定要修改的,否则无法实现跨域
changeOrigin: true,
// 链接重写,通过正则表达式把/server去掉,因为后端服务器不存在/server这个位置
rewrite: (path)=> {
return path.replace(/^\/server/,'')
}
}
}
}
})
发送http请求的对应代码是这样:
function register(){
axios.post('/server/register',{
username: usernameInput.value,
password: passwordInput.value
})
.then((response)=>{
console.log(response);
})
.catch((err)=>{
console.log(err);
})
}
仔细观察返回的response,它是一个object,包含status、data等数据。我们扩展一下上面的代码,让其包含结果判断与提示(注册成功后返回主页)。
function register(){
axios.post('/server/register',{
username: usernameInput.value,
password: passwordInput.value
})
.then((response)=>{
alert(response.data);
router.push('/');
})
.catch((err)=>{
// 如果状态码不是2开头便会抛出错误,但是如果有响应头的话该属性不为空
if(err.response){
alert(`注册失败,${err.response.data}`);
}else{
alert(`注册失败,本地错误${err}`);
}
})
}
前端输入判断
我们在创建数据表的时候规定了用户名的长度,但是我们在前端并没有进行判断,因此可能导致后端崩溃。为了防止这种情况的出现我们需要给前端加入对应的逻辑判断。
function register(){
const username = usernameInput.value;
const password = passwordInput.value;
if(username>=20){
alert('用户名太长啦');
return;
}
axios.post('/server/register',{
username: username,
password: password
})
.then((response)=>{
alert(response.data);
router.push('/');
})
.catch((err)=>{
if(err.response){
alert(`注册失败,${err.response.data}`);
}else{
alert(`注册失败,本地错误${err}`);
}
})
}