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

React實(shí)現(xiàn)音頻文件上傳與試聽(tīng)

 更新時(shí)間:2025年09月04日 10:40:34   作者:山雀~  
本文主要介紹了React實(shí)現(xiàn)音頻文件上傳與試聽(tīng),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

實(shí)現(xiàn)一個(gè)react音頻上傳的大致邏輯如下:

1、上方提示語(yǔ)

<Alert
                message={$t('支持%s,音頻大小需為%d以內(nèi),音頻采樣率為%e')
                    .replace('%s', AUDIO_TYPES.join())
                    .replace('%d', `${AUDIO_MAX_SIZE}KB`)
                    .replace('%e', '16K')}
                type='info'
                showIcon
                style={{ width: '50%', marginBottom: 16 }}
            />

其中AUDIO_TYPES是我們定義的['MP3']類型數(shù)組集合,AUDIO_MAX_SIZE100,后續(xù)可修改

2、封裝上傳組件

<AudioUpload>
    <Button icon={<UploadOutlined />}>上傳</Button>
</AudioUpload>

可以封裝一個(gè)AudioUpload組件,組件內(nèi)部大概是

const AudioUpload = props => {
    const { children } = props;
    
    return (
        <Upload>
            {children}  {/* 自定義上傳按鈕 */}
        </Upload>
    );
};

當(dāng)然并不會(huì)這么簡(jiǎn)單,大致解釋一下上傳的事件監(jiān)聽(tīng)機(jī)制

// 不是事件冒泡,而是組件嵌套關(guān)系
<Upload>           {/* 父組件 */}
    <Button>       {/* 子組件 */}
        上傳
    </Button>
</Upload>

具體的流程

首先

// 用戶點(diǎn)擊這個(gè)按鈕
<Button icon={<UploadOutlined />}>
    {$t('com.Upload')}
</Button>

AudioUpload組件中的Upload 組件捕獲點(diǎn)擊
Upload 組件內(nèi)部的事件監(jiān)聽(tīng)器被觸發(fā)
不是事件冒泡,而是 Upload 組件主動(dòng)監(jiān)聽(tīng)子元素的點(diǎn)擊

// Upload 組件內(nèi)部自動(dòng)執(zhí)行
const hiddenInput = document.querySelector('input[type="file"]');
hiddenInput.click(); // 觸發(fā)文件選擇對(duì)話框

3、Ant Design Upload 的實(shí)現(xiàn)原理

事件委托模式

// Upload 組件內(nèi)部的偽代碼邏輯
class Upload extends React.Component {
    componentDidMount() {
        // 監(jiān)聽(tīng)整個(gè)上傳區(qū)域的點(diǎn)擊事件
        this.uploadArea.addEventListener('click', (e) => {
            // 檢查點(diǎn)擊的是否是子元素
            if (e.target.closest('.ant-upload-select-button')) {
                // 觸發(fā)文件選擇
                this.triggerFileSelect();
            }
        });
    }
    
    triggerFileSelect() {
        // 顯示文件選擇對(duì)話框
        this.fileInput.click();
    }
}

4、{children} 的核心作用

提供可點(diǎn)擊的 UI 元素

<Upload>
    {children}  {/* 這里需要一個(gè)可點(diǎn)擊的元素來(lái)觸發(fā)文件選擇 */}
</Upload>
// 如果 Upload 組件沒(méi)有 children
<Upload>
    {/* 空的,沒(méi)有可點(diǎn)擊的元素 */}
</Upload>

// 結(jié)果:用戶無(wú)法點(diǎn)擊任何地方來(lái)觸發(fā)文件選擇
// Upload 組件不知道應(yīng)該監(jiān)聽(tīng)哪個(gè)元素的點(diǎn)擊事件

5、Upload內(nèi)部參數(shù)含義

<Upload
            name='file'
            headers={}
            action={file =>
                Promise.resolve(
           			 `地址 ${file.name}`
                )
            }
            accept={AUDIO_TYPES.map(item => `.${item}`).join()}
            showUploadList={false}
            beforeUpload={beforeUpload}
            onSuccess={refresh}>
            {children}
        </Upload>

5.1 name

name 屬性指定了文件在表單數(shù)據(jù)中的字段名,服務(wù)器端通過(guò)這個(gè)字段名來(lái)獲取上傳的文件。

服務(wù)器端接收:

// 服務(wù)器端會(huì)這樣獲取文件
const uploadedFile = req.files.file;  // 通過(guò) 'file' 字段名獲取

name 的其他可能值

// 根據(jù)文件類型命名
name='audio'           // 音頻文件
name='image'           // 圖片文件
name='document'        // 文檔文件
name='video'           // 視頻文件

