Vue3项目实战硅谷甄选,从0实现项目搭建

这是b站上尚硅谷分享的基于Vue3+Ts的前端项目《硅谷甄选》,使用的脚手架为Vite,从零开始,进行环境配置,再到项目的实现。

 由于视频是2023年发布的,至今技术也进行了各种更新,所以有些地方我也会用新知识去替代视频中的内容。

项目较大,本期先总结环境配置的部分。

一、创建Vue应用

我使用的包管理器是npm:

npm create vue@latest

初始化配置如下:

接着根据提示完成创建(现在的Vite比较先进,能够自动配置ESLint和Prettier,无需手动配置)。创建完成后手动删除多余的、无用的文件和代码。

二、项目集成

1.集成Element Plus

安装:

npm install element-plus --save

引入:

main.js:

import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

app.use(ElementPlus, {
  locale: zhCn, // 中文
})

2.环境变量配置

在根目录下添加开发、生产和测试环境的文件

.env.development:

NODE_ENV = 'development'
VITE_APP_TITLE = '硅谷甄选运营平台'
VITE_APP_BASE_API = '/api'
VITE_SERVE = 'http://xxx.com'
.env.production:

NODE_ENV = 'production'
VITE_APP_TITLE = '硅谷甄选运营平台'
VITE_APP_BASE_API = '/prod-api'
VITE_SERVE = 'http://yyy.com'
.env.test

NODE_ENV = 'test'
VITE_APP_TITLE = '硅谷甄选运营平台'
VITE_APP_BASE_API = '/test-api'
VITE_SERVE = 'http://zzz.com'

运行配置:

package.json:

"scripts": {
   "build:test": "vue-tsc && vite build --mode test",
   "build:pro": "vue-tsc && vite build --mode production",
},

3.svg图标配置

安装依赖:

npm install vite-plugin-svg-icons -D

创建存放图标的文件夹:

配置:

vite.config.ts:

import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'

  plugins: [
    createSvgIconsPlugin({
      iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')], // svg图标地址
      symbolId: 'icon-[dir]-[name]',
    }),
  ],
main.ts:

// svg 插件需要配置代码
import 'virtual:svg-icons-register'
import SvgIcon from '@/components/SvgIcon/index.vue'

4.svg封装为全局组件

新建SvgIcon组件

封装:

index.vue:

<!-- 封装 svg 图标组件 -->
<template>
  <div>
    <svg :style={width,height}>
      <use :xlink:href="prefix + name" :fill="color"></use>
    </svg>
  </div>
</template>

<script setup lang="ts">
  defineProps({
    prefix:{
      type:String,
      default:'#icon-'
    },
    name:String,
    color:{
      type:String,
      default:''
    },
    width:{
      type:String,
      default:'16px'
    },
    height:{
      type:String,
      default:'16px'
    }
  })
</script>

<style scoped></style>

因为用的地方比较多,注册为全局组件更方便:

main.ts:

import SvgIcon from '@/components/SvgIcon/index.vue'

app.component('SvgIcon', SvgIcon)

测试代码:

<svg-icon name="duck" color="" width="60px" height="60px"></svg-icon>

5.集成sass

安装依赖:

npm install -D sass

在src下创建样式文件:

在npm官网上复制reset.scss文件;

引入:

index.scss:

// 引入清除默认样式
@use './reset.scss'
main.ts:

// 引入 scss 样式
import '@/styles/index.scss'

引入全局变量:

variable.scss

$pri-color: hotpink;

配置全局变量:

vite.config.ts:

export default defineConfig({
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: '@use "@/styles/variable.scss" as *;',
      },
    },
  }
})

6.配置mock数据

安装依赖:

npm i vite-plugin-mock

配置mock:

vite.config.js:

import { viteMockServe } from 'vite-plugin-mock'

plugins: [
  viteMockServe({
    enable: true, // 启用本地mock
  })
],

根目录创建mock文件夹:

创建接口文件:

user.ts:

// 用户信息数据
// createUserList: 此函数执行会返回一个数组,数组里面包含两个用户信息
function createUserList() {
  return [
    {
      userId: 1,
      avatar:
        'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
      username: 'admin',
      password: '111111',
      desc: '平台管理员',
      roles: ['平台管理员'],
      buttons: ['cuser.detail'],
      routes: ['home'],
      token: 'Admin Token',
    },
    {
      userId: 2,
      avatar:
        'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
      username: 'system',
      password: '111111',
      desc: '系统管理员',
      roles: ['系统管理员'],
      buttons: ['cuser.detail', 'cuser.user'],
      routes: ['home'],
      token: 'System Token',
    },
  ]
}

// 对外暴露一个数组:数组里面包含两个接口
// 登录假的接口
// 获取用户信息的假的接口
export default [
  // 用户登录接口
  {
    url: '/api/user/login',//请求地址
    method: 'post',//请求方式
    response: ({ body }) => {
      //获取请求体携带过来的用户名与密码
      const { username, password } = body;
      //调用获取用户信息函数,用于判断是否有此用户
      const checkUser = createUserList().find(
        (item) => item.username === username && item.password === password,
      )
      //没有用户返回失败信息
      if (!checkUser) {
        return { code: 201, data: { message: '账号或者密码不正确' } }
      }
      //如果有返回成功信息
      const { token } = checkUser
      return { code: 200, data: { token } }
    },
  },
  // 获取用户信息
  {
    url: '/api/user/info',
    method: 'get',
    response: (request) => {
      //获取请求头携带token
      const token = request.headers.token;
      //查看用户信息是否包含有次token用户
      const checkUser = createUserList().find((item) => item.token === token)
      //没有返回失败的信息
      if (!checkUser) {
        return { code: 201, data: { message: '获取用户信息失败' } }
      }
      //如果有返回成功信息
      return { code: 200, data: { checkUser } }
    },
  },
]

