Vue3开发案例


大事件

需求


需求

学习路径

  1. 环境准备

    • 创建Vue工程:npm init vue@latest

    • 安装依赖

      • Element-Plus:npm install element-plus --save

      • Axios:npm install axios

      • Sass:npm install sass -D

    • 目录调整

      • 删除components下面自动生成的内容
      • 新建目录api、utils、views
      • 将资料中的静态资源拷贝到assets目录下
      • 删除App.vue中自动生成的内容
  2. 功能开发

开发步骤


开发步骤

数据绑定时,参考接口文档给属性起名。

表单校验时,

el-form标签上通过rules属性,绑定校验规则;

el-form-item标签上通过prop属性,指定校验项。

跨域问题

由于浏览器同源策略限制,向不同源(不同协议、不同域名、不同端口)发送ajax请求会失败。


跨域

解决:配置代理

  1. request.jsconst baseURL = 'http://localhost:8080';修改为const baseURL = '/api';,相当于:http://localhost:5173/api
  2. vite.config.js修改

配置代理

跨域:配置代理

优化axios响应拦截器


优化axios响应拦截器

消息提示

import { ElMessage } from 'element-plus'
ElMessage.error(result.data.msg ? result.data.msg : '服务异常');

 ElMessage.success(result.msg ? result.msg : '登录成功')

路由

  • 路由,决定从起点到终点的路径的进程
  • 在前端工程中,路由指的是根据不同的访问路径,展示不同组件的内容。
  • Vue Router是Vue.js的官方路由,它与Vue.js深度集成,让Vue.js构建单页面应用变得更加轻而易举。

Vue Router

  • 安装Vue Router:npm install vue-router@4

  • 在src/router/index.js中创建路由器,并导出

    //index.js
    //导入vue-router
    import { createRouter, createWebHistory } from 'vue-router'
    //导入组件
    import LoginVue from '@/views/Login.vue'
    import LayoutVue from '@/views/Layout.vue'
    
    //定义路由关系
    const routes = [
        { path: '/login', component: LoginVue },
        { path: '/', component: LayoutVue }
    ]
    
    //创建路由器
    const router = createRouter({
        history: createWebHistory(), //vue中有history和哈希两种路由模式
        routes: routes
    });
    
    export default router
  • 在vue应用实例中使用vue-router

    //main.js
    import router from '@/router' //index.js。这样名字的js文件在导入时,可以不写文件名,只要定位到文件所在的文件夹即可,使用起来很方便
    app.use(router)
  • 声明router-view标签,展示组件内容

    //App.vue
    <template>
       <router-view></router-view>
    </template>

子路由

当用户点击左侧的菜单时,右侧主区域的内容需要发生变化,将来每切换一个菜单,右侧需要加载对应组件的内容进行展示,像这样的场景也需要使用路由来完成

由于这些组件都需要在Layout.vue中展示, 而Layout.vue本身已经参与了路由,因此需要在Layout.vue中通过子路由的方式来完成组件的切换

  • 提供菜单对应的组件

  • 配置子路由

    //定义路由关系
    const routes = [
        { path: '/login', component: LoginVue },
        {
            path: '/', component: LayoutVue, redirect: '/article/manage', children: [
                { path: '/article/category', component: ArticleCategoryVue },
                { path: '/article/manage', component: ArticleManageVue },
                { path: '/user/info', component: UserInfoVue },
                { path: '/user/avatar', component: UserAvatarVue },
                { path: '/user/resetPassword', component: UserResetPasswordVue }
            ]
        }
    ]
  • 在Layout.vue组件的右侧中间区域,添加router-view标签

  • 菜单项el-menu-item设置index属性,设置点击后跳转的路由路径

Pinia状态管理库

Pinia是Vue的专属状态管理库,它允许跨组件或页面共享状态。


