欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JS純前端實(shí)現(xiàn)瀏覽器語音播報、朗讀功能的完整代碼

 更新時間:2025年09月24日 10:37:01   作者:??小月亮  
在現(xiàn)代互聯(lián)網(wǎng)的發(fā)展中,語音技術(shù)正逐漸成為改變用戶體驗(yàn)的重要一環(huán),下面這篇文章主要介紹了JS純前端實(shí)現(xiàn)瀏覽器語音播報、朗讀功能的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下

一、朗讀單條文本:

① 語音自選參數(shù),按鈕控制語音:

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>文本轉(zhuǎn)語音播報</title>
    <style>
        body {
            background: #f0f0f0;
            text-align: center;
        }

        .select {
            display: flex;
            justify-content: center;
            align-items: center;
        }
        button {
            font-size: 18px;
        }
        #status {
            margin: 20px;
            color: yellowgreen;
        }
    </style>
</head>

<body>
    <div style="color: rgb(248, 74, 103);">文本轉(zhuǎn)語音播報:此功能依賴瀏覽器支持Web Speech API,目前主流瀏覽器(Chrome、Edge等)均已支持</div>
    <div>
        <h2>輸入要朗讀的文本:</h2>
        <textarea id="textToSpeak" placeholder="請輸入需要朗讀的文本內(nèi)容..." rows="20" cols="100"></textarea>
    </div>
    <div class="select">
        <h3>選擇語音:</h3>
        <select id="voiceSelect">
            <option value="">加載中...</option>
        </select>
    </div>
    <div class="select">
        <h3>語速:</h3>
        <input type="range" id="rate" min="0.5" max="2" step="0.1" value="1">
    </div>
    <div class="select">
        <h3>音調(diào):</h3>
        <input type="range" id="pitch" min="0.5" max="2" step="0.1" value="1">
    </div>
    <div class="select">
        <h3>音量:</h3>
        <input type="range" id="volume" min="0" max="1" step="0.1" value="1">
    </div>
    <!-- 控制按鈕區(qū)域 -->
    <div>
        <button id="startBtn">開始朗讀</button>
        <button id="pauseBtn" disabled>暫停</button>
        <button id="resumeBtn" disabled>繼續(xù)</button>
        <button id="cancelBtn" disabled>停止</button>
    </div>

    <!-- 狀態(tài)顯示區(qū)域 -->
    <div id="status"></div>

