vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue文字转语音播放

基于Vue实现文字转语音播放功能的示例代码

作者:IT界Tony哥

这篇文章主要为大家详细介绍了如何基于Vue实现文字转语音播放应用,具有美观的界面和完整的交互功能,感兴趣的小伙伴可以跟随小编一起学习一下

我将为您创建一个完整的Vue文字转语音播放应用,具有美观的界面和完整的交互功能。

设计思路

实现代码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue文字转语音播放器</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="external nofollow" >
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        
        body {
            background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 20px;
        }
        
        .container {
            width: 100%;
            max-width: 800px;
            background-color: rgba(255, 255, 255, 0.95);
            border-radius: 20px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
            overflow: hidden;
        }
        
        .header {
            background: linear-gradient(to right, #4a00e0, #8e2de2);
            color: white;
            padding: 25px;
            text-align: center;
        }
        
        .header h1 {
            font-size: 2.2rem;
            margin-bottom: 10px;
        }
        
        .header p {
            opacity: 0.9;
            font-size: 1.1rem;
        }
        
        .content {
            padding: 30px;
        }
        
        .text-input {
            margin-bottom: 25px;
        }
        
        .text-input label {
            display: block;
            margin-bottom: 10px;
            font-weight: 600;
            color: #333;
            font-size: 1.1rem;
        }
        
        textarea {
            width: 100%;
            min-height: 150px;
            padding: 15px;
            border: 2px solid #e0e0e0;
            border-radius: 10px;
            font-size: 1rem;
            resize: vertical;
            transition: border 0.3s;
        }
        
        textarea:focus {
            outline: none;
            border-color: #6a11cb;
        }
        
        .controls {
            display: flex;
            flex-wrap: wrap;
            gap: 20px;
            margin-bottom: 25px;
        }
        
        .control-group {
            flex: 1;
            min-width: 200px;
        }
        
        .control-group label {
            display: block;
            margin-bottom: 8px;
            font-weight: 600;
            color: #333;
        }
        
        .slider-container {
            display: flex;
            align-items: center;
            gap: 10px;
        }
        
        input[type="range"] {
            flex: 1;
            height: 8px;
            -webkit-appearance: none;
            background: #e0e0e0;
            border-radius: 5px;
            outline: none;
        }
        
        input[type="range"]::-webkit-slider-thumb {
            -webkit-appearance: none;
            width: 20px;
            height: 20px;
            background: #6a11cb;
            border-radius: 50%;
            cursor: pointer;
        }
        
        .value-display {
            min-width: 40px;
            text-align: center;
            font-weight: 600;
            color: #6a11cb;
        }
        
        .voice-selector {
            margin-bottom: 25px;
        }
        
        .voice-selector label {
            display: block;
            margin-bottom: 8px;
            font-weight: 600;
            color: #333;
        }
        
        select {
            width: 100%;
            padding: 12px 15px;
            border: 2px solid #e0e0e0;
            border-radius: 10px;
            font-size: 1rem;
            background-color: white;
            cursor: pointer;
        }
        
        .buttons {
            display: flex;
            justify-content: center;
            gap: 15px;
            flex-wrap: wrap;
        }
        
        button {
            padding: 12px 25px;
            border: none;
            border-radius: 50px;
            font-size: 1rem;
            font-weight: 600;
            cursor: pointer;
            display: flex;
            align-items: center;
            gap: 8px;
            transition: all 0.3s;
        }
        
        .play-btn {
            background: linear-gradient(to right, #00b09b, #96c93d);
            color: white;
            padding: 12px 30px;
        }
        
        .pause-btn {
            background: linear-gradient(to right, #f46b45, #eea849);
            color: white;
        }
        
        .stop-btn {
            background: linear-gradient(to right, #ff416c, #ff4b2b);
            color: white;
        }
        
        button:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
        }
        
        button:active {
            transform: translateY(0);
        }
        
        button:disabled {
            background: #cccccc;
            cursor: not-allowed;
            transform: none;
            box-shadow: none;
        }
        
        .status {
            text-align: center;
            margin-top: 20px;
            padding: 15px;
            border-radius: 10px;
            font-weight: 600;
        }
        
        .status.ready {
            background-color: #e8f5e9;
            color: #2e7d32;
        }
        
        .status.speaking {
            background-color: #e3f2fd;
            color: #1565c0;
        }
        
        .status.paused {
            background-color: #fff3e0;
            color: #ef6c00;
        }
        
        .footer {
            text-align: center;
            padding: 20px;
            color: #777;
            font-size: 0.9rem;
            border-top: 1px solid #eee;
        }
        
        @media (max-width: 600px) {
            .header h1 {
                font-size: 1.8rem;
            }
            
            .content {
                padding: 20px;
            }
            
            button {
                padding: 10px 20px;
                font-size: 0.9rem;
            }
        }
    </style>
</head>
<body>
    <div id="app">
        <div class="container">
            <div class="header">
                <h1><i class="fas fa-volume-up"></i> 文字转语音播放器</h1>
                <p>输入文字,选择语音,然后播放</p>
            </div>
            
            <div class="content">
                <div class="text-input">
                    <label for="text-to-speak"><i class="fas fa-font"></i> 输入要转换的文字:</label>
                    <textarea 
                        id="text-to-speak" 
                        v-model="text" 
                        placeholder="在这里输入您想要转换为语音的文字..."
                    ></textarea>
                </div>
                
                <div class="controls">
                    <div class="control-group">
                        <label for="rate"><i class="fas fa-tachometer-alt"></i> 语速:</label>
                        <div class="slider-container">
                            <input 
                                type="range" 
                                id="rate" 
                                min="0.5" 
                                max="2" 
                                step="0.1" 
                                v-model="rate"
                            >
                            <span class="value-display">{{ rate }}x</span>
                        </div>
                    </div>
                    
                    <div class="control-group">
                        <label for="pitch"><i class="fas fa-waveform"></i> 音调:</label>
                        <div class="slider-container">
                            <input 
                                type="range" 
                                id="pitch" 
                                min="0.5" 
                                max="2" 
                                step="0.1" 
                                v-model="pitch"
                            >
                            <span class="value-display">{{ pitch }}</span>
                        </div>
                    </div>
                </div>
                
                <div class="voice-selector">
                    <label for="voice-select"><i class="fas fa-microphone"></i> 选择语音:</label>
                    <select id="voice-select" v-model="selectedVoice">
                        <option v-for="voice in voices" :value="voice.name">
                            {{ voice.name }} ({{ voice.lang }})
                        </option>
                    </select>
                </div>
                
                <div class="buttons">
                    <button class="play-btn" @click="speak" :disabled="isSpeaking || !text">
                        <i class="fas fa-play"></i> {{ isPaused ? '继续' : '播放' }}
                    </button>
                    <button class="pause-btn" @click="pause" :disabled="!isSpeaking || isPaused">
                        <i class="fas fa-pause"></i> 暂停
                    </button>
                    <button class="stop-btn" @click="stop" :disabled="!isSpeaking && !isPaused">
                        <i class="fas fa-stop"></i> 停止
                    </button>
                </div>
                
                <div class="status" :class="statusClass">
                    <i :class="statusIcon"></i> {{ statusText }}
                </div>
            </div>
            
            <div class="footer">
                <p>使用Web Speech API实现 | Vue 3文字转语音应用</p>
            </div>
        </div>
    </div>

    <script>
        const { createApp, ref, onMounted, computed, watch } = Vue;
        
        createApp({
            setup() {
                const text = ref('欢迎使用Vue文字转语音播放器!这是一个演示应用,您可以输入任何文字并转换为语音播放。');
                const rate = ref(1);
                const pitch = ref(1);
                const voices = ref([]);
                const selectedVoice = ref('');
                const isSpeaking = ref(false);
                const isPaused = ref(false);
                const synth = window.speechSynthesis;
                
                // 计算状态显示
                const statusText = computed(() => {
                    if (isSpeaking.value && !isPaused.value) return '正在播放语音...';
                    if (isPaused.value) return '语音已暂停';
                    if (!text.value) return '请输入要转换的文字';
                    return '准备就绪,点击播放按钮开始';
                });
                
                const statusClass = computed(() => {
                    if (isSpeaking.value && !isPaused.value) return 'speaking';
                    if (isPaused.value) return 'paused';
                    return 'ready';
                });
                
                const statusIcon = computed(() => {
                    if (isSpeaking.value && !isPaused.value) return 'fas fa-play-circle';
                    if (isPaused.value) return 'fas fa-pause-circle';
                    return 'fas fa-check-circle';
                });
                
                // 获取可用的语音列表
                const loadVoices = () => {
                    const availableVoices = synth.getVoices();
                    voices.value = availableVoices;
                    
                    // 默认选择中文语音
                    if (availableVoices.length > 0) {
                        const chineseVoice = availableVoices.find(voice => 
                            voice.lang.includes('zh') || voice.lang.includes('CN')
                        );
                        selectedVoice.value = chineseVoice ? chineseVoice.name : availableVoices[0].name;
                    }
                };
                
                // 初始化语音
                onMounted(() => {
                    // 某些浏览器需要延迟加载语音列表
                    if (synth.onvoiceschanged !== undefined) {
                        synth.onvoiceschanged = loadVoices;
                    }
                    loadVoices();
                });
                
                // 播放语音
                const speak = () => {
                    if (isPaused.value) {
                        // 如果已暂停,恢复播放
                        synth.resume();
                        isPaused.value = false;
                        return;
                    }
                    
                    if (isSpeaking.value) {
                        // 如果正在播放,先停止
                        synth.cancel();
                    }
                    
                    if (!text.value) return;
                    
                    const utterance = new SpeechSynthesisUtterance(text.value);
                    utterance.rate = rate.value;
                    utterance.pitch = pitch.value;
                    
                    // 设置选定的语音
                    const voice = voices.value.find(v => v.name === selectedVoice.value);
                    if (voice) {
                        utterance.voice = voice;
                    }
                    
                    utterance.onstart = () => {
                        isSpeaking.value = true;
                        isPaused.value = false;
                    };
                    
                    utterance.onend = () => {
                        isSpeaking.value = false;
                        isPaused.value = false;
                    };
                    
                    utterance.onerror = () => {
                        isSpeaking.value = false;
                        isPaused.value = false;
                    };
                    
                    synth.speak(utterance);
                };
                
                // 暂停语音
                const pause = () => {
                    if (isSpeaking.value && !isPaused.value) {
                        synth.pause();
                        isPaused.value = true;
                    }
                };
                
                // 停止语音
                const stop = () => {
                    synth.cancel();
                    isSpeaking.value = false;
                    isPaused.value = false;
                };
                
                return {
                    text,
                    rate,
                    pitch,
                    voices,
                    selectedVoice,
                    isSpeaking,
                    isPaused,
                    statusText,
                    statusClass,
                    statusIcon,
                    speak,
                    pause,
                    stop
                };
            }
        }).mount('#app');
    </script>
</body>
</html>

功能说明

这个Vue文字转语音应用具有以下功能:

1.文本输入:用户可以输入或粘贴需要转换为语音的文字

2.语音调节

3.语音选择:从浏览器支持的语音列表中选择喜欢的语音

4.播放控制:播放/暂停/停止功能

5.状态显示:实时显示当前播放状态

6.响应式设计:适配各种屏幕尺寸

使用说明

这个应用使用了现代浏览器的Web Speech API,在Chrome、Edge等主流浏览器中都能良好运行。

到此这篇关于基于Vue实现文字转语音播放功能的示例代码的文章就介绍到这了,更多相关Vue文字转语音播放内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文