// 根據(jù)業(yè)務(wù)功能命名
name='profile-picture' // 頭像
name='background-music' // 背景音樂(lè)
name='notification-sound' // 通知音效

5.2 headers

headers 的作用
headers 屬性用于設(shè)置 HTTP 請(qǐng)求的請(qǐng)求頭,通常用于:
身份認(rèn)證
跨域請(qǐng)求
自定義請(qǐng)求信息
服務(wù)器端識(shí)別

headers 的常見(jiàn)用途

// 認(rèn)證相關(guān)
headers={{
    'Authorization': 'Bearer ' + token,
    'X-API-Key': apiKey,
    'User-Token': userToken
}}

// 跨域相關(guān)
headers={{
    'Access-Control-Allow-Origin': '*',
    'Content-Type': 'multipart/form-data'
}}

// 自定義標(biāo)識(shí)
headers={{
    'X-Request-ID': generateRequestId(),
    'X-Client-Version': '1.0.0',
    'X-Platform': 'web'
}}

// 業(yè)務(wù)相關(guān)
headers={{
    'Device-Id': deviceId,
    'Session-Id': sessionId,
    'Request-Source': 'audio-upload'
}}

5.3 action 屬性

action 的基本作用

1.定義上傳地址

action 屬性指定了文件上傳的目標(biāo) URL,告訴 Upload 組件將文件發(fā)送到哪個(gè)服務(wù)器地址。

2. 觸發(fā)上傳流程

當(dāng)用戶選擇文件并通過(guò)驗(yàn)證后,Upload 組件會(huì)自動(dòng)向 action 指定的地址發(fā)送 HTTP POST 請(qǐng)求,將文件數(shù)據(jù)上傳到服務(wù)器。

action 的不同配置方式

1.靜態(tài) URL

// 最簡(jiǎn)單的配置
<Upload action="/api/upload">
    <Button>上傳</Button>
</Upload>

// 完整的 URL
<Upload action="https://api.example.com/upload">
    <Button>上傳</Button>
</Upload>

2.動(dòng)態(tài) URL

// 根據(jù)文件信息動(dòng)態(tài)構(gòu)建
action={file => `/upload/${file.name}`}

// 根據(jù)環(huán)境動(dòng)態(tài)選擇
action={file => 
    process.env.NODE_ENV === 'production' 
        ? 'https://api.prod.com/upload' 
        : 'http://localhost:3000/upload'
}

// 根據(jù)文件類型動(dòng)態(tài)選擇
action={file => {
    if (file.type.startsWith('audio/')) {
        return '/api/upload/audio';
    }
    if (file.type.startsWith('image/')) {
        return '/api/upload/image';
    }
    return '/api/upload/file';
}}

action 的執(zhí)行時(shí)機(jī)

// 1. 用戶選擇文件
// 2. beforeUpload 驗(yàn)證通過(guò)
// 3. action 函數(shù)被調(diào)用,獲取上傳地址
// 4. 向該地址發(fā)送文件數(shù)據(jù)
// 5. 觸發(fā) onSuccess 或 onError 回調(diào)

使用 Promise.resolve

1、兼容性考慮

// Ant Design Upload 組件期望 action 返回一個(gè) Promise
// 即使我們返回的是同步的字符串,也需要包裝成 Promise

// 正確的方式
action={file => Promise.resolve(uploadUrl)}

// 也可以這樣寫
action={file => new Promise(resolve => resolve(uploadUrl))}

// 或者使用 async/await
action={async file => uploadUrl}

5.4 分塊上傳實(shí)現(xiàn)簡(jiǎn)單方案

1. 基本思路

// 在 action 中判斷文件大小,大文件走分塊上傳
action={file => {
    if (file.size > 10 * 1024 * 1024) { // 大于10MB
        // 分塊上傳
        return '/api/upload/chunk';
    } else {
        // 普通上傳
        return '/api/upload/normal';
    }
}}

具體是

