最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

TensorFlow.js圖片分類應用開發(fā)項目實戰(zhàn)記錄

 更新時間:2026年06月06日 14:11:29   作者:瑪蹄柯拿  
TensorFlow.js是由Google開發(fā)的一個開源庫,允許你直接在瀏覽器和Node.js環(huán)境中定義、訓練和運行機器學習模型,這篇文章主要介紹了TensorFlow.js圖片分類應用開發(fā)項目實戰(zhàn)的相關資料,需要的朋友可以參考下

一個基于深度學習的Web圖像識別應用開發(fā)全記錄

前言

在這個人工智能日益普及的時代,將機器學習能力融入Web應用已成為前端開發(fā)的重要趨勢。今天,我要和大家分享一個基于TensorFlow.js開發(fā)的圖片分類應用項目,通過這個項目,我們可以深入了解如何在瀏覽器端實現(xiàn)圖像識別功能。

這個項目不僅是一個實用的工具,更是一個學習前端AI應用的絕佳案例。讓我們一起探索如何將復雜的機器學習模型優(yōu)雅地集成到Web應用中!

項目概述

這個應用實現(xiàn)了以下核心功能:

主要功能

  • 圖片上傳:支持點擊選擇和拖拽上傳兩種方式
  • 攝像頭拍攝:實時獲取設備攝像頭畫面進行識別
  • 智能分類:利用預訓練的MobileNet模型進行圖像識別
  • 結果展示:清晰展示識別結果及置信度百分比

項目特點

特點說明
純前端實現(xiàn)無需后端服務器,所有處理在瀏覽器完成
輕量級模型使用MobileNet,模型體積小加載快
響應式設計完美適配桌面端和移動端
良好的用戶體驗加載動畫、錯誤提示、使用引導一應俱全

技術棧選擇

在技術棧的選擇上,我考慮了以下幾個關鍵因素:

TensorFlow.js + MobileNet

為什么選擇這個組合呢?TensorFlow.js是Google推出的JavaScript機器學習庫,它讓我們可以直接在瀏覽器中運行機器學習模型,無需后端服務。而MobileNet是一個輕量級的卷積神經網絡,專為移動端和嵌入式設備設計,非常適合Web應用場景。

技術優(yōu)勢:

  1. 無需服務器:所有計算在客戶端完成,減少服務器壓力
  2. 隱私保護:圖片不需要上傳到服務器
  3. 實時響應:網絡延遲降到最低
  4. 離線可用:可配合Service Worker實現(xiàn)離線功能

代碼示例:

// 模型加載代碼示例
async function loadModel() {
    try {
        // 加載MobileNet V2模型,alpha=1.0在速度和準確率之間取得平衡
        model = await mobilenet.load({
            version: 2,
            alpha: 1.0
        });
        isModelReady = true;
        console.log('模型加載成功!');
    } catch (error) {
        handleError('模型加載失敗', error);
    }
}

響應式設計技術

采用現(xiàn)代CSS技術實現(xiàn)響應式布局:

  • CSS Grid:實現(xiàn)雙欄主布局
  • Flexbox:處理組件對齊和導航
  • Media Queries:適配不同屏幕尺寸
  • CSS動畫:增強用戶體驗

核心實現(xiàn)解析

模型加載與狀態(tài)管理

模型加載是整個應用的起點,我們需要處理好加載狀態(tài)、進度反饋和錯誤處理。

/**
 * 加載預訓練的MobileNet模型
 * 使用TensorFlow.js和MobileNet庫
 */
async function loadModel() {
    try {
        updateModelStatus('loading', '正在下載模型文件...');
        simulateProgress(0, 30);
        
        // 加載MobileNet模型
        // 使用version: 2, alpha: 1.0的版本,在準確率和速度之間取得平衡
        model = await mobilenet.load({
            version: 2,
            alpha: 1.0
        });
        
        simulateProgress(30, 60);
        updateModelStatus('loading', '模型加載中...');
        
        // 驗證模型是否正確加載
        if (!model) {
            throw new Error('模型加載失敗,返回值為空');
        }
        
        simulateProgress(60, 100);
        isModelReady = true;
        updateModelStatus('ready', '模型已就緒,可以開始分類');
        
        console.log('? MobileNet模型加載成功');
        
    } catch (error) {
        console.error('? 模型加載失敗:', error);
        handleError('模型加載失敗,請刷新頁面重試。', error);
    }
}