Pinia状态管理库
  • 安装pinia:npm install pinia

  • 在vue应用实例中使用pinia

    import { createPinia } from 'pinia'
    
    const pinia = createPinia()
    app.use(pinia)
  • 在src/stores/token.js中定义store

    import { defineStore } from "pinia";
    import {ref} from 'vue';
    
    /*
        defineStore参数描述:
            第一个参数:给状态起名,具有唯一性
            第二个参数:函数,可以把定义该状态中拥有的内容
    
        defineStore返回值描述:
            返回的是一个函数,将来可以调用该函数,得到第二个参数中返回的内容
    */
    export const useTokenStore = defineStore('token',()=>{
        //1.定义描述token
        const token = ref('')
    
        //2.定义修改token的方法
        const setToken = (newToken)=>{
            token.value = newToken
        }
    
        //3.定义移除token的方法
        const removeToken = ()=>{
            token.value=''
        }
        return {
            token,setToken,removeToken
        }
    })
  • 在组件中使用store

    在需要使用状态的地方,导入@/stores/*.js , 使用即可

    在Login.vue中导入@/stores/token.js, 并且当用户登录成功后,将token保存pinia中

    //导入token状态
    import { useTokenStore } from '@/stores/token.js'
    
    //调用useTokenStore得到状态
    const tokenStore = useTokenStore();
    
    //用于登录的事件函数
    const login = async () => {
        let result = await loginService(registerData.value)
        //保存token
        tokenStore.setToken(result.data)
        
        ElMessage.success('登录成功!')
        router.push('/')
    }

    在article.js中导入@/stores/token.js, 从pinia中获取到存储的token,在发起查询文章分类列表的时候把token通过请求头的形式携带给服务器

    //导入@/stores/token.js
    import { useTokenStore } from '../stores/token'
    
    
    //文章分类列表查询
    export const articleCategoryListService = () => {
        //获取token状态
        const tokenStore = useTokenStore()
        //通过请求头Authorization携带token
        return request.get('/category', { headers: { 'Authorization': tokenStore.token } })
    }

Axios请求拦截器

当进入主页后,将来要与后台交互,都需要携带token,如果每次请求都写这样的代码,将会比较繁琐,此时可以将携带token的代码通过请求拦截器统一处理

在 src/util/request.js中

//导入token状态
import { useTokenStore } from '@/stores/token.js';
//添加请求拦截器
instance.interceptors.request.use(
    (config)=>{
        //在发送请求之前做什么
        let tokenStore = useTokenStore()
        //如果token中有值,在携带
        if(tokenStore.token){
            config.headers.Authorization=tokenStore.token
        }
        return config
    },
    (err)=>{
        //如果请求错误做什么
        Promise.reject(err)
    }
)

Pinia持久化插件-persist

  • 由于pinia是内存存储,当刷新页面的时候pinia中的数据会丢失
  • Persist插件支持将pinia中的数据持久化到sessionStorage和localStorage中

使用

  • 安装persist:npm install pinia-persistedstate-plugin

  • 在pinia中使用persist

    import { createPersistedState } from 'pinia-persistedstate-plugin'
    const persist = createPersistedState();
    pinia.use(persist);
  • 定义状态Store时指定持久化配置参数

    //token.js
    {
        persist: true //持久化存储
    }

未登录统一处理

在后续访问接口时,如果没有登录,则前端不携带token,后台服务器会返回响应状态码401,代表未登录,此时可以在axios的响应拦截器中,统一对未登录的情况做处理

//request.js
import router from '@/router'
//添加响应拦截器
instance.interceptors.response.use(
    result => {
        //如果业务状态码为0,代表本次操作成功
        if (result.data.code == 0) {
            return result.data;
        }
        //代码走到这里,代表业务状态码不是0,本次操作失败
        ElMessage.error(result.data.message || '服务异常');
        return Promise.reject(result.data);//异步的状态转化成失败的状态
    },
    err => {
        //如果响应状态码时401,代表未登录,给出对应的提示,并跳转到登录页
        if(err.response.status===401){
            ElMessage.error('请先登录!')
            router.push('/login')
        }else{
            ElMessage.error('服务异常');
        }
        return Promise.reject(err);//异步的状态转化成失败的状态
    }
)

文章作者: nusqx
文章链接: https://nusqx.top
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 nusqx !
评论
  目录