const AudioUpload = props => {
    const [isChunked, setIsChunked] = useState(false);
    
    const handleChunkedUpload = async (file) => {
        // 分塊上傳邏輯
        const chunkSize = 1024 * 1024; // 1MB每塊
        const totalChunks = Math.ceil(file.size / chunkSize);
        
        for (let i = 0; i < totalChunks; i++) {
            const chunk = file.slice(i * chunkSize, (i + 1) * chunkSize);
            const formData = new FormData();
            formData.append('chunk', chunk);
            formData.append('chunkIndex', i);
            formData.append('totalChunks', totalChunks);
            
            await fetch('/api/upload/chunk', {
                method: 'POST',
                body: formData
            });
        }
        
        // 合并文件
        await fetch('/api/upload/merge', {
            method: 'POST',
            body: JSON.stringify({ fileName: file.name, totalChunks })
        });
    };

    const beforeUpload = file => {
        // 大文件使用分塊上傳
        if (file.size > 10 * 1024 * 1024) {
            setIsChunked(true);
            handleChunkedUpload(file);
            return false; // 阻止默認(rèn)上傳
        }
        return true; // 小文件正常上傳
    };

    return (
        <Upload
            action={file => {
                if (isChunked) {
                    return '/api/upload/chunk'; // 分塊上傳地址
                }
                // 原有的上傳地址
                return `地址+${file.name}`;
            }}
            beforeUpload={beforeUpload}
            onSuccess={refresh}>
            {children}
        </Upload>
    );
};

5.5 accept屬性

文件選擇階段

<Upload
    accept={AUDIO_TYPES.map(item => `.${item}`).join()}  // 只顯示 .MP3 文件
    // ...
>

瀏覽器原生文件選擇器
通過(guò) accept 屬性過(guò)濾,只顯示 MP3 文件
用戶選擇文件后,瀏覽器將文件對(duì)象傳遞給組件

5.6 beforeUpload屬性

const beforeUpload = file => {
    const { name, size } = file;  // 從 File 對(duì)象獲取文件信息
    
    // 執(zhí)行各種驗(yàn)證...
    
    // 返回 false 阻止上傳,返回 true 允許上傳
};

5.7 onSuccess屬性

一般是執(zhí)行刷新操作,重新請(qǐng)求服務(wù)器中上傳文件列表,展示到table中

6、音頻播放控制功能分析

主要是在Table中每一行音頻文件的最后放一個(gè)圖標(biāo)

播放音頻

{playUid !== record.uid ? (
                                    <Icon
                                        type='play3'
                                        className='audio-btn'
                                        onClick={() => handlePlayAudio(record)}
                                    />
                                ) : (
                                    <Icon
                                        type='pause2'
                                        className='audio-btn'
                                        onClick={() => handlePauseAudio()}
                                    />
                                )}

其中一開(kāi)始

const [playUid, setPlayUid] = useState(-1);

那么開(kāi)始前就是播放圖標(biāo)

執(zhí)行流程

const handlePlayAudio = record => {
    // 1. 提取音頻信息
    const { uid, url } = record;
    
    // 2. 設(shè)置播放狀態(tài)
    setPlayUid(uid);
    
    // 3. 獲取環(huán)境配置
    const urlParamsString = localStorage.getItem('_urlParams');
    const urlParams = urlParamsString ? JSON.parse(urlParamsString) : {};
    const { Prefix, UserToken, DeviceId } = urlParams;
    
    // 4. 構(gòu)建文件加載地址
    const preFix = 地址;
    
    // 5. 先停止上一個(gè)音頻
    if (lastAudio.current) {
        lastAudio.current.pause();
    }
    
    // 6. 根據(jù)部署模式選擇播放方式
    if (CLOUDWEB) {
        // 云端模式:先下載再播放
        // ...
    } else {
        // 本地模式:直接播放
        // ...
    }
};

本地模式處理

else {
    // 直接使用文件路徑創(chuàng)建音頻對(duì)象
    lastAudio.current = new Audio(preFix + url);
    
    // 開(kāi)始播放
    lastAudio.current.play();
    
    // 設(shè)置播放結(jié)束和錯(cuò)誤處理
    lastAudio.current.onended = () => {
        setPlayUid(-1);
    };
    lastAudio.current.onerror = () => {
        setPlayUid(-1);
    };
}

暫停當(dāng)前正在播放的音頻

const handlePauseAudio = () => {
    // 1. 暫停音頻播放
    if (lastAudio.current) {
        lastAudio.current.pause();
    }
    
    // 2. 重置播放狀態(tài)
    setPlayUid(-1);
};

7、文件內(nèi)容處理機(jī)制詳解

7.1 文件對(duì)象結(jié)構(gòu)

const file = {
    name: 'audio.mp3',           // 文件名
    size: 51200,                 // 文件大小(字節(jié))
    type: 'audio/mpeg',          // MIME類型
    lastModified: 1234567890,    // 最后修改時(shí)間
    // 文件的實(shí)際二進(jìn)制內(nèi)容存儲(chǔ)在內(nèi)存中,但前端不直接讀取
};

7.2 文件內(nèi)容存儲(chǔ)位置

前端: 只獲取文件的元數(shù)據(jù)(名稱、大小、類型等)
實(shí)際內(nèi)容: 存儲(chǔ)在瀏覽器的內(nèi)存中,作為 File 對(duì)象的一部分
傳輸: 通過(guò) HTTP 請(qǐng)求自動(dòng)傳輸?shù)椒?wù)器