關鍵點解析:

  • 進度模擬:由于TensorFlow.js不提供加載進度,我們使用setInterval模擬進度動畫
  • 狀態(tài)更新:根據(jù)加載進度更新UI狀態(tài),給用戶即時反饋
  • 錯誤處理:捕獲并處理加載過程中的異常

圖片預處理

為了讓模型能夠正確識別圖片,我們需要在分類前對圖片進行預處理。MobileNet模型要求的輸入尺寸是224x224像素。

/**
 * 圖像預處理
 * 將圖像調整為模型要求的輸入尺寸
 * @param {HTMLImageElement} img - 原始圖像
 * @param {number} width - 目標寬度(默認224)
 * @param {number} height - 目標高度(默認224)
 * @returns {HTMLCanvasElement} 處理后的圖像
 */
function preprocessImage(img, width = 224, height = 224) {
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext('2d');
    
    // 保持寬高比的縮放
    const scale = Math.min(width / img.width, height / img.height);
    const newWidth = img.width * scale;
    const newHeight = img.height * scale;
    const x = (width - newWidth) / 2;
    const y = (height - newHeight) / 2;
    
    // 繪制調整后的圖像
    ctx.drawImage(img, x, y, newWidth, newHeight);
    
    return canvas;
}

技術要點:

  • 保持原始圖片的寬高比,避免變形
  • 使用Canvas API進行圖像處理
  • 將圖片縮放到224x224以匹配模型輸入

圖像分類

這是應用的核心功能,使用加載好的模型對圖片進行分類。

/**
 * 對圖像進行分類
 * @param {HTMLImageElement} img - 要分類的圖像元素
 */
async function classifyImage(img) {
    if (!model || !isModelReady) {
        showError('模型尚未就緒,請稍候...');
        return;
    }
    
    showLoading(true);
    
    try {
        // 使用TensorFlow.js進行圖像分類
        // MobileNet模型的輸入尺寸為224x224
        // 獲取前5個預測結果
        const predictions = await model.classify(img, 5);
        
        displayResults(predictions);
        
    } catch (error) {
        console.error('? 分類失敗:', error);
        handleError('圖像分類失敗,請重試。', error);
    } finally {
        showLoading(false);
    }
}

返回結果格式:

// predictions數(shù)組示例
[
    {
        className: "golden retriever",
        probability: 0.98
    },
    {
        className: "Labrador retriever",
        probability: 0.01
    }
    // ...更多結果
]

攝像頭功能實現(xiàn)

使用MediaDevices API訪問設備攝像頭,這是現(xiàn)代瀏覽器提供的標準API。

/**
 * 啟動攝像頭
 */
async function startCamera() {
    if (!isModelReady) {
        showError('模型尚未加載完成,請稍候...');
        return;
    }
    
    try {
        // 請求攝像頭權限并獲取流
        stream = await navigator.mediaDevices.getUserMedia({
            video: {
                facingMode: 'environment', // 優(yōu)先使用后置攝像頭
                width: { ideal: 1280 },
                height: { ideal: 720 }
            },
            audio: false
        });
        
        // 顯示視頻流
        elements.cameraVideo.srcObject = stream;
        elements.cameraPlaceholder.classList.add('hidden');
        elements.cameraVideo.classList.remove('hidden');
        
        // 更新按鈕狀態(tài)
        elements.startCameraBtn.classList.add('hidden');
        elements.captureBtn.disabled = false;
        elements.stopCameraBtn.classList.remove('hidden');
        
        console.log('? 攝像頭已啟動');
        
    } catch (error) {
        console.error('? 攝像頭啟動失敗:', error);
        
        // 處理常見錯誤
        if (error.name === 'NotAllowedError') {
            showError('無法訪問攝像頭,請確保已授予攝像頭權限。');
        } else if (error.name === 'NotFoundError') {
            showError('未檢測到攝像頭設備,請連接攝像頭后重試。');
        } else {
            showError(`攝像頭啟動失敗: ${error.message}`);
        }
    }
}