</body>
<script>
    // 檢查瀏覽器是否支持Web Speech API
    if ('speechSynthesis' in window) {
        const synth = window.speechSynthesis;
        let voices = [];

        // DOM元素
        const textInput = document.getElementById('textToSpeak');

        const voiceSelect = document.getElementById('voiceSelect');
        const rateInput = document.getElementById('rate');
        const pitchInput = document.getElementById('pitch');
        const volumeInput = document.getElementById('volume');

        const rateValue = document.getElementById('rateValue');
        const pitchValue = document.getElementById('pitchValue');
        const volumeValue = document.getElementById('volumeValue');

        const startBtn = document.getElementById('startBtn');
        const pauseBtn = document.getElementById('pauseBtn');
        const resumeBtn = document.getElementById('resumeBtn');
        const cancelBtn = document.getElementById('cancelBtn');

        const statusDisplay = document.getElementById('status');

        // 獲取可用語音列表
        function loadVoices() {
            voices = synth.getVoices();
            voiceSelect.innerHTML = '';

            // 篩選中文語音優(yōu)先顯示
            const chineseVoices = voices.filter(voice =>
                voice.lang.includes('zh') || voice.name.includes('Chinese')
            );
            const otherVoices = voices.filter(voice =>
                !voice.lang.includes('zh') && !voice.name.includes('Chinese')
            );

            // 添加中文語音
            chineseVoices.forEach(voice => {
                const option = document.createElement('option');
                option.textContent = `${voice.name} (${voice.lang})`;
                option.value = voice.name;
                voiceSelect.appendChild(option);
            });

            // 如果有中文語音,添加分隔線
            if (chineseVoices.length > 0 && otherVoices.length > 0) {
                const separator = document.createElement('option');
                separator.textContent = '────────── 其他語言 ──────────';
                separator.disabled = true;
                voiceSelect.appendChild(separator);
            }

            // 添加其他語音
            otherVoices.forEach(voice => {
                const option = document.createElement('option');
                option.textContent = `${voice.name} (${voice.lang})`;
                option.value = voice.name;
                voiceSelect.appendChild(option);
            });

            // 默認(rèn)選擇第一個中文語音
            if (chineseVoices.length > 0) {
                voiceSelect.value = chineseVoices[0].name;
            } else if (voices.length > 0) {
                voiceSelect.value = voices[0].name;
            }
        }

        // 初始化時加載語音,某些瀏覽器需要觸發(fā)一次語音合成才能加載語音列表
        loadVoices();
        if (speechSynthesis.onvoiceschanged !== undefined) {
            speechSynthesis.onvoiceschanged = loadVoices;
        }

        // 顯示當(dāng)前速率、音調(diào)、音量值
        rateInput.addEventListener('input', () => {
            rateValue.textContent = rateInput.value;
        });

        pitchInput.addEventListener('input', () => {
            pitchValue.textContent = pitchInput.value;
        });

        volumeInput.addEventListener('input', () => {
            volumeValue.textContent = volumeInput.value;
        });

        // 開始朗讀
        startBtn.addEventListener('click', () => {
            if (synth.speaking) {
                synth.cancel();
            }

            const text = textInput.value.trim();
            if (text) {
                statusDisplay.textContent = '正在朗讀...';
                updateButtonStates(true);

                const utterThis = new SpeechSynthesisUtterance(text);

                // 設(shè)置語音
                const selectedVoice = voices.find(voice => voice.name === voiceSelect.value);
                if (selectedVoice) {
                    utterThis.voice = selectedVoice;
                }

                // 設(shè)置語音參數(shù)
                utterThis.rate = parseFloat(rateInput.value);
                utterThis.pitch = parseFloat(pitchInput.value);
                utterThis.volume = parseFloat(volumeInput.value);

                // 朗讀結(jié)束時的回調(diào)
                utterThis.onend = () => {
                    statusDisplay.textContent = '朗讀完成';
                    updateButtonStates(false);
                };

                // 朗讀出錯時的回調(diào)
                utterThis.onerror = (event) => {
                    statusDisplay.textContent = `朗讀出錯: ${event.error}`;
                    updateButtonStates(false);
                };

                synth.speak(utterThis);
            } else {
                statusDisplay.textContent = '請輸入要朗讀的文本';
            }
        });

        // 暫停朗讀
        pauseBtn.addEventListener('click', () => {
            if (synth.speaking) {
                if (synth.paused) {
                    // 如果已經(jīng)暫停,則繼續(xù)
                    synth.resume();
                    statusDisplay.textContent = '繼續(xù)朗讀...';
                    pauseBtn.disabled = false;
                    resumeBtn.disabled = true;
                } else {
                    // 暫停朗讀
                    synth.pause();
                    statusDisplay.textContent = '已暫停';
                    pauseBtn.disabled = true;
                    resumeBtn.disabled = false;
                }
            }
        });

        // 繼續(xù)朗讀
        resumeBtn.addEventListener('click', () => {
            if (synth.paused) {
                synth.resume();
                statusDisplay.textContent = '繼續(xù)朗讀...';
                pauseBtn.disabled = false;
                resumeBtn.disabled = true;
            }
        });

        // 停止朗讀
        cancelBtn.addEventListener('click', () => {
            synth.cancel();
            statusDisplay.textContent = '已停止';
            updateButtonStates(false);
        });

        // 更新按鈕狀態(tài)
        function updateButtonStates(isSpeaking) {
            startBtn.disabled = isSpeaking;
            pauseBtn.disabled = !isSpeaking;
            cancelBtn.disabled = !isSpeaking;
            resumeBtn.disabled = true;
        }

    } else {
        // 瀏覽器不支持Web Speech API時的處理
        document.getElementById('status').textContent = '抱歉,您的瀏覽器不支持語音合成功能,請使用Chrome、Edge等現(xiàn)代瀏覽器。';

        // 禁用所有控制按鈕
        const buttons = document.querySelectorAll('button');
        buttons.forEach(button => {
            button.disabled = true;
            button.classList.add('opacity-50', 'cursor-not-allowed');
        });

        // 禁用選擇框
        document.getElementById('voiceSelect').disabled = true;
        const sliders = document.querySelectorAll('input[type="range"]');
        sliders.forEach(slider => {
            slider.disabled = true;
        });
    }
