安裝Vite
npm init vite@latest
安裝eslint
npm install eslint --save-dev
npx eslint --init (初始化eslint配置)
添加 npm script 驗證腳本
"scripts": {
...
"lint": "eslint src/**/*.{js,jsx,vue,ts,tsx} --fix",
}
編輯器集成eslint
- 禁用Vetur
- 安裝eslint插件
- 安裝Volar插件
配置 git commit hook
npx mrm@2 lint-staged
-
https://github.com/okonet/lint-staged
在commit之前 對代碼進行校驗
安裝后.png
"lint-staged": {
"*.{js,jsx,vue,ts,tsx}": [
"npm run lint",
// "git add" 之前的版本需要手動把 lint 過程中修改的代碼手動 add,新版本不需要了
]
}
vite-plugin-eslint
npm install vite-plugin-eslint --save-dev
- vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import eslintplugin from 'vite-plugin-eslint'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue(),eslintplugin({'配置參數'})]
})
commit 提交規范
Commit message 和 Change log 編寫指南
Install commitlint
Vue3 ts支持
- vue文件添加ts聲明
<script lang="ts">
- 要讓 TypeScript 正確推斷 Vue 組件選項中的類型,需要使用 defineComponent 全局方法定義組件:
import { defineComponent } from 'vue'
const Component = defineComponent({
// 已啟用類型推斷
})
//如果你使用的是[單文件組件](https://v3.cn.vuejs.org/guide/single-file-component.html),則通常會被寫成:
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
// 已啟用類型推斷
})
</script>
Vue3 中的<script setup>語法
vue3支持三種寫法
- Option Api
- Composition API
- <script setup> (Composition API 的語法糖)
defineProps,defineEmits,defineExpose,withDefaults 為全局的 可以不import 直接使用
eslint配置 .eslintrc.js 中配置則不會對此進行引入校驗
module.exports = {
globals: {
defineProps: 'readonly',
defineEmits: 'readonly',
defineExpose: 'readonly',
withDefaults: 'readonly'
}
}
script-setup用法
該連接為github倉庫連接 可能網絡問題打不開
配置轉換JSX和TSX
- npm i @vitejs/plugin-vue-jsx --save-dev
vite.config.ts配置
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
vueJsx({
//配置選項
})
]
})
使用
<template>
<abc/>
</template>
<script setup lang="tsx">
const abc = <h1>abc</h1>
</script>
單獨一個組件文件 text.tsx
//函數式組件
export default () => {
return (
<div>
<h1>text函數式組件</h1>
</div>
)
}
//需要有狀態的組件 options API
import { defineComponent } from '@vue/runtime-core'
export default defineComponent({
props:{
msg:{
type:String
}
},
render(){
return (
<div>{ this.msg }</div>
)
}
})
//需要有狀態的組件 組合式 API
import { defineComponent,ref } from '@vue/runtime-core'
interface PropsType {
msg:string
}
export default defineComponent({
props:{
msg:{
type:String
}
},
setup(){
const count = ref (0)
return (props:PropsType ) => (
<div>
<p>{props.msg}</p>
<p>{count}</p>
</div>
)
}
})
初始化VueRouter
- 安裝vue-router
npm install vue-router@4
// src\router\index.ts
import { createRouter, RouteRecordRaw, createWebHashHistory } from 'vue-router'
const routes: RouteRecordRaw[] = [
{
path: '/',
component: () => import('../views/home/index.vue')
},
{
path: '/login',
component: () => import('../views/login/index.vue')
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router
// src\main.ts
import { createApp } from 'vue'
import router from './router'
import App from './App.vue'
createApp(App).use(router).mount('#app')
初始化 Vuex
- 安裝Vuex
npm install vuex@next --save
// src\store\index.ts
import { createStore } from 'vuex'
const store = createStore({
state: {},
getters: {},
mutations: {},
actions: {},
modules: {}
})
export default store
// src\main.ts
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
createApp(App)
.use(router)
.use(store)
.mount('#app')
結合ts優化后
//store/index.ts
import { createStore, useStore as baseUseStore, Store } from 'vuex'
import { InjectionKey } from 'vue'
export interface State {
count: number
}
// 定義 injection key
export const key: InjectionKey<Store<State>> = Symbol('store')
export const store = createStore<State>({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++
}
}
})
// 定義自己的 `useStore` 組合式函數 //調用該 useStore 可以推斷出state屬性及類型
export function useStore() {
return baseUseStore(key)
}
export default store
// vuex.d.ts
import { ComponentCustomProperties } from 'vue'
import { Store } from 'vuex'
import { State } from './store/index'
declare module '@vue/runtime-core' {
// 聲明自己的 store state
// interface State {
// count: number
// }
// 為 `this.$store` 提供類型聲明
interface ComponentCustomProperties {
$store: Store<State>
}
}
配置模塊路徑別名
vite不自帶@等路徑別名
import xxx from '@/views/xxx.vue' //不支持src別名@符 所以要手動配置
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 注意:在 ts 模塊中加載 node 核心模塊需要安裝 node 的類型補充模塊:npm i -D @types/node
import path from 'path'
// https://vitejs.dev/config/
export default defineConfig({
...
resolve: {
alias: {
'@': path.resolve(__dirname, './src')
}
}
})
// tsconfig.json
//所有以@開頭的都指向src
{
"compilerOptions": {
...
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
...
}
使用
// js
import xxx from '@/api/xxx.ts'
// html
<img src="@/assets/logo.png">
// css
@import url("@/styles/index.scss");
background: url("@/assets/logo.png");
CSS樣式管理
vite css配置 文檔
Vite 也同時提供了對 .scss, .sass, .less, .styl 和 .stylus 文件的內置支持。沒有必要為它們安裝特定的 Vite 插件,但必須安裝相應的預處理器依賴:
# .scss and .sass
npm install -D sass
# .less
npm install -D less
# .styl and .stylus
npm install -D stylus
如果是用的是單文件組件,可以通過 <style lang="sass">(或其他預處理器)自動開啟。
- 注意事項:
● Vite 為 Sass 和 Less 改進了 @import 解析,以保證 Vite 別名也能被使用。
● 另外,url() 中的相對路徑引用的,與根文件不同目錄中的 Sass/Less 文件會自動變基以保證正確性。
● 由于 Stylus API 限制,@import 別名和 URL 變基不支持 Stylus。
● 你還可以通過在文件擴展名前加上 .module 來結合使用 CSS modules 和預處理器,例如 style.module.scss。
深度作用操作符新語法::deep(<inner-selector>)
樣式目錄結構
variables.scss # 全局 Sass 變量
mixin.scss # 全局 mixin
common.scss # 全局公共樣式
transition.scss # 全局過渡動畫樣式
index.scss # 組織統一導出
全局樣式都寫在 src/styles 目錄下,每個頁面自己對應的樣式都寫在自己的 .vue 文件之中。
// index.scss
@import './variables.scss';
@import './mixin.scss';
@import './transition.scss';
@import './common.scss';
然后在 main.ts 中導入 index.scss:
//main.ts 這里僅僅是加載了全局樣式,并不能實現在組件內直接使用全局變量樣式
import "./styles/index.scss"
在單獨組件里使用全局變量 需要單獨加載
//xxx.vue
<style lang="scss" scoped>
@import '@/styles/variables.scss';
.font{
color:$color;
}
</style>
要想在全局單文件中不用單獨引入就可以使用scss全局變量 需要配置使用全局樣式
配置使用全局樣式變量
css-preprocessoroptions
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import path from 'path'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
vueJsx({
// 配置選項
})
],
resolve: {
alias: {
'@': path.join(__dirname, 'src')//絕對路徑
}
},
css: {
preprocessorOptions: {
// 給 sass-loader 傳遞選項
sass: {
// @/ 是 src/ 的別名
// 所以這里假設你有 `src/variables.sass` 這個文件
// 注意:在 sass-loader v8 中,這個選項名是 "prependData"
additionalData: `@import "@/styles/variables.scss"`
},
// 默認情況下 `sass` 選項會同時對 `sass` 和 `scss` 語法同時生效
// 因為 `scss` 語法在內部也是由 sass-loader 處理的
// 但是在配置 `prependData` 選項的時候
// `scss` 語法會要求語句結尾必須有分號,`sass` 則要求必須沒有分號
// 在這種情況下,我們可以使用 `scss` 選項,對 `scss` 語法進行單獨配置
scss: {
additionalData: `@import "~@/variables.scss";`
},
// 給 less-loader 傳遞 Less.js 相關選項
less: {
// http://lesscss.org/usage/#less-options-strict-units `Global Variables`
// `primary` is global variables fields name
globalVars: {
primary: '#fff'
}
}
}
}
})
自動注冊全局組件
glob-impor
全局組件放在 components 目錄下
- components
+ foo
+ index.vue
+ index.ts
+ bar
+ index.vue
+ index.ts
- main.ts
// main.ts
const app = createApp(App)
const modules = import.meta.globEager('./components/**/index.ts')
for (const path in modules) {
app.use(modules[path].default)
}
// components/foo/index.ts
import { App } from '@vue/runtime-dom'
import Component from './index.vue'
export default {
install (app: App) {
app.component('Foo', Component)
}
}
// components/bar/index.ts
import { App } from '@vue/runtime-dom'
import Component from './index.vue'
export default {
install (app: App) {
app.component('Bar', Component)
}
}
服務端交互
**基于axios封裝請求模塊
- 安裝axios
npm i axios
基礎配置
//src/utils/request.ts
import axios from 'axios'
const request = axios.create({
baseURL: '' //基礎請求路徑
})
// 請求攔截器
request.interceptors.request.use(
config => {
// 統一設置用戶身份 Token
return config
},
error => {
return Promise.reject(error)
}
)
// 響應攔截器
request.interceptors.response.use(
response => {
// 統一處理響應錯誤,例如 token 無效、服務端異常等
return response
},
err => {
return Promise.reject(err)
}
)
export default request
/**
* 公共基礎接口封裝
*/
import request from '@/utils/request'
export const getLoginInfo = () => {
return request({
method: 'GET',
url: '/login/info'
})
}
/**
* 組件中使用
*/
import { getLoginInfo } from '@/api/common'
import { onMounted } from '@vue/runtime-core'
onMounted(() => {
getLoginInfo().then(res => {
console.log(res)
})
})
多環境 baseURL
# .env.development
# 開發模式下加載的環境變量
VITE_API_BASEURL=http://a.com
# .env.production
# 生產模式下加載的環境變量
VITE_API_BASEURL=http://b.com
// src\utils\request.ts
const request = axios.create({
// localhost:8080/xxx
// abc.com/xxx
// test.com/xxx
baseURL: import.meta.env.VITE_API_BASEURL
})
//env.d.ts中對類型聲明
/// <reference types="vite/client" />
declare module '*.vue' {
import { DefineComponent } from 'vue'
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
const component: DefineComponent<{}, {}, any>
export default component
}
interface ImportMetaEnv {
VITE_API_BASEURL: string
// 更多環境變量...
}
跨域問題
推薦方案
- 開發環境
- 在服務端配置 CORS。
- 配置開發服務器代理,比如 vite-server.proxy。
- 生產環境
- 在服務端配置 CORS。
- 配置生產服務器代理,比如 nginx。
CORS
CORS 全稱為 Cross Origin Resource Sharing(跨域資源共享)。這種方案對于前端來說沒有什么工作量,和正常發送請求寫法上沒有任何區別,工作量基本都在后端(其實也沒啥工作量,就是配置一些 HTTP 協議)。
服務器代理
可能有些后端開發人員覺得配置 CORS 麻煩不想搞,那純前端也是有解決方案的。
在開發模式下可以下使用開發服務器的 proxy 功能,比如 vite - server.proxy。
但這種方法在生產環境是不能使用的。在生產環境中需要配置生產服務器(比如 nginx、Apache 等)進行反向代理。在本地服務和生產服務配置代理的原理都是一樣的,通過搭建一個中轉服務器來轉發請求規避跨域的問題。
//vite.config.ts
export default defineConfig({
server: {
proxy: {
// 字符串簡寫寫法
'/foo': 'http://localhost:4567',
// 選項寫法
'/api': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
},
// 正則表達式寫法
'^/fallback/.*': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/fallback/, '')
},
// 使用 proxy 實例
'/api': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
configure: (proxy, options) => {
// proxy 是 'http-proxy' 的實例
}
}
}
}
})
初始化 Element Plus
npm install element-plus --save
Element Plus快速開始