注意事項:

  • 需要用戶明確授權才能訪問攝像頭
  • 優(yōu)先請求后置攝像頭(移動設備場景)
  • 處理各種可能的錯誤情況

拖拽上傳實現(xiàn)

支持用戶將圖片直接拖拽到上傳區(qū)域,提供更好的用戶體驗。

/**
 * 設置拖拽上傳功能
 */
function setupDragAndDrop() {
    ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
        elements.uploadArea.addEventListener(eventName, preventDefaults);
    });
    
    // 拖拽視覺效果
    ['dragenter', 'dragover'].forEach(eventName => {
        elements.uploadArea.addEventListener(eventName, () => {
            elements.uploadArea.classList.add('dragover');
        });
    });
    
    ['dragleave', 'drop'].forEach(eventName => {
        elements.uploadArea.addEventListener(eventName, () => {
            elements.uploadArea.classList.remove('dragover');
        });
    });
    
    // 處理拖拽釋放
    elements.uploadArea.addEventListener('drop', handleDrop);
}

界面設計亮點

動態(tài)進度指示器

使用CSS動畫模擬模型加載進度,提供視覺反饋:

.progress-bar {
    width: 100%;
    height: 6px;
    background: var(--border-color);
    border-radius: 3px;
    overflow: hidden;
    margin-top: 10px;
}

.progress-fill {
    height: 100%;
    background: linear-gradient(90deg, var(--primary-color), var(--secondary-color));
    border-radius: 3px;
    transition: width 0.5s ease;
    width: 0%;
}

置信度環(huán)形進度

使用SVG實現(xiàn)優(yōu)雅的置信度展示:

.confidence-ring {
    fill: none;
    stroke: var(--success-color);
    stroke-width: 8;
    stroke-linecap: round;
    stroke-dasharray: 283;
    stroke-dashoffset: 283;
    transition: stroke-dashoffset 1s ease, stroke 0.3s ease;
}

SVG圓環(huán)計算:

const circumference = 2 * Math.PI * 45; // 半徑45的圓周長
const offset = circumference - (percent / 100) * circumference;

結果動畫效果

/**
 * 數(shù)字遞增動畫
 */
function animateNumber(element, start, end, duration) {
    const startTime = performance.now();
    
    function update(currentTime) {
        const elapsed = currentTime - startTime;
        const progress = Math.min(elapsed / duration, 1);
        
        // 使用緩動函數(shù)實現(xiàn)平滑動畫
        const easeOut = 1 - Math.pow(1 - progress, 3);
        const current = Math.round(start + (end - start) * easeOut);
        
        element.textContent = current;
        
        if (progress < 1) {
            requestAnimationFrame(update);
        }
    }
    
    requestAnimationFrame(update);
}

響應式布局

/* 桌面端雙欄布局 */
.main-content {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 30px;
}

/* 平板及以下單欄布局 */
@media (max-width: 1024px) {
    .main-content {
        grid-template-columns: 1fr;
    }
    
    .right-panel {
        order: -1; /* 結果區(qū)域置頂 */
    }
}

/* 移動端適配 */
@media (max-width: 768px) {
    .header h1 {
        font-size: 1.8rem;
    }
    
    .confidence-circle {
        width: 120px;
        height: 120px;
    }
}

視覺設計規(guī)范

:root {
    --primary-color: #4f46e5;       /* 主色調 */
    --secondary-color: #06b6d4;     /* 輔助色 */
    --success-color: #10b981;       /* 成功色 */
    --danger-color: #ef4444;        /* 危險色 */
    --warning-color: #f59e0b;       /* 警告色 */
    --bg-gradient-start: #f0f4ff;   /* 背景漸變起始 */
    --bg-gradient-end: #e0e7ff;     /* 背景漸變結束 */
    --card-bg: #ffffff;             /* 卡片背景 */
    --text-primary: #1f2937;        /* 主文字色 */
    --text-secondary: #6b7280;      /* 次要文字色 */
    --border-color: #e5e7eb;        /* 邊框色 */
    --radius-md: 10px;              /* 中等圓角 */
    --radius-lg: 16px;              /* 大圓角 */
    --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
    --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}

錯誤處理機制

完善的錯誤處理是提升用戶體驗的關鍵,我們實現(xiàn)了多層次的錯誤處理機制。