</script>
</body>

</html>

② 效果圖:

二、朗讀多條文本:

① 語音有默認(rèn)值:

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>文本轉(zhuǎn)語音播報(后端數(shù)據(jù))</title>
    <style>
        body {
            background: #f0f0f0;
            text-align: center;
            padding: 20px;
            font-family: Arial, sans-serif;
        }

        .control-panel {
            margin: 20px 0;
        }

        button {
            font-size: 18px;
            padding: 8px 16px;
            margin: 0 5px;
            cursor: pointer;
            border: none;
            border-radius: 4px;
            background: #4CAF50;
            color: white;
        }

        button:disabled {
            background: #cccccc;
            cursor: not-allowed;
        }

        #status {
            margin: 20px auto;
            color: #333;
            padding: 10px;
            background: #e8f0fe;
            display: inline-block;
            min-width: 300px;
            border-radius: 4px;
        }

        .alarm-list {
            max-width: 600px;
            margin: 20px auto;
            text-align: left;
            background: white;
            padding: 15px;
            border-radius: 4px;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
        }

        .alarm-item {
            padding: 8px 0;
            border-bottom: 1px solid #eee;
        }

        .alarm-item:last-child {
            border-bottom: none;
        }

        .loading {
            color: #666;
            font-style: italic;
        }
    </style>
</head>

<body>
    <div style="color: rgb(248, 74, 103);">文本轉(zhuǎn)語音播報:此功能依賴瀏覽器支持Web Speech API,目前主流瀏覽器(Chrome、Edge等)均已支持</div>

    <!-- 報警信息列表預(yù)覽 -->
    <div class="alarm-list">
        <h4>待朗讀報警信息:</h4>
        <div id="alarmContainer" class="loading">正在從后端獲取數(shù)據(jù)...</div>
    </div>

    <!-- 控制按鈕區(qū)域 -->
    <div class="control-panel">
        <button id="fetchDataBtn">獲取后端數(shù)據(jù)</button>
        <button id="initVoiceBtn" disabled>初始化語音(必須先獲取數(shù)據(jù))</button>
        <button id="startBtn" disabled>開始批量朗讀</button>
        <button id="pauseBtn" disabled>暫停</button>
        <button id="resumeBtn" disabled>繼續(xù)</button>
        <button id="cancelBtn" disabled>停止</button>
    </div>

    <!-- 狀態(tài)顯示區(qū)域 -->
    <div id="status">請點(diǎn)擊"獲取后端數(shù)據(jù)"按鈕開始</div>