测试接口:

main.ts:

// 测试接口
import axios from 'axios'
axios({
  url: '/api/user/login',
  method: 'post',
  data: {
    username: 'admin',
    password: '111111'
  }
})

7.axios二次封装

src下创建utils/request.ts :

结合axios和element-plus封装request:

request.ts:

// 进行 axios 的二次封装:使用请求和响应拦截器
import axios from "axios";
import { ElMessage } from "element-plus";

// 一、利用 axios 的 create 方法,去创建 axios 实例(其他配置:基础路径、超时时间)
const request = axios.create({
  // 基础路径
  baseURL: import.meta.env.VITE_APP_BASE_API,
  timeout: 5000
})
// 二、request 实例添加请求与响应拦截器
request.interceptors.request.use((config) => {
  // config 配置对象,header 属性请求头,经常给服务器端携带参数
  // config.headers.token = "111"
  // 返回配置对象
  return config;
})

// 三、响应拦截器
request.interceptors.response.use((response) => {
  // 成功回调
  // 简化数据
  return response.data;
}, (error) => {
  // 失败回调,处理http网络错误
  // 定义一个变量-存储网络错误信息
  let message = ''
  // http状态码
  let status = error.response.status;
  switch (status) {
    case 401:
      message = "TOKEN过期"
      break;
    case 403:
      message = "无权访问"
      break;
    case 404:
      message = "请求地址错误"
      break;
    case 500:
      message = "服务器出现问题"
      break;
    default:
      message = "网络出现问题"
      break;
  }
  // 提示错误信息
  ElMessage({
    type: 'error',
    message
  })
  return Promise.reject(error)
})

// 暴露
export default request

测试:

App.vue:

  // request 测试
  import request from './utils/request'
  import { onMounted } from 'vue'
  onMounted(() => {
    request({
      url: '/user/login11',
      method: 'post',
      data: {
        username: 'admin',
        password: '111111'
      }
    }).then(res => {
      console.log(res);
    }).catch(error=>{
      console.log(error);
    })
  })

8.api接口统一管理

创建api接口管理文件:

用户接口管理:

user/index.ts:

// 统一管理项目用户相关接口
import request from "@/utils/request";
import type { loginForm, loginResponseData, userResponseData } from "./type";
// 统一管理接口
enum API {
  LOGIN_URL = "/user/login",
  USERINFO_URL = "user/info"
}
// 暴露请求函数
// 登录接口方法
export const reqLogin = (data: loginForm) => request.post<any, loginResponseData>(API.LOGIN_URL, data)
// 获取用户信息接口方法
export const reqUserInfo = () => request.get<any, userResponseData>(API.USERINFO_URL)

类型约束:

user/type.ts:

// 登录接口需要携带的ts类型
export interface loginForm {
  username: string,
  password: string
}

interface dataType {
  token: string
}

// 登录接口返回的数据类型
export interface loginResponseData {
  code: number,
  data: dataType
}

interface userInfo {
  userId: number,
  avatar: string
  username: string,
  password: string,
  desc: string,
  roles: string[],
  buttons: string[],
  routes: string[],
  token: string,
}
// 定义服务器返回用户信息相关的数据类型
interface user {
  checkUser: userInfo
}

export interface userResponseData {
  code: number
  data: user
}

测试:

App.vue:

  // 接口测试
  import { reqLogin } from './api/user';
  onMounted(()=>{
    reqLogin({username:'admin',password:'1111111'})
  })

9.路由配置

创建路由文件:

配置路由(我用的是 HTML5 模式):

router/index.ts:

import { createRouter, createWebHistory } from 'vue-router'
import Login from '@/views/login/Login.vue'
import Home from '@/views/home/Home.vue'
import Not from '@/views/404/Not.vue'

// 创建路由器
const router = createRouter({
  // 路由模式
  history: createWebHistory(),
  routes: [
    {
      path: '/login',
      component: Login
    },
    {
      path: '/home',
      component: Home
    },
    {
      path: '/404',
      component: Not
    },
    // 重定向
    {
      path: '/',
      redirect: 'home'
    },
    // 任意路由
    {
      path: '/:pathMatch(.*)*',
      redirect: '404'
    }
  ],
  //滚动行为
  scrollBehavior() {
    return {
      left: 0,
      top: 0
    }
  }
})

// 暴露
export default router

10.pinia配置

创建store文件夹:

index.ts:

import { createPinia } from 'pinia'

const pinia = createPinia()

export default pinia

应用:

main.ts:

import pinia from './store'

app.use(pinia)

三、小结

总之,项目初期,环境配置是一个大量且繁琐的工程,但有至关重要,需要耐心对待。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值