模型加載錯誤

try {
    model = await mobilenet.load({...});
} catch (error) {
    console.error('? 模型加載失敗:', error);
    updateModelStatus('error', '模型加載失敗,請刷新頁面重試。');
    showError('模型加載失敗,請檢查網絡連接后刷新頁面。');
}

攝像頭訪問錯誤

try {
    stream = await navigator.mediaDevices.getUserMedia({...});
} catch (error) {
    if (error.name === 'NotAllowedError') {
        showError('無法訪問攝像頭,請確保已授予攝像頭權限。');
    } else if (error.name === 'NotFoundError') {
        showError('未檢測到攝像頭設備,請連接攝像頭后重試。');
    } else if (error.name === 'NotReadableError') {
        showError('攝像頭已被其他應用占用。');
    } else {
        showError(`攝像頭啟動失敗: ${error.message}`);
    }
}

圖片處理錯誤

const reader = new FileReader();
reader.onerror = () => {
    showError('文件讀取失敗,請重試');
};

img.onerror = () => {
    showError('圖片加載失敗,請重試');
};

統(tǒng)一錯誤展示

/**
 * 顯示錯誤信息
 * @param {string} message - 錯誤消息
 */
function showError(message) {
    elements.resultsSection.classList.add('hidden');
    elements.errorSection.classList.remove('hidden');
    elements.errorMessage.textContent = message;
}

性能優(yōu)化實踐

DOM元素緩存

在應用初始化時緩存所有DOM元素引用,避免頻繁查詢。

/**
 * 緩存DOM元素引用,提高性能
 */
function cacheElements() {
    elements.modelStatus = document.getElementById('model-status');
    elements.statusText = document.getElementById('status-text');
    elements.progressFill = document.getElementById('progress-fill');
    
    elements.uploadArea = document.getElementById('upload-area');
    elements.fileInput = document.getElementById('file-input');
    elements.previewImage = document.getElementById('preview-image');
    
    // ...更多元素
}

CSS動畫優(yōu)先

盡量使用CSS動畫而非JavaScript動畫,減少主線程負擔。

/* CSS動畫 */
.progress-fill {
    transition: width 0.5s ease;
}

.confidence-ring {
    transition: stroke-dashoffset 1s ease, stroke 0.3s ease;
}

圖片尺寸限制

在上傳前驗證圖片大小,避免處理過大的圖片。

// 驗證文件大?。ㄏ拗茷?0MB)
if (file.size > 10 * 1024 * 1024) {
    showError('圖片文件過大,請選擇小于10MB的圖片');
    return;
}

事件委托

使用事件委托處理動態(tài)添加的元素。

// 事件委托示例
document.querySelector('.results-list').addEventListener('click', (e) => {
    // 處理列表項點擊
});

資源清理

在頁面卸載時釋放攝像頭等資源。

window.addEventListener('beforeunload', () => {
    if (stream) {
        stream.getTracks().forEach(track => track.stop());
    }
});

使用指南

環(huán)境要求

要求說明
瀏覽器現(xiàn)代瀏覽器(Chrome、Firefox、Safari、Edge)
網絡穩(wěn)定的網絡連接(首次加載需要下載模型,約20MB)
攝像頭設備攝像頭(使用攝像頭功能時需要)
權限攝像頭訪問權限(首次使用時需要授權)

使用步驟

第一步:打開應用

在瀏覽器中打開index.html文件。

第二步:等待模型加載

頁面會自動下載MobileNet模型,首次加載可能需要幾秒鐘(取決于網絡速度)。狀態(tài)欄會顯示加載進度。

第三步:選擇圖片方式

  • 圖片上傳:點擊"圖片上傳"標簽
  • 攝像頭拍攝:點擊"攝像頭拍攝"標簽

第四步:獲取圖片

上傳模式:

  • 點擊上傳區(qū)域選擇圖片
  • 或直接將圖片拖拽到上傳區(qū)域

攝像頭模式:

  • 點擊"開啟攝像頭"按鈕
  • 允許攝像頭權限請求
  • 調整角度準備拍攝

第五步:開始分類

  • 點擊"開始分類"或"拍照并分類"按鈕

