从0到1构建vite+vue3项目脚手架

4,741 阅读3分钟

构建完成之后的目录展示

image.png

1、创建项目

npm init vite@latest
  • 输入项目名称,选择vue,需要支持TypeScript就选择vue-ts,不选ts也没关系

image.png

  • 下载依赖包,使用npm run dev命令启动项目

image.png

  • 项目启动完毕

image.png

image.png

2、修改Vite配置文件

  • 主要是配置路径别名和配置跨域代理
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// 如果这里飘红则安装下依赖。
// pnpm add @types/node -D
// npm install @types/node -D
// yarn add @types/node -D
import { resolve } from "path"

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  resolve: {
    // 配置别名
    alias: {
      "@": resolve(__dirname, "src")
    },
    extensions: [".js", ".json", ".ts", ".vue"] // 使用路径别名时想要省略的后缀名
  },
  server: {
    proxy: {
      '/devApi': {
        target: 'https://10.194.98.123', // 所要代理的目标地址
        secure: false,
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/devApi/, '') // 重写传过来的path路径
      }
    }
  }
})
  • 修改tsconfig.json文件,使路径别名配置生效
 "compilerOptions": {
    ...
    "baseUrl": ".",
    "paths": {
      "@/*": [
        "src/*"
      ]
    }
  }

3、创建路由

  • 下载依赖
npm install vue-router@4
  • 在src目录下新建router.ts文件;新建pages文件夹,在文件夹下新建home.vue文件
// createWebHistory:history路由
//  createWebHashHistory:hash路由
import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'

const routes = [
  {
    path: '/',
    redirect: '/home',
  },
  {
    path: '/home',
    name: 'Home',
    component: () => import('@/pages/Home.vue'),  // 配置路径别名后,可以使用@
  },
]

const router = createRouter({
  history: createWebHashHistory(),
  routes,
})

export default router
  • 在main.ts中注册路由
import { createApp } from 'vue'
import App from './App.vue'
// 引入路由
import router from './router'

// 创建vue实例
const app = createApp(App)
app.use(router)
app.mount('#app')
  • app.ts中添加 router-view,至此路由大功告成
<template>
  <router-view />
</template>

4、集成Stylus/Sass/Less

  • 直接安装相关依赖包就可以使用了,这里安装sass
npm install sass -D
<style lang="scss" scoped>
</style>

5、集成element-plus

  • vue3中,element-plus替代了element-ui,安装依赖
npm install element-plus --Save
  • main.ts中引入
// 引入element-plus
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

app.use(ElementPlus)
  • 代码里直接使用
<el-button type="primary">Primary</el-button>

6、axios封装

npm install axios --Save
  • 在src文件夹下新建api文件夹,创建httpInstance.js文件
import axios from 'axios'
import { ElMessage } from 'element-plus'
const REFRESH_BY_HEADER = 'pleaseRefreshByHeader'
const REQUEST_SUCCESS = '0'

const http = axios.create({
  timeout: 20000,
  withCredentials: true,
  headers: { 'X-Requested-With': 'XMLHttpRequest' },
})

// 相应拦截器
http.interceptors.response.use(
  function (response) {
    // 请求多语言的json文件
    if (/.*\.json$/.test(response.config.url)) {
      return response
    }

    // 根据响应数据判断是否登录过期
    if (response.data.errorCode === REFRESH_BY_HEADER) {
      let refreshUrl = response.headers['refresh-url'].split('?')[0]
      refreshUrl =
        refreshUrl +
        '?service=' +
        location.protocol +
        '//' +
        location.host +
        location.pathname +
        encodeURIComponent(location.search)
      location.href = refreshUrl
      return
    }

    // 对错误进行统一处理
    if (response.data.code !== REQUEST_SUCCESS) {
      if (!response.config.noMsg && response.data.msg) {
        ElMessage.error(response.data.msg)
      }
      return Promise.reject(response)
    } else if (
      response.data.code === REQUEST_SUCCESS &&
      response.config.successNotify &&
      response.data.msg
    ) {
      // 弹出成功提示
      ElMessage.success(response.data.msg)
    }
    return Promise.resolve({
      code: response.data.code,
      msg: response.data.msg,
      data: response.data.data,
    })
  },
  function (error) {
    if (error.ElMessage.indexOf('timeout') > -1) {
      // 多语言需要自己在项目中配置
      ElMessage.error('请求超时,请重试!')
    }
    return Promise.reject(error)
  }
)

export default http
  • 新建index.js文件
import http from './httpInstance.js'
// /devApip配合跨域代理使用
const baseUrl = process.env.NODE_ENV === 'development' ? '/devApi' : ''

export function getPlacePage(data) {
  return http({
    method: 'post',
    url: baseUrl + '/pointatps/place/page',
    data,
  })
}
  • 代码中使用
<script setup lang="ts">
import { onMounted } from "vue"
import { getArea } from '@/api'

onMounted(() => {
  getData()
})

const getData = async () => {
  const { data } = await getArea()
  console.log(data)
}
</script>
  • 配合跨域代理,成功获取到数据

image.png

7、安装pinia

  • 使用大菠萝pinia替代vuex,尤大大也更加推荐使用pinia~~
npm install pinia --Save
  • main中注册
// 引入pinia
import { createPinia } from 'pinia'
// 创建 Pinia 实例
const pinia = createPinia()
// 挂载
app.use(pinia)
  • 新建store文件夹,在store文件夹下新建index.js
import { defineStore } from "pinia";

export const useMainStore = defineStore("main", {
  // 类似于Vue2组件中的data,用于存储全局状态数据,但有两个要求
  // 1. 必须是函数,目的是为了在服务端渲染的时候避免交叉请求导致的数据状态污染
  // 2. 必须是箭头函数,这样是为了更好的 TS 类型推导
  state: () => {
    return {
      msg: "安徽黄山期待您的到来",
      count: 0
    };
  },
  getters: {
    getCount(state) {
      return state.count + 100;
    }
  },
  actions: {
    changeState() {
      this.msg = "安徽黄山祝您工作愉快";
      this.count += 10;
    }
  }
});
  • 基本使用
<template>
  <div class="home">
    <div>{{msg}}</div>
    <el-button type="primary"
               @click="addCount">count+1</el-button>
    <div>{{count}}</div>
     <!-- getter 和 Vuex中的getter一样,在获取 State值之前做一些逻辑处理,具有缓存作用 -->
    <div>{{store.getCount}}</div>
  </div>
</template>
<script setup lang="ts">

import { useMainStore } from '@/store/index'
// 当store中的多个参数需要被使用到的时候,为了更简洁的使用这些变量,采用结构的方式一次性获取所有的变量名
// ES传统方式解构(能获取到值,但是不具有响应性)
// Pinia解构方法:storeToRefs
import { storeToRefs } from 'pinia'
const store = useMainStore()
// 解构store中的值
const { msg, count } = storeToRefs(store)

const addCount = () => {
  // 通过`store.属性名`来直接修改值
  store.count++
  // 通过store.方法名来调用action中的方法
  store.changeState()
}
</script>

至此脚手架构建基本结束~