</body>
<script>
    // 檢查瀏覽器是否支持Web Speech API
    if ('speechSynthesis' in window) {
        const synth = window.speechSynthesis;
        let voices = [];
        let isVoiceReady = false; // 語音是否準(zhǔn)備就緒
        let currentAlarmIndex = 0; // 當(dāng)前播放的報警索引
        let alarmList = []; // 報警信息列表(后端返回的數(shù)據(jù))
        let isPlaying = false; // 是否正在播放

        // DOM元素
        const fetchDataBtn = document.getElementById('fetchDataBtn');
        const initVoiceBtn = document.getElementById('initVoiceBtn');
        const startBtn = document.getElementById('startBtn');
        const pauseBtn = document.getElementById('pauseBtn');
        const resumeBtn = document.getElementById('resumeBtn');
        const cancelBtn = document.getElementById('cancelBtn');
        const statusDisplay = document.getElementById('status');
        const alarmContainer = document.getElementById('alarmContainer');

        // 模擬從后端獲取報警信息
        fetchDataBtn.addEventListener('click', async () => {
            statusDisplay.textContent = '正在從后端獲取報警信息...';
            fetchDataBtn.disabled = true;

            try {
                // 模擬API請求延遲
                const response = await simulateBackendRequest();

                if (response.success && response.data && response.data.length > 0) {
                    alarmList = response.data;
                    displayAlarmList(alarmList);

                    statusDisplay.textContent = `成功獲取${alarmList.length}條報警信息,請初始化語音`;
                    initVoiceBtn.disabled = false; // 啟用初始化語音按鈕
                } else {
                    statusDisplay.textContent = '后端未返回任何報警信息';
                    fetchDataBtn.disabled = false;
                }
            } catch (err) {
                statusDisplay.textContent = `獲取數(shù)據(jù)失?。?{err.message}`;
                fetchDataBtn.disabled = false;
            }
        });

        // 模擬后端請求
        function simulateBackendRequest() {
            return new Promise((resolve) => {
                // 模擬網(wǎng)絡(luò)延遲
                setTimeout(() => {
                    // 模擬后端返回的數(shù)據(jù)
                    const mockData = {
                        success: true,
                        data: [
                            {
                                "id": 1,
                                "title": "空調(diào)異常警報",
                                "text": "25樓北區(qū)空調(diào)參數(shù)異常:總有功功率實(shí)際值5.79kW,異常狀態(tài)累計15分0秒",
                                "type": 1,
                                "typeText": "輕微",
                                "timestamp": "2023-10-15 09:23:45"
                            },
                            {
                                "id": 2,
                                "title": "配電柜溫度過高",
                                "text": "B棟配電室3號柜溫度超標(biāo):當(dāng)前溫度62°C(閾值55°C),持續(xù)8分30秒",
                                "type": 2,
                                "typeText": "嚴(yán)重",
                                "timestamp": "2023-10-15 10:15:22"
                            },
                            {
                                "id": 3,
                                "title": "水泵壓力異常",
                                "text": "地下二層供水系統(tǒng)壓力異常:當(dāng)前壓力0.25MPa(正常范圍0.3-0.5MPa),持續(xù)12分鐘",
                                "type": 1,
                                "typeText": "輕微",
                                "timestamp": "2023-10-15 11:07:18"
                            },
                            {
                                "id": 4,
                                "title": "消防水箱水位不足",
                                "text": "1號樓消防水箱水位過低:當(dāng)前水位1.2m(最低警戒線1.5m),請立即處理",
                                "type": 3,
                                "typeText": "緊急",
                                "timestamp": "2023-10-15 13:45:03"
                            }
                        ]
                    };
                    resolve(mockData);
                }, 1500); // 1.5秒延遲,模擬真實(shí)網(wǎng)絡(luò)請求
            });
        }

        // 在頁面上顯示報警信息列表
        function displayAlarmList(alarms) {
            alarmContainer.innerHTML = '';
            alarms.forEach((alarm, index) => {
                const item = document.createElement('div');
                item.className = 'alarm-item';
                item.innerHTML = `${index + 1}. ${alarm.text} <span style="color:#666;font-size:0.8em;">(${alarm.typeText})</span>`;
                alarmContainer.appendChild(item);
            });
        }

        // 初始化語音引擎
        initVoiceBtn.addEventListener('click', async () => {
            statusDisplay.textContent = '正在初始化語音引擎...';
            initVoiceBtn.disabled = true;

            try {
                const loadedVoices = await getAvailableVoices();
                // 篩選中文語音(確保有可用的中文語音)
                const chineseVoices = loadedVoices.filter(v =>
                    v.lang === 'zh-CN' ||
                    v.lang === 'zh' ||
                    v.name.includes('Chinese') ||
                    v.name.includes('微軟') ||
                    v.name.includes('慧濤')
                );

                if (chineseVoices.length === 0) {
                    statusDisplay.textContent = '未找到中文語音包,請先在系統(tǒng)中安裝中文語音(如Windows的“微軟慧濤”)';
                    initVoiceBtn.disabled = false;
                    return;
                }

                // 語音初始化完成
                isVoiceReady = true;
                startBtn.disabled = false;
                statusDisplay.textContent = `語音初始化成功!找到${chineseVoices.length}個中文語音包,點(diǎn)擊"開始批量朗讀"按鈕`;
                console.log('可用中文語音:', chineseVoices);
            } catch (err) {
                statusDisplay.textContent = `語音初始化失?。?{err.message}`;
                initVoiceBtn.disabled = false;
            }
        });

        // 獲取語音列表(帶重試機(jī)制)
        function getAvailableVoices() {
            return new Promise((resolve, reject) => {
                // 最多重試3次
                let attempts = 0;
                const checkVoices = () => {
                    const voices = synth.getVoices();
                    if (voices.length > 0) {
                        resolve(voices);
                    } else if (attempts < 3) {
                        attempts++;
                        // 觸發(fā)一次空語音來激活引擎
                        const testUtter = new SpeechSynthesisUtterance('');
                        synth.speak(testUtter);
                        setTimeout(() => {
                            synth.cancel();
                            checkVoices();
                        }, 500);
                    } else {
                        reject(new Error('無法加載語音列表,請刷新頁面重試'));
                    }
                };

                // 監(jiān)聽語音變化事件
                synth.onvoiceschanged = checkVoices;
                // 立即檢查一次
                checkVoices();
            });
        }

        // 開始批量朗讀
        startBtn.addEventListener('click', () => {
            if (!isVoiceReady || alarmList.length === 0) return;

            isPlaying = true;
            currentAlarmIndex = 0; // 從第一條開始
            updateButtonStates(true);
            statusDisplay.textContent = `準(zhǔn)備開始朗讀,共${alarmList.length}條信息`;
            speakNextAlarm(); // 開始朗讀第一條
        });

        // 朗讀下一條報警信息
        function speakNextAlarm() {
            // 如果已經(jīng)讀完所有信息或已停止,則退出
            if (currentAlarmIndex >= alarmList.length || !isPlaying) {
                completeBatchReading();
                return;
            }

            // 停止當(dāng)前正在播放的語音
            if (synth.speaking) {
                synth.cancel();
            }

            const currentAlarm = alarmList[currentAlarmIndex];
            statusDisplay.textContent = `正在朗讀第${currentAlarmIndex + 1}/${alarmList.length}條:${currentAlarm.title}`;

            // 創(chuàng)建語音實(shí)例
            const utterThis = new SpeechSynthesisUtterance(currentAlarm.text);

            // 獲取中文語音
            const chineseVoices = voices.filter(v =>
                v.lang === 'zh-CN' ||
                v.name.includes('Chinese')
            );
            const selectedVoice = chineseVoices.find(voice => voice.lang === 'zh-CN') || chineseVoices[0];
            if (selectedVoice) {
                utterThis.voice = selectedVoice;
            }

            // 設(shè)置語音參數(shù)
            utterThis.rate = 1; // 語速
            utterThis.pitch = 1; // 音調(diào)
            utterThis.volume = 1; // 音量
            utterThis.lang = 'zh-CN'; // 語言

            // 朗讀結(jié)束后處理
            utterThis.onend = () => {
                currentAlarmIndex++;
                // 延遲500ms播放下一條,避免連在一起
                setTimeout(speakNextAlarm, 500);
            };

            // 朗讀出錯處理
            utterThis.onerror = (event) => {
                statusDisplay.textContent = `第${currentAlarmIndex + 1}條朗讀出錯:${event.error}`;
                currentAlarmIndex++;
                setTimeout(speakNextAlarm, 500);
            };

            // 開始朗讀
            synth.speak(utterThis);
        }

        // 批量朗讀完成
        function completeBatchReading() {
            isPlaying = false;
            statusDisplay.textContent = `所有${alarmList.length}條報警信息朗讀完成`;
            updateButtonStates(false);
        }

        // 暫停朗讀
        pauseBtn.addEventListener('click', () => {
            if (synth.speaking) {
                synth.pause();
                statusDisplay.textContent = `已暫停在第${currentAlarmIndex + 1}條`;
                pauseBtn.disabled = true;
                resumeBtn.disabled = false;
            }
        });

        // 繼續(xù)朗讀
        resumeBtn.addEventListener('click', () => {
            if (synth.paused) {
                synth.resume();
                statusDisplay.textContent = `繼續(xù)朗讀第${currentAlarmIndex + 1}條...`;
                pauseBtn.disabled = false;
                resumeBtn.disabled = true;
            }
        });

        // 停止朗讀
        cancelBtn.addEventListener('click', () => {
            synth.cancel();
            isPlaying = false;
            statusDisplay.textContent = '已停止朗讀';
            updateButtonStates(false);
        });

        // 更新按鈕狀態(tài)
        function updateButtonStates(isSpeaking) {
            fetchDataBtn.disabled = isSpeaking;
            initVoiceBtn.disabled = isSpeaking;
            startBtn.disabled = isSpeaking;
            pauseBtn.disabled = !isSpeaking || synth.paused;
            resumeBtn.disabled = !isSpeaking || !synth.paused;
            cancelBtn.disabled = !isSpeaking;
        }

    } else {
        // 瀏覽器不支持Web Speech API時的處理
        document.getElementById('status').textContent = '抱歉,您的瀏覽器不支持語音合成功能,請使用Chrome、Edge等現(xiàn)代瀏覽器。';

        // 禁用所有控制按鈕
        const buttons = document.querySelectorAll('button');
        buttons.forEach(button => {
            button.disabled = true;
            button.style.opacity = '0.5';
            button.style.cursor = 'not-allowed';
        });
    }
</script>
</body>

</html>

② 效果圖:

三、如果沒有聲音請注意:

① 是否進(jìn)行了語音包的初始化:

現(xiàn)代瀏覽器(Chrome、Edge、Safari 等)從安全和用戶體驗(yàn)角度出發(fā),強(qiáng)制要求 “語音合成 / 音頻播放” 必須由用戶主動交互觸發(fā)(如點(diǎn)擊、觸摸、鍵盤輸入),模擬點(diǎn)擊會被認(rèn)為是腳本,沒有任何技術(shù)手段能完全 “繞過” 這一限制。

解決辦法: “弱交互觸發(fā)”

頁面加載完成后,用戶只要進(jìn)行 “極輕微的交互”(如點(diǎn)擊頁面任意位置、滾動鼠標(biāo)滾輪、按任意鍵盤鍵),就會立即觸發(fā)語音播報。

② 是否清除了其它正在播放的語音:

if (window.speechSynthesis.speaking) {
  window.speechSynthesis.cancel();
}

總結(jié) 

到此這篇關(guān)于JS純前端實(shí)現(xiàn)瀏覽器語音播報、朗讀功能的文章就介紹到這了,更多相關(guān)JS純前端瀏覽器語音播報朗讀內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論