我使用 Laravel 10、Livewire 3 来完成此任务。录音按钮,单击后即可录制语音并保存。我还想保留页面渲染时记录预览的状态,以便我可以执行其他任务,例如在保存之前附加徽章。 我使用调度方法通过创建文件后的 JavaScript 来调用 livewire 方法, 每次我在链接音频文件时得到一个空数组,当我删除它并添加“测试”时,dd 响应是“测试”
过去两天我一直在尝试,但不明白为什么我没有捕捉到录制的文件。请检查下面我的代码
刀片:
<!-- Record/Stop Button with loading toggle -->
<div class="custom-file-upload mb-4 pt-3 text-center">
<button type="button" class="btn btn-primary btn-lg" id="recordButton">
<i class="fas fa-microphone" id="micIcon"></i> <span id="recordButtonText">Start Recording</span>
</button>
</div>
<!-- Duration Display -->
<div id="durationDisplay" class="mt-2 text-center" style="font-size: 1.5rem; color: #333;"></div>
<!-- Audio Preview -->
<div class="mt-3 text-center">
<audio id="audioPreview" controls hidden></audio>
</div>
<!-- Hidden Input for Livewire to Use -->
<input type="file" wire:model="audio" id="audioInput" hidden>
@error('audio')
<span class="text-danger">{{ $message }}</span>
@enderror
<div class="form-group">
<input type="text" class="form-control" wire:model="title" placeholder="Title">
@error('title')
<span class="text-danger">{{ $message }}</span>
@enderror
</div>
<div class="d-flex justify-content-between align-items-center mt-4">
<button type="button" class="btn btn-primary button-style" wire:click="store()" id="publishButton" disabled>
<span wire:loading.remove wire:target="store">Publish Recording</span>
<span wire:loading.class="d-block" wire:target="store" class="d-none"><i class="fas fa-spinner fa-spin el-icon-loading"></i> Publishing...</span>
</button>
<span wire:loading.class="d-block" wire:target="store" class="text-info ml-3 d- none">
<i class="fas fa-spinner fa-spin el-icon-loading"></i> Saving your Recording...
</span>
</div>
@if(session()->has('message'))
<div class="alert alert-success mt-3">{{ session('message') }}</div>
@endif
</el-card>
</div>
</div>
组件记录.php
use Illuminate\Http\UploadedFile;
use Livewire\Component;
use Livewire\WithFileUploads;
use WithFileUploads;
public $title;
public $audio;
public $audioUrl;
protected $listeners = ['audioRecorded'];
public function audioRecorded($audio) // Accept audio directly
{
dd($audio);
// Check if audio is provided and is an instance of UploadedFile
if ($audio instanceof UploadedFile) {
// Process the audio file (e.g., save it to S3)
dd("Audio received successfully", $audio);
} else {
dd("No audio data received.");
}
}
我的Javascript
document.addEventListener('DOMContentLoaded', function () {
const recordButton = document.getElementById('recordButton');
const micIcon = document.getElementById('micIcon');
const recordButtonText = document.getElementById('recordButtonText');
const durationDisplay = document.getElementById('durationDisplay');
const audioPreview = document.getElementById('audioPreview');
const audioInput = document.getElementById('audioInput');
let mediaRecorder;
let audioChunks = [];
let isRecording = false;
let startTime;
let durationInterval;
recordButton.addEventListener('click', () => {
if (!isRecording) {
console.log("Starting recording...");
startRecording();
} else {
console.log("Stopping recording...");
stopRecording();
}
});
function startRecording() {
navigator.mediaDevices.getUserMedia({ audio: true })
.then(stream => {
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.start();
audioChunks = [];
startTime = new Date();
isRecording = true;
mediaRecorder.ondataavailable = event => {
audioChunks.push(event.data);
};
mediaRecorder.onstop = () => {
const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
const audioUrl = URL.createObjectURL(audioBlob);
// Set the preview audio and make it visible
audioPreview.src = audioUrl;
audioPreview.hidden = false;
// Create a File object
const audioFile = new File([audioBlob], 'recording.wav', { type: 'audio/wav' });
// Dispatch the audio file directly
Livewire.dispatch('audioRecorded', { audio: audioFile }); // Send the audio file directly
// Enable the Publish button
document.getElementById('publishButton').disabled = false;
};
micIcon.classList.replace('fa-microphone', 'fa-stop');
recordButtonText.textContent = "Stop Recording";
durationInterval = setInterval(updateDuration, 1000);
})
.catch(error => {
console.error("Error accessing microphone:", error);
alert("Microphone access denied or unavailable.");
});
durationDisplay.textContent = "00:00";
}
function stopRecording() {
if (mediaRecorder && mediaRecorder.state !== "inactive") {
mediaRecorder.stop();
clearInterval(durationInterval);
isRecording = false;
micIcon.classList.replace('fa-stop', 'fa-microphone');
recordButtonText.textContent = "Start Recording";
}
}
function updateDuration() {
const elapsedSeconds = Math.floor((new Date() - startTime) / 1000);
const minutes = String(Math.floor(elapsedSeconds / 60)).padStart(2, '0');
const seconds = String(elapsedSeconds % 60).padStart(2, '0');
durationDisplay.textContent = `${minutes}:${seconds}`;
}
function createFileList(file) {
const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);
return dataTransfer.files;
}
});
实际上遇到了同样的问题:/