7.3 文件內(nèi)容的傳輸機(jī)制

自動(dòng)傳輸過(guò)程

<Upload
    name='file'                    // 表單字段名
    action={file => Promise.resolve(uploadUrl)}  // 上傳地址
    // ...
/>

傳輸流程:

瀏覽器自動(dòng)創(chuàng)建 FormData 對(duì)象
將 File 對(duì)象作為 file 字段添加到表單
發(fā)送 POST 請(qǐng)求到服務(wù)器
文件內(nèi)容作為請(qǐng)求體的一部分自動(dòng)傳輸

服務(wù)器端接收

// 服務(wù)器端接收到的數(shù)據(jù)格式:
// Content-Type: multipart/form-data
// 
// --boundary
// Content-Disposition: form-data; name="file"; filename="audio.mp3"
// Content-Type: audio/mpeg
// 
// [二進(jìn)制音頻文件內(nèi)容]
// --boundary--

上傳文件生命周期

用戶選擇文件 → 文件存儲(chǔ)在瀏覽器內(nèi)存 → 通過(guò)HTTP傳輸?shù)椒?wù)器 → 服務(wù)器存儲(chǔ)

到此這篇關(guān)于React實(shí)現(xiàn)音頻文件上傳與試聽(tīng)的文章就介紹到這了,更多相關(guān)React 音頻上傳與試聽(tīng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • React useCallback詳細(xì)使用教程

    React useCallback詳細(xì)使用教程

    useCallback是react中比較重要的一個(gè)hook,useCallback 用來(lái)返回一個(gè)函數(shù),在父子組件傳參或者通用函數(shù)封裝中,起到舉足輕重的作用
    2022-11-11
  • 理解react中受控組件和非受控組件及應(yīng)用場(chǎng)景

    理解react中受控組件和非受控組件及應(yīng)用場(chǎng)景

    當(dāng)涉及到React框架時(shí),了解受控組件和非受控組件是非常重要的概念,本文主要介紹了理解react中受控組件和非受控組件及應(yīng)用場(chǎng)景,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • React中key屬性的警告及解決方案

    React中key屬性的警告及解決方案

    在使用 React 進(jìn)行開(kāi)發(fā)時(shí),key 屬性是一個(gè)至關(guān)重要的概念,尤其在渲染列表時(shí),開(kāi)發(fā)者在使用 key 屬性時(shí),常常會(huì)遇到各種警告信息,本文將詳細(xì)解析這些警告的原因,提供有效的解決方案,并總結(jié)最佳實(shí)踐,需要的朋友可以參考下
    2024-12-12
  • React八大常見(jiàn)錯(cuò)誤及其解決方案

    React八大常見(jiàn)錯(cuò)誤及其解決方案

    這篇文章主要介紹了React八大常見(jiàn)錯(cuò)誤及其解決方案,并通過(guò)代碼示例介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)react有一定的幫助,感興趣的朋友可以參考下
    2024-03-03
  • React虛擬渲染實(shí)現(xiàn)50個(gè)或者一百個(gè)圖表渲染

    React虛擬渲染實(shí)現(xiàn)50個(gè)或者一百個(gè)圖表渲染

    這篇文章主要為大家介紹了React虛擬渲染實(shí)現(xiàn)50個(gè)或者100個(gè)圖表渲染的實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • react中useRef的應(yīng)用使用詳解

    react中useRef的應(yīng)用使用詳解

    這篇文章主要介紹了react中useRef的應(yīng)用使用詳解的相關(guān)資料,需要的朋友可以參考下
    2023-05-05
  • React 中合成事件的實(shí)現(xiàn)示例

    React 中合成事件的實(shí)現(xiàn)示例

    本文主要介紹了React 中合成事件的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2025-02-02
  • 深入研究React中setState源碼

    深入研究React中setState源碼

    這篇文章主要介紹了深入研究React中setState源碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-11-11
  • 前端開(kāi)發(fā)使用Ant Design項(xiàng)目評(píng)價(jià)

    前端開(kāi)發(fā)使用Ant Design項(xiàng)目評(píng)價(jià)

    這篇文章主要為大家介紹了前端開(kāi)發(fā)使用Ant Design項(xiàng)目評(píng)價(jià),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • react路由基礎(chǔ)解讀(Router、Link和Route)

    react路由基礎(chǔ)解讀(Router、Link和Route)

    這篇文章主要介紹了react路由基礎(chǔ)解讀(Router、Link和Route),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07

最新評(píng)論