Vue 项目实战,从注册登录到首页开发:接口封装 + 导航守卫 + 拦截器全流程

Vue 项目中,注册登录是基础功能,而接口封装、请求拦截器、导航守卫是保障项目可维护性的核心。

一、注册功能:静态布局 + 接口封装 + 用户提示

注册功能是用户体系的入口,需完成静态页面、接口调用、表单校验等步骤。

1. 注册静态布局

使用 Vant UI 快速搭建注册表单(以手机号 + 密码注册为例):

vue 复制代码
<template>
  <van-form @submit="onSubmit">
    <van-field
      v-model="form.phone"
      label="手机号"
      placeholder="请输入手机号"
      type="tel"
    />
    <van-field
      v-model="form.password"
      label="密码"
      placeholder="请输入密码"
      type="password"
    />
    <van-button type="primary" block native-type="submit">注册</van-button>
  </van-form>
</template>

<script>
export default {
  data() {
    return {
      form: { phone: '', password: '' }
    };
  },
  methods: {
    onSubmit() {
      // 后续实现注册请求
    }
  }
};
</script>

2. 封装 request 模块(统一请求配置)

基于axios封装请求模块,统一处理请求地址、超时等配置:

javascript 复制代码
// src/utils/request.js
import axios from 'axios';

// 创建axios实例
const request = axios.create({
  baseURL: 'https://api.example.com', // 后端接口地址
  timeout: 5000 // 超时时间
});

export default request;

注意:要记得下载axios包(npm i axios)

3. 封装 api 模块(接口统一管理)

将注册接口封装到api目录,便于维护:

javascript 复制代码
// src/api/user.js
import request from '@/utils/request';

// 注册接口
export function register(data) {
  return request({
    url: '/auth/register',
    method: 'POST',
    data
  });
}

4. 注册请求:成功 / 失败提示用户

调用封装的接口,结合 Vant 的Toast组件提示用户:

vue 复制代码
<script>
import { register } from '@/api/user';
import { Toast } from 'vant';

export default {
  methods: {
    async onSubmit() {
      try {
        await register(this.form);
        Toast.success('注册成功!');
        this.$router.push('/login'); // 跳转到登录页
      } catch (err) {
        Toast.fail(err.response.data.msg || '注册失败');
      }
    }
  }
};
</script>

5. 正则校验 + 响应拦截器统一处理

  • 正则校验:在表单提交前验证手机号格式:
javascript 复制代码
onSubmit() {
  const phoneReg = /^1[3-9]\d{9}$/;
  if (!phoneReg.test(this.form.phone)) {
    Toast.fail('手机号格式错误');
    return;
  }
  // 后续请求逻辑
}
  • 响应拦截器:在request.js中统一处理接口错误:
javascript 复制代码
// src/utils/request.js
request.interceptors.response.use(
  response => response.data, // 直接返回响应体
  error => {
    // 统一处理错误
    Toast.fail(error.response.data.msg || '请求失败');
    return Promise.reject(error);
  }
);

二、登录功能:接口调用 + Token 存储

登录的核心是获取 Token 并持久化存储,便于后续接口鉴权。

1. 登录功能实现

类似注册流程,调用登录接口并获取 Token:

javascript 复制代码
// src/api/user.js
export function login(data) {
  return request({
    url: '/auth/login',
    method: 'POST',
    data
  });
}
vue 复制代码
// Login.vue
async onSubmit() {
  const res = await login(this.form);
  // 存储Token
  localStorage.setItem('token', res.token);
  Toast.success('登录成功');
  this.$router.push('/'); // 跳转到首页
}

2. 封装 storage 模块(统一存储操作)

将本地存储封装为工具模块,避免重复代码:

javascript 复制代码
// src/utils/storage.js
const KEY = 'study-day-1212-token'
// 存储数据
export const setToken = token => localStorage.setItem(KEY, token)

// 获取数据
export const getToken = () => localStorage.getItem(KEY)

// 删除数据
export const delToken = () => localStorage.removeItem(KEY)

注意:KEY是自己定义的一个变量,尽量不要直接使用token,容易和其他重复,建议设置一个不易重复的

使用:

javascript 复制代码
import { setItem } from '@/utils/storage';
setToken(res.data.token)

三、导航守卫:页面拦截(未登录禁止访问首页)

导航守卫用于控制路由访问权限,比如未登录用户禁止进入首页。

1. 全局前置守卫

router/index.js中配置全局前置守卫:

javascript 复制代码
import VueRouter from 'vue-router';
import { getItem } from '@/utils/storage';
import { Toast } from 'vant';

const router = new VueRouter({ routes });