第六步:查看結果

  • 右側會顯示識別結果
  • 置信度以環(huán)形進度展示
  • 下方列出Top 5預測結果

常見問題

Q: 模型加載很慢怎么辦?

A: 首次加載需要下載約20MB的模型文件。請確保網絡連接穩(wěn)定。后續(xù)訪問會使用瀏覽器緩存,加載會快很多。

Q: 攝像頭無法啟動?

A: 請檢查以下幾點:

  • 瀏覽器是否有攝像頭訪問權限
  • 攝像頭是否被其他應用占用
  • 設備是否連接了攝像頭

Q: 識別結果不準確?

A: 嘗試以下方法:

  • 使用清晰、光線充足的照片
  • 確保識別主體在圖片中清晰可見
  • 避免背景過于復雜

技術要點總結

技術點實現(xiàn)方式說明
模型加載TensorFlow.js + MobileNetV2版本,alpha=1.0
圖片處理HTML5 Canvas API尺寸調整和預處理
攝像頭訪問MediaDevices APIgetUserMedia
拖拽上傳Drag and Drop API原生拖拽支持
動畫效果CSS Transitions + SVG圓環(huán)進度動畫
響應式設計CSS Grid + Media Queries三端適配
狀態(tài)管理原生JavaScript變量簡單有效
錯誤處理try-catch + 錯誤類型判斷完善的異常處理

擴展建議

如果你想進一步擴展這個應用,可以考慮以下方向:

多模型支持

集成不同的預訓練模型供用戶選擇:

// 支持多種模型
const models = {
    mobilenet: () => mobilenet.load({ version: 2, alpha: 1.0 }),
    resnet: () => tf.loadLayersModel('https://.../model.json'),
    inception: () => tf.loadLayersModel('https://.../model.json')
};

圖像標注

在圖片上直接顯示識別結果:

function annotateImage(img, predictions) {
    const ctx = img.getContext('2d');
    predictions.forEach(p => {
        // 繪制邊框和標簽
        ctx.strokeStyle = 'red';
        ctx.lineWidth = 2;
        ctx.strokeRect(p.bbox.x, p.bbox.y, p.bbox.width, p.bbox.height);
    });
}

歷史記錄

保存用戶的識別歷史:

// 使用localStorage保存歷史
function saveToHistory(prediction) {
    const history = JSON.parse(localStorage.getItem('recognitionHistory') || '[]');
    history.unshift({
        timestamp: new Date(),
        image: capturedImage,
        result: prediction
    });
    // 只保留最近20條記錄
    localStorage.setItem('recognitionHistory', JSON.stringify(history.slice(0, 20)));
}

批量處理

支持一次處理多張圖片:

async function batchClassify(images) {
    const results = await Promise.all(
        images.map(img => model.classify(img))
    );
    return results;
}

離線支持

使用Service Worker實現(xiàn)離線功能:

// service-worker.js
self.addEventListener('install', (event) => {
    event.waitUntil(
        caches.open('tfjs-classifier-v1').then((cache) => {
            return cache.addAll([
                '/',
                '/index.html',
                '/styles.css',
                '/app.js',
                'https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest/dist/tf.min.js',
                'https://cdn.jsdelivr.net/npm/@tensorflow-models/mobilenet@latest/dist/mobilenet.min.js'
            ]);
        })
    );
});

主題切換

添加深色/淺色主題支持:

function toggleTheme() {
    document.body.classList.toggle('dark-theme');
    const isDark = document.body.classList.contains('dark-theme');
    localStorage.setItem('theme', isDark ? 'dark' : 'light');
}

項目文件結構

TensorFlowDemo/
├── index.html          # 主頁面結構
├── styles.css          # 樣式文件
├── app.js              # 核心邏輯
└── README.md           # 項目說明

結語

通過這個項目,我深刻體會到TensorFlow.js為前端開發(fā)者打開了一扇通往機器學習世界的大門。無需深厚的數(shù)據(jù)科學背景,我們也能在Web應用中集成智能識別能力。

這個項目教會了我:

  1. 前沿技術的力量:TensorFlow.js讓機器學習觸手可及
  2. 用戶體驗的重要性:即使是AI應用,也需要良好的UI/UX設計
  3. 錯誤處理的關鍵:完善的錯誤處理能大幅提升用戶滿意度
  4. 性能優(yōu)化的必要:在前端,性能永遠不能被忽視

