vite.config.js的CSS配置
postcss-pxtorem
開發響應式網頁的時候需要用到postcss-pxtorem
amfe-flexible
amfe-flexible是由阿里團隊開發的一個庫,它可以根據設備的屏幕寬度去動態調整HTML根元素()的字體大小,這意味著無論用戶使用什么尺寸的設備訪問你的網站,頁面都能根據設備的實際寬度進行縮放,從而達到響應式設計效果
工作原理:amfe-flexible會檢測設備的屏幕寬度,并基于這個寬度設置一個基準字體大小,默認情況下,如果設備寬度為750px,則根字體被設置為100px,如果是375px寬,則根字體大小為50px,以此類推。
引入方式:在main.js中引入amfe-flexible
什么是postcss-pxtorem
postcss-pxtorem是PostCSS的一個插件,它的主要作用是將CSS中的px(像素)單位自動轉換為rem(根em)單位,Rem單位基于HTML文檔的根元素的字體大小來計算尺寸,這使得它可以很好的適應不同的屏幕尺寸和分辨率,從而幫助創建響應式設計
為什么選擇Rem而不是px
靈活性:使用rem可以讓你更容易地調整整個頁面或者其他部分的縮放比列,只需要改變根元素的字體大小即可
響應式設計: rem單位非常適合用于響應式設計,因為它允許你根據用戶的設備設置基礎字體大小,并以此為基礎進行相對縮放
postcss-pxtorem的使用
上面的 postcssPxToRem只能將標簽內的css像素單位轉換成rem,但是實際的項目開發中,我們需要用到行內樣式,所以我們還需要寫一個工具函數來轉換行內樣式的單位,在項目的src目錄下創建 >utils文件夾 >創建pxToRem.js
pxToRem.js
const getBaseFontSize = () => {
// 使用 document.documentElement 獲取 HTML 文檔的根元素(即 <html> 標簽)// getComputedStyle 是一個用于獲取所有計算樣式的接口,它返回一個包含所有計算樣式的對象// .fontSize 屬性從這個對象中獲取根元素的字體大小屬性值,該值是一個字符串,如 "16px"const rootFontSize = parseFloat(getComputedStyle(document.documentElement).fontSize);// parseFloat 函數將字符串轉換為浮點數,這里是為了去掉 'px' 單位,只保留數字部分// 例如,如果 fontSize 返回的是 '16px',那么 parseFloat('16px') 將返回 16// 返回計算后的根字體大小,這是一個純數字,表示當前頁面根元素的字體大小(以像素為單位)return rootFontSize;
}const pxToRem = px => {// 如果傳入的是帶單位的字符串(比如 '100px')if (typeof px === 'string') {// 如果包含 '%',直接返回if (/%/gi.test(px)) {return px;}// 去掉 'px' 單位px = parseFloat(px.replace('px', ''));}// 如果傳入的不是數字,直接返回if (isNaN(px)) {return px;}// 使用 amfe-flexible 設置的根字體大小進行計算const baseFontSize = getBaseFontSize();const remValue = (px / baseFontSize).toFixed(6) + 'rem';return remValue;
}// 導出函數
export default pxToRem;
使用pxToRem.js
在需要使用的組件中引入文件再使用
preprocessorOptions預處理器選項,配置了預處理器是less
javascriptEnabled: true允許在less文件中使用JavaScript表達式,動態計算顏色值或根據條件生成樣式有用
additionalData: '@import “@/assets/styles/variables.less”;'在每個less文件的開頭自動導入@/assets/styles/variables.less文件這樣,就可以在任何less文件中使用variables.less中定義的變量
vite.config.js中的server配置
基礎服務配置:
host: 指定服務器監聽的IP地址。0.0.0.0表示允許所有網絡接口(包括本地和外部)訪問服務
port:指定服務器運行的端口號,項目啟動后可以通過http://localhost:8888/chatai/Chat或者外部IP訪問
代理配置 (proxy):
'/api': {target: 'https://thecatapi.com/',changeOrigin: true,ws: true,timeout: 300000
},
作用:將所有請求代理到https://thecatapi.com/
配置項:
target:代理的目標服務器URL
changeOrigin:修改請求頭中的Host為目標URL的主機名(繞過某些服務器的反爬機制)
ws: 啟用webSocket代理(用于實時通信)
timeout:設置代理請求超時時間
路徑匹配規則
所有以/api開頭的請求都會被代理到https://thecatapi.com
例如:/api/cats → https://thecatapi.com/cats(自動去除/api前綴)
允許訪問的主機 (allowedHosts):
allowedHosts: ['8eec-113-106-75-166.ngrok-free.app', // 添加你的ngrok URL// 如果需要,可以添加其他允許的主機'localhost', // 允許本地訪問'127.0.0.1' // 允許本地訪問
],
作用:定義合法的主機名列表,防止未經授權的主機訪問開發服務器
常用于ngrok暴露本地服務到公網時,需要添加生成的域名,一般開發H5移動端,想要手機調試可以使用這個方法,關于ngrok的安裝使用可以參考這篇文章
前端請求發起到代理轉發的全流程
前端axios實例配置的baseURL為/api,發送請求到vite開發服務器的8888端口,vite的server.proxy配置檢測到/api開頭的請求,轉發到目標服務器,修改請求頭,處理路徑重寫,然后返回響應
封裝的axios,其中baseURL: ‘/api’,表示每個請求都會自動加上"/api"前綴,如:request.get(‘/cats’)實際的請求地址是http://localhost:8888/api/cats
import axios from 'axios'
import { useUserStore } from '@/stores/user'// 創建 axios 實例
const request = axios.create({baseURL:'/api',timeout: 100000,withCredentials: true,headers: {'Content-Type': 'application/json;charset=utf-8',Accept: 'text/event-stream'}
})// 創建請求取消控制器Map
const pendingMap = new Map()// 生成取消請求的key
const getPendingKey = config => {const { url, method, params, data } = configreturn [url, method, JSON.stringify(params), JSON.stringify(data)].join('&')
}// 添加請求到pendingMap
const addPending = config => {const pendingKey = getPendingKey(config)if (!pendingMap.has(pendingKey)) {const controller = new AbortController()config.signal = controller.signalpendingMap.set(pendingKey, controller)}
}// 移除請求從pendingMap
const removePending = config => {const pendingKey = getPendingKey(config)if (pendingMap.has(pendingKey)) {const controller = pendingMap.get(pendingKey)controller.abort()pendingMap.delete(pendingKey)}
}// 請求攔截器
request.interceptors.request.use(config => {// removePending(config)addPending(config)// 如果是流式請求if (config.isStream) {config.responseType = 'blob'config.timeout = 0 // 禁用超時}// 判斷是否需要轉換為FormDataif (config.formData === true && config.data) {let formData = new FormData()for (let key in config.data) {if (Array.isArray(config.data[key])) {config.data[key].forEach(value => {formData.append(`${key}[]`, value)})} else {formData.append(key, config.data[key])}}config.data = formDataconfig.headers['Content-Type'] = 'multipart/form-data'}return config},error => {return Promise.reject(error)}
)// 響應攔截器
request.interceptors.response.use(response => {removePending(response.config)// 如果是流式響應,直接返回responseif (response.config.isStream) {return response}if (response.data.code == 215) {const userStore = useUserStore()userStore.clearUserState() //清除用戶狀態}return response.data},error => {if (error.name === 'AbortError') {console.log('請求被取消')return Promise.reject(error)}handleHttpError(error)return Promise.reject(error)}
)// 處理 HTTP 錯誤
const handleHttpError = error => {if (error.response) {switch (error.response.status) {case 404:console.error('請求的資源不存在')breakcase 500:console.error('服務器錯誤')breakdefault:console.error('網絡錯誤')}} else if (error.request) {console.error('請求超時')} else {console.error('請求錯誤')}
}export default request
在項目中啟動的VConsole,用于調試移動端網頁
viteVConsole函數用于初始化和配置VConsole,接收一個配置對象作為參數
entry,配置VConsole的入口文件,path.resolve用于將相對路徑轉換為絕對路徑,指定了入口文件為src/main.js
enabled,設置VConsole的啟用狀態
config,用于配置VConsole的各種參數,maxLogNumber設置日志的最大數量,當日志超過這個數量,舊的日志就會被自動清除;theme設置VConsole的主題為黑色
當然在這之前的先安裝相應的依賴,vconsole不必說
vite-plugin-vconsole自動集成vconsole,通過插件就可以實現vconsole的自動注入,無需修改代碼;可以根據不同的構建環境動態的啟動或者禁用vconsole,使用vite插件系統更攘夷進行擴展和維護
npm install vconsole --save
npm install vite-plugin-vconsole --save-dev//專門用于開發環境的工具