// 全局前置守卫
router.beforeEach((to, from, next) => {
  // 不需要登录的页面(如登录、注册)直接放行
  const whiteList = ['/login', '/register'];
  if (whiteList.includes(to.path)) {
    return next();
  }

  // 验证Token
  const token = getItem('token');
  if (token) {
    next(); // 已登录,放行
  } else {
    Toast.fail('请先登录');
    next('/login'); // 未登录,跳转到登录页
  }
});

四、首页开发:组件封装 + 接口请求 + 拦截器优化

首页需实现文章列表展示、分页、数据筛选等功能,结合拦截器统一处理接口鉴权。

1. 首页静态布局 + 封装文章组件

先封装ArticleItem组件,用于渲染单篇文章:

vue 复制代码
<!-- src/components/ArticleItem.vue -->
<template>
  <div class="article-item">
    <h3>{{ article.title }}</h3>
    <p>{{ article.content }}</p>
    <span>{{ article.createTime }}</span>
  </div>
</template>

<script>
export default {
  props: { article: { type: Object, required: true } }
};
</script>

在首页中使用:

vue 复制代码
<!-- src/views/Home.vue -->
<template>
  <div>
    <article-item 
      v-for="item in articleList" 
      :key="item.id" 
      :article="item"
    />
  </div>
</template>

<script>
import ArticleItem from '@/components/ArticleItem.vue';
export default {
  components: { ArticleItem },
  data() {
    return { articleList: [] };
  }
};
</script>

2. 获取文章列表数据

封装文章列表接口,并在首页调用:

javascript 复制代码
// src/api/article.js
export function getArticleList(params) {
  return request({
    url: '/article/list',
    method: 'GET',
    params // 分页、筛选参数
  });
}
vue 复制代码
// Home.vue
async mounted() {
  const res = await getArticleList({ page: 1, size: 10 });
  this.articleList = res.list;
}

3. 拦截器统一携带 Token + 处理 401 错误

  • 统一携带 Token:在request.js的请求拦截器中添加 Token:
javascript 复制代码
// src/utils/request.js
import { getItem } from '@/utils/storage';

request.interceptors.request.use(config => {
  // 给请求头添加Token
  const token = getItem('token');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});
  • 统一处理 401 错误(Token 失效):
javascript 复制代码
// src/utils/request.js
request.interceptors.response.use(
  response => response.data,
  error => {
    // 401:Token失效
    if (error.response.status === 401) {
      Toast.fail('登录已过期,请重新登录');
      // 清除Token并跳转到登录页
      removeItem('token');
      router.push('/login');
    }
    return Promise.reject(error);
  }
);

4. 分页功能实现

添加分页参数,实现分页加载:

vue 复制代码
// Home.vue
data() {
  return {
    articleList: [],
    page: 1, // 当前页
    size: 10 // 每页条数
  };
},
methods: {
  async loadMore() {
    const res = await getArticleList({ page: this.page, size: this.size });
    this.articleList = [...this.articleList, ...res.list];
    this.page++;
  }
}

5. 文章列表交互:切换推荐 / 最新 + 跳转详情页

  • 切换推荐 / 最新:添加筛选参数,重新请求列表:
vue 复制代码
<van-tabs v-model="activeTab" @change="fetchArticleList">
  <van-tab title="推荐">推荐</van-tab>
  <van-tab title="最新">最新</van-tab>
</van-tabs>

<script>
methods: {
  async fetchArticleList() {
    const type = this.activeTab === 0 ? 'recommend' : 'latest';
    const res = await getArticleList({ type, page: 1 });
    this.articleList = res.list;
    this.page = 2;
  }
}
</script>
  • 跳转详情页:携带文章 ID 跳转到详情页:
vue 复制代码
<!-- ArticleItem.vue -->
<div @click="toDetail">
  <!-- 文章内容 -->
</div>

<script>
methods: {
  toDetail() {
    this.$router.push({ path: '/article/detail', query: { id: this.article.id } });
  }
}
</script>
相关推荐
毕设源码-朱学姐3 小时前
【开题答辩全过程】以 工厂能耗分析平台的设计与实现为例,包含答辩的问题和答案
java·vue.js
老前端的功夫4 小时前
Vue 3 性能深度解析:从架构革新到运行时的全面优化
javascript·vue.js·架构
天天扭码4 小时前
如何实现流式输出?一篇文章手把手教你!
前端·aigc·ai编程
前端 贾公子4 小时前
vue移动端适配方案 === postcss-px-to-viewport
前端·javascript·html
GISer_Jing5 小时前
AI营销增长:4大核心能力+前端落地指南
前端·javascript·人工智能
明远湖之鱼6 小时前
一种基于 Service Worker 的渐进式渲染方案的基本原理
前端
前端小端长7 小时前
Vue 中 keep-alive 组件的原理与实践详解
前端·vue.js·spring
FeelTouch Labs7 小时前
Nginx核心架构设计
运维·前端·nginx
雪球工程师团队7 小时前
别再“苦力”写后台,Spec Coding “跑” 起来
前端·ai编程