Vue3+Node.js實(shí)現(xiàn)AI流式輸出方式
最近在入門AI領(lǐng)域,發(fā)現(xiàn)AI對(duì)話場(chǎng)景中最影響用戶體驗(yàn)的就是“流式輸出”——像ChatGPT那樣逐字逐句顯示回復(fù),而不是等待全部?jī)?nèi)容加載完成,這也是前端與AI結(jié)合的核心交互點(diǎn)之一。
結(jié)合自己的學(xué)習(xí)實(shí)踐,今天就來(lái)詳細(xì)拆解:用Vue3(前端)+Node.js(后端)如何實(shí)現(xiàn)流式輸出,前后端配合的完整流程是什么,實(shí)戰(zhàn)中會(huì)遇到哪些坑、怎么解決,以及如何優(yōu)化系統(tǒng)性能、保證數(shù)據(jù)安全。
一、先搞懂:什么是流式輸出?
在AI對(duì)話、實(shí)時(shí)日志、大數(shù)據(jù)展示等場(chǎng)景中,傳統(tǒng)的“請(qǐng)求-完整響應(yīng)”模式會(huì)有明顯的弊端:比如AI生成一篇長(zhǎng)回復(fù)需要3-5秒,用戶只能空白等待,體驗(yàn)很差。
流式輸出的核心的是「增量傳輸、實(shí)時(shí)渲染」:后端調(diào)用AI接口時(shí),不等待完整結(jié)果,而是將生成的內(nèi)容拆分成多個(gè)小片段(chunk),逐段返回給前端;前端接收一個(gè)片段,就渲染一個(gè)片段,實(shí)現(xiàn)“打字機(jī)”效果,讓用戶無(wú)需等待,實(shí)時(shí)看到響應(yīng)內(nèi)容。
本文的技術(shù)棧:
- 前端:Vue3(Composition API)+ SSE(Server-Sent Events,優(yōu)先選擇,輕量、原生支持,適配流式文本場(chǎng)景)
- 后端:Node.js + Express + OpenAI Node.js SDK(調(diào)用AI接口,實(shí)現(xiàn)流式轉(zhuǎn)發(fā))
二、前后端流式輸出實(shí)現(xiàn)(實(shí)戰(zhàn)代碼)
先上可運(yùn)行代碼,再拆解細(xì)節(jié),新手可直接復(fù)制搭建環(huán)境,快速跑通demo。
2.1 后端 Node.js + Express 實(shí)現(xiàn)(流式轉(zhuǎn)發(fā)AI接口)
后端的核心作用:接收前端請(qǐng)求,調(diào)用AI接口(開啟流式),將AI返回的chunk逐段轉(zhuǎn)發(fā)給前端,相當(dāng)于“中間轉(zhuǎn)發(fā)站”。
步驟1:初始化后端項(xiàng)目,安裝依賴
mkdir ai-stream-backend cd ai-stream-backend npm init -y npm install express cors openai dotenv # 核心依賴 # cors:解決跨域;openai:調(diào)用AI接口;dotenv:管理環(huán)境變量
步驟2:編寫后端核心代碼(server.js)
require('dotenv').config(); // 加載環(huán)境變量
const express = require('express');
const cors = require('cors');
const { OpenAI } = require('openai');
const app = express();
app.use(cors()); // 允許跨域(開發(fā)環(huán)境,生產(chǎn)環(huán)境需配置具體域名)
app.use(express.json()); // 解析JSON請(qǐng)求體
// 初始化OpenAI客戶端(調(diào)用AI接口,這里以O(shè)penAI兼容接口為例,如阿里云百煉、通義千問(wèn))
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY, // 從環(huán)境變量獲取,避免明文暴露
baseURL: process.env.BASE_URL || 'https://api.openai.com/v1' // 可替換為國(guó)內(nèi)AI接口地址
});
// 流式輸出接口(核心接口)
app.post('/api/stream', async (req, res) => {
try {
const { prompt } = req.body; // 接收前端傳遞的用戶提問(wèn)
if (!prompt) {
return res.status(400).json({ error: '請(qǐng)輸入提問(wèn)內(nèi)容' });
}
// 1. 調(diào)用AI接口,開啟流式(stream: true)
const stream = await openai.chat.completions.create({
model: 'gpt-3.5-turbo', // 可替換為qwen-3.5-plus等國(guó)內(nèi)模型
messages: [
{ role: 'user', content: prompt }
],
stream: true // 開啟流式輸出,核心參數(shù)
});
// 2. 配置SSE響應(yīng)頭(關(guān)鍵:告訴前端這是流式響應(yīng))
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
res.setHeader('Access-Control-Allow-Origin', '*'); // 開發(fā)環(huán)境允許所有域名
// 3. 遍歷AI返回的stream,逐段轉(zhuǎn)發(fā)給前端
for await (const chunk of stream) {
// 過(guò)濾空chunk(AI會(huì)返回空片段表示結(jié)束,避免前端報(bào)錯(cuò))
const content = chunk.choices[0]?.delta?.content;
if (content) {
// SSE格式:必須以 "data: 內(nèi)容\n\n" 結(jié)尾,否則前端無(wú)法解析
res.write(`data: ${content}\n\n`);
}
}
// 4. 流式結(jié)束,關(guān)閉連接
res.write('data: [END]\n\n');
res.end();
} catch (error) {
console.error('流式接口報(bào)錯(cuò):', error);
res.status(500).write('data: 服務(wù)器異常,請(qǐng)稍后再試\n\n');
res.end();
}
});
// 啟動(dòng)服務(wù)
const PORT = process.env.PORT || 3001;
app.listen(PORT, () => {
console.log(`后端服務(wù)啟動(dòng)成功,端口:${PORT}`);
});步驟3:配置環(huán)境變量(.env文件)
OPENAI_API_KEY=你的AI接口密鑰(如阿里云百煉、OpenAI密鑰) BASE_URL=你的AI接口基礎(chǔ)地址(如阿里云百煉:https://dashscope.aliyuncs.com/compatible-mode/v1) PORT=3001
2.2 前端 Vue3 實(shí)現(xiàn)(流式渲染)
前端的核心作用:發(fā)送用戶提問(wèn)到后端,接收后端轉(zhuǎn)發(fā)的流式片段,逐字渲染到頁(yè)面,實(shí)現(xiàn)打字機(jī)效果,同時(shí)處理異常、中斷等場(chǎng)景。
步驟1:初始化Vue3項(xiàng)目,安裝依賴
npm create vue@latest ai-stream-frontend cd ai-stream-frontend npm install # 無(wú)需額外安裝依賴,Vue3原生支持EventSource(SSE)
步驟2:編寫前端核心組件(StreamChat.vue)
<template>
<div class="stream-chat">
<h2>Vue3 + Node.js AI流式對(duì)話</h2>
<div class="chat-container">
<div class="chat-content" v-text="chatContent"></div>
<div class="loading" v-if="isLoading">思考中...</div>
</div>
<div class="input-container">
<input
v-model="prompt"
placeholder="請(qǐng)輸入你的問(wèn)題..."
@keyup.enter="sendPrompt"
:disabled="isLoading"
/>
<button @click="sendPrompt" :disabled="isLoading">發(fā)送</button>
<button @click="stopStream" :disabled="!isLoading">停止生成</button>
</div>
</div>
</template>
<script setup>
import { ref, onUnmounted } from 'vue';
// 狀態(tài)管理
const prompt = ref(''); // 用戶輸入的提問(wèn)
const chatContent = ref(''); // 流式渲染的內(nèi)容
const isLoading = ref(false); // 加載狀態(tài)
let eventSource = ref(null); // SSE連接實(shí)例
// 發(fā)送提問(wèn),開啟流式請(qǐng)求
const sendPrompt = () => {
if (!prompt.value.trim()) {
alert('請(qǐng)輸入問(wèn)題');
return;
}
// 重置狀態(tài)
chatContent.value = '';
isLoading.value = true;
// 1. 先發(fā)送請(qǐng)求到后端(告知后端用戶提問(wèn))
fetch('http://localhost:3001/api/stream', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ prompt: prompt.value })
}).then(() => {
// 2. 建立SSE連接,接收流式數(shù)據(jù)
eventSource.value = new EventSource('http://localhost:3001/api/stream');
// 3. 接收后端推送的每一個(gè)片段
eventSource.value.onmessage = (event) => {
// 監(jiān)聽流式結(jié)束標(biāo)識(shí)
if (event.data === '[END]') {
isLoading.value = false;
eventSource.value.close(); // 關(guān)閉連接
return;
}
// 逐字追加內(nèi)容,實(shí)現(xiàn)打字機(jī)效果
chatContent.value += event.data;
};
// 4. 處理SSE連接異常
eventSource.value.onerror = (error) => {
console.error('SSE連接異常:', error);
isLoading.value = false;
chatContent.value += '\n\n連接異常,請(qǐng)稍后再試';
eventSource.value.close();
};
}).catch((error) => {
console.error('發(fā)送請(qǐng)求失敗:', error);
isLoading.value = false;
chatContent.value += '\n\n發(fā)送請(qǐng)求失敗,請(qǐng)稍后再試';
});
};
// 停止流式生成(中斷連接)
const stopStream = () => {
if (eventSource.value) {
eventSource.value.close();
eventSource.value = null;
}
isLoading.value = false;
};
// 組件卸載時(shí),關(guān)閉SSE連接(避免內(nèi)存泄漏)
onUnmounted(() => {
if (eventSource.value) {
eventSource.value.close();
}
});
</script>
<style scoped>
.stream-chat {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.chat-container {
width: 100%;
min-height: 300px;
border: 1px solid #eee;
padding: 20px;
margin-bottom: 20px;
border-radius: 8px;
white-space: pre-wrap; /* 保留換行 */
}
.loading {
color: #666;
margin-top: 10px;
font-style: italic;
}
.input-container {
display: flex;
gap: 10px;
}
input {
flex: 1;
padding: 10px;
border: 1px solid #eee;
border-radius: 4px;
}
button {
padding: 10px 20px;
border: none;
border-radius: 4px;
background: #42b983;
color: white;
cursor: pointer;
}
button:disabled {
background: #ccc;
cursor: not-allowed;
}
</style>步驟3:在App.vue中引入組件
<template> <StreamChat /> </template> <script setup> import StreamChat from './components/StreamChat.vue'; </script>
三、前后端配合的完整流程(圖文拆解)
結(jié)合上面的代碼,我們梳理一下前后端配合實(shí)現(xiàn)流式輸出的完整鏈路,每一步都對(duì)應(yīng)實(shí)戰(zhàn)代碼,新手可以對(duì)照理解:
完整流程步驟(共6步)
- 前端發(fā)起請(qǐng)求:用戶在Vue3頁(yè)面輸入提問(wèn),點(diǎn)擊“發(fā)送”,前端通過(guò)fetch發(fā)送POST請(qǐng)求到后端的「/api/stream」接口,攜帶用戶提問(wèn)內(nèi)容(prompt)。
- 后端調(diào)用AI接口:后端接收請(qǐng)求后,通過(guò)OpenAI Node.js SDK調(diào)用AI接口,開啟流式模式(stream: true),AI模型開始逐段生成回復(fù)。
- 后端轉(zhuǎn)發(fā)流式片段:后端通過(guò)for await循環(huán)遍歷AI返回的stream,過(guò)濾空片段,將有效內(nèi)容按照SSE格式(data: 內(nèi)容\n\n)逐段寫入響應(yīng)(res.write)。
- 前端建立SSE連接:前端fetch請(qǐng)求成功后,創(chuàng)建EventSource實(shí)例,連接后端的「/api/stream」接口,監(jiān)聽后端推送的message事件。
- 前端實(shí)時(shí)渲染:前端每接收到一個(gè)流式片段(event.data),就將其追加到chatContent中,通過(guò)v-text渲染到頁(yè)面,實(shí)現(xiàn)打字機(jī)效果。
- 流式結(jié)束/中斷:當(dāng)AI生成完成,后端發(fā)送「[END]」標(biāo)識(shí),前端接收后關(guān)閉SSE連接,結(jié)束加載;若用戶點(diǎn)擊“停止生成”,前端主動(dòng)關(guān)閉SSE連接,后端檢測(cè)到連接關(guān)閉后,終止AI接口調(diào)用。
流程示意圖(簡(jiǎn)化)
用戶 → Vue3前端(發(fā)送prompt)→ Node.js后端(調(diào)用AI流式接口)→ AI模型(逐段返回chunk)→ 后端(轉(zhuǎn)發(fā)chunk)→ 前端(逐段渲染)→ 用戶看到打字機(jī)效果
四、實(shí)戰(zhàn)中常見(jiàn)問(wèn)題及解決方案(踩坑總結(jié))
我在搭建這個(gè)demo時(shí),踩了很多新手常犯的錯(cuò)誤,整理了最常見(jiàn)的6個(gè)問(wèn)題,每個(gè)問(wèn)題都附上場(chǎng)景、原因和解決方案,幫大家避坑。
問(wèn)題1:前端報(bào)跨域錯(cuò)誤(最常見(jiàn))
現(xiàn)象:瀏覽器控制臺(tái)報(bào)錯(cuò):
Access to EventSource at 'http://localhost:3001/api/stream' from origin 'http://localhost:5173' has been blocked by CORS policy。
原因:前端端口(5173)與后端端口(3001)不同,屬于跨域請(qǐng)求,瀏覽器的同源策略攔截了SSE連接。
解決方案:后端開啟CORS,并且配置允許SSE相關(guān)的響應(yīng)頭(前面的后端代碼已包含):
// 后端配置(關(guān)鍵代碼)
app.use(cors()); // 開發(fā)環(huán)境允許所有跨域請(qǐng)求
// 流式接口中添加響應(yīng)頭
res.setHeader('Access-Control-Allow-Origin', '*');
生產(chǎn)環(huán)境注意:不要用*,配置具體的前端域名(如https://yourdomain.com),避免安全風(fēng)險(xiǎn)。
問(wèn)題2:前端接收不到數(shù)據(jù),或出現(xiàn)亂碼
現(xiàn)象:前端無(wú)任何渲染,或出現(xiàn)「data: xxx」亂碼、undefined。
原因:后端SSE格式錯(cuò)誤(必須以「data: 內(nèi)容\n\n」結(jié)尾,兩個(gè)換行符是關(guān)鍵);或后端沒(méi)有過(guò)濾空chunk。
解決方案:
// 后端關(guān)鍵修復(fù)
const content = chunk.choices[0]?.delta?.content;
if (content) {
res.write(`data: ${content}\n\n`); // 必須是\n\n結(jié)尾
}
問(wèn)題3:流式輸出到一半突然中斷
現(xiàn)象:回復(fù)生成到一半,前端停止渲染,SSE連接斷開。
原因:Node.js默認(rèn)有連接超時(shí)限制;或AI接口返回異常;或后端沒(méi)有處理背壓?jiǎn)栴},導(dǎo)致數(shù)據(jù)堆積溢出。
解決方案:
- 后端添加連接超時(shí)配置,延長(zhǎng)連接存活時(shí)間;
- 處理背壓:利用Node.js流的自動(dòng)背壓機(jī)制,或手動(dòng)監(jiān)聽drain事件,避免數(shù)據(jù)堆積(參考Node.js流的背壓處理機(jī)制);
- 添加異常捕獲,確保即使AI接口報(bào)錯(cuò),也能正常關(guān)閉連接,給前端返回錯(cuò)誤提示。
// 后端添加超時(shí)配置
app.use((req, res, next) => {
res.setTimeout(300000, () => { // 5分鐘超時(shí)
res.end('data: 連接超時(shí),請(qǐng)重新提問(wèn)\n\n');
});
next();
});
問(wèn)題4:前端打字機(jī)效果卡頓、閃爍
現(xiàn)象:文字不是逐字渲染,而是一段一段跳,或頁(yè)面出現(xiàn)閃爍。
原因:前端頻繁更新DOM(每次追加內(nèi)容都觸發(fā)重繪);或AI返回的chunk過(guò)大。
解決方案:
- 用v-text替代v-html(減少DOM解析開銷),或用textContent操作DOM,比innerHTML更高效;
- 用變量緩存全文,批量更新DOM(比如每接收3個(gè)字符更新一次);
- 后端控制chunk大小,避免一次性返回過(guò)多內(nèi)容。
問(wèn)題5:多個(gè)請(qǐng)求并發(fā),內(nèi)容串流(多人使用時(shí))
現(xiàn)象:A用戶的提問(wèn),返回的是B用戶的回復(fù);或同一個(gè)用戶多次發(fā)送請(qǐng)求,內(nèi)容混在一起。
原因:沒(méi)有做會(huì)話隔離,后端全局共享stream實(shí)例,導(dǎo)致多個(gè)請(qǐng)求共用一個(gè)流。
解決方案:
- 前端每次發(fā)送請(qǐng)求時(shí),攜帶唯一的chatId(比如用uuid生成);
- 后端根據(jù)chatId隔離stream實(shí)例,每個(gè)請(qǐng)求對(duì)應(yīng)一個(gè)獨(dú)立的stream,避免共享;
- 前端關(guān)閉SSE連接時(shí),攜帶chatId,后端終止對(duì)應(yīng)chatId的stream。
問(wèn)題6:HTTPS環(huán)境下SSE連接失敗
現(xiàn)象:本地HTTP環(huán)境正常,上線HTTPS后,SSE連接失敗,報(bào)mixed content錯(cuò)誤。
原因:瀏覽器安全策略限制,HTTPS頁(yè)面不能加載HTTP的SSE連接,必須統(tǒng)一為HTTPS。
解決方案:
- 后端部署HTTPS(配置SSL證書);
- 前端SSE連接地址改為HTTPS(eventSource = new EventSource('https://yourdomain.com/api/stream'));
- 避免混合HTTP和HTTPS資源,確保所有請(qǐng)求都是HTTPS。
五、系統(tǒng)性能優(yōu)化(前端+后端)
流式輸出的性能優(yōu)化,核心是「減少延遲、降低內(nèi)存占用、避免資源浪費(fèi)」,結(jié)合前端和后端分別優(yōu)化,新手也能快速上手。
5.1 前端性能優(yōu)化
- 優(yōu)化DOM渲染:用textContent替代innerHTML,減少DOM解析開銷;批量更新DOM(比如每10ms更新一次),避免頻繁重繪。
- 防抖處理:用戶快速發(fā)送多次請(qǐng)求時(shí),添加防抖(比如300ms),避免重復(fù)請(qǐng)求,浪費(fèi)資源。
- 資源釋放:組件卸載、用戶離開頁(yè)面時(shí),主動(dòng)關(guān)閉SSE連接,避免內(nèi)存泄漏;停止生成時(shí),及時(shí)終止連接,減少不必要的請(qǐng)求。
- 虛擬滾動(dòng):如果流式輸出內(nèi)容過(guò)長(zhǎng)(比如萬(wàn)字回復(fù)),用虛擬滾動(dòng)(如vue-virtual-scroller),只渲染可視區(qū)域的內(nèi)容,減少DOM節(jié)點(diǎn)數(shù)量。
5.2 后端性能優(yōu)化
- 背壓控制:利用Node.js流的背壓機(jī)制,避免數(shù)據(jù)生產(chǎn)速度快于消費(fèi)速度導(dǎo)致的內(nèi)存溢出,可通過(guò)調(diào)整highWaterMark參數(shù)優(yōu)化緩沖區(qū)大小,或用stream.pipeline()替代鏈?zhǔn)絧ipe()調(diào)用,提升流處理效率。
- 連接復(fù)用:配置HTTP長(zhǎng)連接(keep-alive),減少每次請(qǐng)求的連接建立開銷;合理設(shè)置keepAliveTimeout和headersTimeout,延長(zhǎng)連接存活時(shí)間。
- 緩存優(yōu)化:對(duì)高頻提問(wèn)(如“你是誰(shuí)”)進(jìn)行緩存,后端直接返回緩存結(jié)果,無(wú)需重復(fù)調(diào)用AI接口,減少延遲和token消耗。
- 限流控制:限制單個(gè)用戶的并發(fā)請(qǐng)求數(shù)(比如每秒最多1個(gè)請(qǐng)求),避免惡意請(qǐng)求導(dǎo)致服務(wù)器過(guò)載。
- 異步處理:用異步迭代器(for await...of)處理流式數(shù)據(jù),避免阻塞事件循環(huán);CPU密集型任務(wù)可采用Worker線程,避免影響整體服務(wù)性能。
六、數(shù)據(jù)安全性保障(關(guān)鍵?。?/h2>
AI流式接口涉及API密鑰、用戶提問(wèn)、AI回復(fù)等數(shù)據(jù),安全性容易被忽略,結(jié)合前端和后端,做好這5點(diǎn),避免安全風(fēng)險(xiǎn)。
6.1 后端安全保障
- API密鑰加密存儲(chǔ):不要將AI接口密鑰(如OPENAI_API_KEY)明文寫在代碼中,用.env文件存儲(chǔ),通過(guò)process.env獲取;生產(chǎn)環(huán)境用服務(wù)器環(huán)境變量,避免密鑰泄露。
- 接口鑒權(quán):添加用戶認(rèn)證(如JWT),只有登錄用戶才能調(diào)用流式接口,避免匿名惡意請(qǐng)求;生成JWT時(shí)設(shè)置合理的有效期,使用強(qiáng)密鑰,定期更換。
- 請(qǐng)求參數(shù)校驗(yàn):校驗(yàn)前端傳遞的prompt,過(guò)濾惡意內(nèi)容(如SQL注入、XSS腳本),避免后端被攻擊。
- 敏感數(shù)據(jù)過(guò)濾:對(duì)用戶提問(wèn)和AI回復(fù)中的敏感信息(如手機(jī)號(hào)、密碼)進(jìn)行過(guò)濾、加密,避免數(shù)據(jù)泄露。
- 日志監(jiān)控:記錄接口調(diào)用日志(用戶ID、提問(wèn)內(nèi)容、調(diào)用時(shí)間),便于排查異常,及時(shí)發(fā)現(xiàn)惡意請(qǐng)求。
6.2 前端安全保障
- 防止XSS攻擊:對(duì)AI返回的內(nèi)容進(jìn)行轉(zhuǎn)義處理,避免惡意腳本注入;用v-text替代v-html,減少XSS風(fēng)險(xiǎn)。
- Token安全存儲(chǔ):前端存儲(chǔ)用戶認(rèn)證Token時(shí),用HttpOnly Cookie,避免localStorage被XSS攻擊竊?。辉O(shè)置SameSite屬性,防止CSRF攻擊。
- 避免明文傳遞敏感信息:用戶提問(wèn)中若有敏感信息,前端先加密再傳遞給后端,后端解密后再調(diào)用AI接口。
- 請(qǐng)求合法性校驗(yàn):前端發(fā)送請(qǐng)求時(shí),添加請(qǐng)求頭(如Authorization),避免非法請(qǐng)求。
七、總結(jié)與學(xué)習(xí)感悟
其實(shí)流式輸出的核心并不復(fù)雜:后端負(fù)責(zé)“拿數(shù)據(jù)”(調(diào)用AI流式接口,轉(zhuǎn)發(fā)chunk),前端負(fù)責(zé)“展示數(shù)據(jù)”(接收chunk,實(shí)時(shí)渲染),前后端通過(guò)SSE協(xié)議配合,就能實(shí)現(xiàn)ChatGPT那樣的打字機(jī)效果。
實(shí)戰(zhàn)中,最容易踩的坑是跨域、SSE格式錯(cuò)誤、連接中斷,只要記住“后端開CORS、SSE格式要規(guī)范、及時(shí)釋放資源”,就能解決大部分問(wèn)題;而性能優(yōu)化和數(shù)據(jù)安全,雖然細(xì)節(jié)較多,但只要從“減少開銷、防止泄露”的角度出發(fā),逐步優(yōu)化,就能讓系統(tǒng)更穩(wěn)定、更安全。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue限制輸入框只能輸入8位整數(shù)和2位小數(shù)的代碼
這篇文章主要介紹了vue限制輸入框只能輸入8位整數(shù)和2位小數(shù),文中我們使用v-model加watch 實(shí)現(xiàn)這一個(gè)功能,代碼簡(jiǎn)單易懂,需要的朋友可以參考下2019-11-11
Vue?Vuex搭建vuex環(huán)境及vuex求和案例分享
這篇文章主要介紹了Vue?Vuex搭建vuex環(huán)境及vuex求和案例分享,?Vue?中實(shí)現(xiàn)集中式狀態(tài)管理的一個(gè)?Vue?插件,對(duì)?vue?應(yīng)用中多個(gè)組件的共享狀態(tài)進(jìn)行集中式的管理,下文相關(guān)介紹,需要的朋友可以參考一下2022-04-04
vue-cli3在main.js中console.log()會(huì)報(bào)錯(cuò)的解決
這篇文章主要介紹了vue-cli3在main.js中console.log()會(huì)報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04
在Vue項(xiàng)目中引入騰訊驗(yàn)證碼服務(wù)的教程
這篇文章主要介紹了在Vue項(xiàng)目中引入騰訊驗(yàn)證碼服務(wù)的教程,需要的朋友可以參考下2018-04-04
vue實(shí)現(xiàn)圖片按比例縮放問(wèn)題操作
這篇文章主要介紹了vue實(shí)現(xiàn)圖片按比例縮放問(wèn)題操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08

