Vue博客搭建(7)注册的前端实现

952 阅读1分钟

在上一篇文章中我们已经做好了Vue的路由跳转,接下来就可以进行注册页面的实现了。

基本设计

简易的注册页面很简单,只需要两个输入框分别输入用户名和密码,一个确定按钮就可以了。现在就可以搭建出来。

<template>
    注册
    <div>
        用户名
        <input/>
        密码
        <input/>
        <button>注册</button>
    </div>
</template>

但是目前它们并没有任何的功能。

v-model

首先我们需要解决一个问题:如何获取到输入框中的数据?使用HTML原生的获取元素还是比较麻烦的,因此我们这里介绍Vue响应式的另一个重要指令:v-modelv-modelv-bind最大的区别就是前者是双向的,可以通过template影响到script,而后者是单向的,只能通过script影响到template而不能反过来。

这里再稍微讲一下v-model的内部实现。其实v-modelv-bindv-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,包含statusdata等数据。我们扩展一下上面的代码,让其包含结果判断与提示(注册成功后返回主页)。

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}`);
        }
        
    })
}