前端與AI的結合一定是未來發(fā)展的重要方向。從智能推薦到圖像識別,從自然語言處理到實時翻譯,AI正在改變我們構建Web應用的方式。

希望這個項目能給大家一些啟發(fā),也期待看到更多有趣的前端AI應用!

參考資源

到此這篇關于TensorFlow.js圖片分類應用開發(fā)項目的文章就介紹到這了,更多相關TensorFlow.js圖片分類應用內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 結合ES6?編寫?JavaScript?設計模式中的結構型模式

    結合ES6?編寫?JavaScript?設計模式中的結構型模式

    這篇文章主要介紹了結合ES6編寫JavaScript?設計模式中的結構型模式,設計模式是軟件設計中常見問題的解決方案,這些模式很容易重復使用并且富有表現(xiàn)力
    2022-07-07
  • JS在Canvas元素內繪制鐘表

    JS在Canvas元素內繪制鐘表

    這篇文章介紹了JS在Canvas元素內繪制鐘表的方法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-01-01
  • js/jquery獲取文本框輸入焦點的方法

    js/jquery獲取文本框輸入焦點的方法

    本篇文章主要是對js/jquery獲取文本框輸入焦點的方法進行了介紹,需要的朋友可以過來參考下,希望對大家有所幫助
    2014-03-03
  • uniapp中安裝axios并解決跨域問題小結

    uniapp中安裝axios并解決跨域問題小結

    跨域(Cross-Origin)是指在瀏覽器中,當前網頁的協(xié)議、域名或端口與請求目標的協(xié)議、域名或端口不相同,即存在跨域請求的情況,這篇文章主要介紹了uniapp中安裝axios并解決跨域問題小結,需要的朋友可以參考下
    2024-05-05
  • 微信小程序使用自定義組件導航實現(xiàn)當前頁面高亮

    微信小程序使用自定義組件導航實現(xiàn)當前頁面高亮

    這篇文章主要介紹了微信小程序使用自定義組件導航實現(xiàn)當前頁面高亮,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-01-01
  • 一句話JavaScript表單驗證代碼

    一句話JavaScript表單驗證代碼

    純屬技術交流,在實際應用中不建議那么做。建議js加載比較好。
    2009-08-08
  • JavaScript實現(xiàn)鼠標懸浮頁面切換效果

    JavaScript實現(xiàn)鼠標懸浮頁面切換效果

    這篇文章主要為大家詳細介紹了JavaScript實現(xiàn)鼠標懸浮頁面切換效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • 指定js可訪問其它域名的cookie的方法

    指定js可訪問其它域名的cookie的方法

    指定js可訪問其它域名的cookie的方法...
    2007-09-09
  • 使用typeof判斷function是否存在于上下文

    使用typeof判斷function是否存在于上下文

    這篇文章主要介紹了使用typeof判斷function是否存在于上下文,在窗口加載時,使用typeof進行判斷,需要的朋友可以參考下
    2014-08-08
  • Next.js水合詳解及常見錯誤解決

    Next.js水合詳解及常見錯誤解決

    這篇文章主要介紹了Next.js水合詳解及常見錯誤解決的相關資料,水合遠不止是讓靜態(tài)HTML動起來那么簡單,它是服務端渲染和靜態(tài)生成的靈魂所在,是連接服務器預渲染的靜態(tài)內容與客戶端動態(tài)交互的關鍵橋梁,需要的朋友可以參考下
    2026-03-03

最新評論

新兴县| 高雄县| 新密市| 新竹市| 武城县| 南丰县| 兴化市| 库尔勒市| 海口市| 西峡县| 诸暨市| 磴口县| 小金县| 工布江达县| 南通市| 中宁县| 乌兰浩特市| 湖南省| 花垣县| 子长县| 扶余县| 桓台县| 南投市| 长治市| 滦平县| 卓资县| 甘德县| 昌吉市| 马龙县| 凌云县| 都昌县| 射阳县| 克拉玛依市| 北流市| 彭泽县| 黄骅市| 陆河县| 黑龙江省| 和静县| 商城县| 新竹市|