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>
相关推荐
程序员清洒9 小时前
Flutter for OpenHarmony:GridView — 网格布局实现
android·前端·学习·flutter·华为
VX:Fegn08959 小时前
计算机毕业设计|基于ssm + vue超市管理系统(源码+数据库+文档)
前端·数据库·vue.js·spring boot·后端·课程设计
0思必得09 小时前
[Web自动化] 反爬虫
前端·爬虫·python·selenium·自动化
LawrenceLan10 小时前
Flutter 零基础入门(二十六):StatefulWidget 与状态更新 setState
开发语言·前端·flutter·dart
秋秋小事10 小时前
TypeScript 模版字面量与类型操作
前端·typescript
2401_8920005210 小时前
Flutter for OpenHarmony 猫咪管家App实战 - 添加提醒实现
前端·javascript·flutter
Yolanda9410 小时前
【项目经验】vue h5移动端禁止缩放
前端·javascript·vue.js
VX:Fegn089512 小时前
计算机毕业设计|基于springboot + vue酒店管理系统(源码+数据库+文档)
vue.js·spring boot·课程设计
广州华水科技12 小时前
单北斗GNSS形变监测一体机在基础设施安全中的应用与技术优势
前端
EndingCoder12 小时前
案例研究:从 JavaScript 迁移到 TypeScript
开发语言·前端·javascript·性能优化·typescript