对端通信
This commit is contained in:
		
							
								
								
									
										8
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								index.js
									
									
									
									
									
								
							@@ -31,10 +31,10 @@ app.ws('/webrtc/:channel', (ws, req) => {
 | 
				
			|||||||
    // 设备发送信令时转发给指定在线设备
 | 
					    // 设备发送信令时转发给指定在线设备
 | 
				
			||||||
    ws.on('message', message => {
 | 
					    ws.on('message', message => {
 | 
				
			||||||
        console.log(ws.id, '设备发送信令:', ws.channel, wsInstance.getWss().clients.size)
 | 
					        console.log(ws.id, '设备发送信令:', ws.channel, wsInstance.getWss().clients.size)
 | 
				
			||||||
        const { id } = JSON.parse(message)
 | 
					        const data = JSON.parse(message)
 | 
				
			||||||
        wsInstance.getWss().clients.forEach(client => {
 | 
					        wsInstance.getWss().clients.forEach(client => {
 | 
				
			||||||
            if (client !== ws && client.readyState === 1 && client.channel === ws.channel && client.id === id) {
 | 
					            if (client !== ws && client.readyState === 1 && client.channel === ws.channel && client.id === data.id) {
 | 
				
			||||||
                client.send(message)
 | 
					                client.send(JSON.stringify({ ...data, id: ws.id }))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
@@ -43,7 +43,7 @@ app.ws('/webrtc/:channel', (ws, req) => {
 | 
				
			|||||||
    wsInstance.getWss().clients.forEach(client => {
 | 
					    wsInstance.getWss().clients.forEach(client => {
 | 
				
			||||||
        if (client !== ws && client.readyState === 1 && client.channel === ws.channel) {
 | 
					        if (client !== ws && client.readyState === 1 && client.channel === ws.channel) {
 | 
				
			||||||
            client.send(JSON.stringify({ type: 'push', id: ws.id, channel: ws.channel }))
 | 
					            client.send(JSON.stringify({ type: 'push', id: ws.id, channel: ws.channel }))
 | 
				
			||||||
            ws.send(JSON.stringify({ type: 'push', id: client.id, channel: client.channel }))
 | 
					            ws.send(JSON.stringify({ type: 'list', id: client.id, channel: client.channel }))
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										110
									
								
								public/client.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								public/client.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
				
			|||||||
 | 
					import { List, ListItem } from './weigets.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class ClientList {
 | 
				
			||||||
 | 
					    constructor() {
 | 
				
			||||||
 | 
					        const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws'
 | 
				
			||||||
 | 
					        const host = window.location.host
 | 
				
			||||||
 | 
					        this.websocket = new WebSocket(`${protocol}://${host}/webrtc/music`)
 | 
				
			||||||
 | 
					        this.clientlist = []
 | 
				
			||||||
 | 
					        this.ul = List({})
 | 
				
			||||||
 | 
					        document.body.appendChild(this.ul)
 | 
				
			||||||
 | 
					        //this.websocket.onopen = event => {
 | 
				
			||||||
 | 
					        //    console.log('clientlist websocket: onopen')
 | 
				
			||||||
 | 
					        //    console.log('当连接建立时,服务器将逐一发送所有客户端信息')
 | 
				
			||||||
 | 
					        //}
 | 
				
			||||||
 | 
					        this.websocket.onmessage = async event => {
 | 
				
			||||||
 | 
					            const data = JSON.parse(event.data)
 | 
				
			||||||
 | 
					            if (data.type === 'list') {
 | 
				
			||||||
 | 
					                console.log('取得在线对端列表:', data)
 | 
				
			||||||
 | 
					                const webrtc = new RTCPeerConnection()
 | 
				
			||||||
 | 
					                webrtc.createDataChannel('music')
 | 
				
			||||||
 | 
					                //webrtc.onicecandidate = event => {
 | 
				
			||||||
 | 
					                //    console.log('clientlist onicecandidate E', event)
 | 
				
			||||||
 | 
					                //    if (event.candidate) {
 | 
				
			||||||
 | 
					                //        this.websocket.send(JSON.stringify({ type: 'candidate', id: data.id, candidate: event.candidate }))
 | 
				
			||||||
 | 
					                //    }
 | 
				
			||||||
 | 
					                //}
 | 
				
			||||||
 | 
					                console.log('发送给对方 offer')
 | 
				
			||||||
 | 
					                const offer = await webrtc.createOffer()
 | 
				
			||||||
 | 
					                await webrtc.setLocalDescription(offer)
 | 
				
			||||||
 | 
					                this.clientlist.push({ id: data.id, name: data.name, webrtc })
 | 
				
			||||||
 | 
					                this.websocket.send(JSON.stringify({ type: 'offer', id: data.id, offer }))
 | 
				
			||||||
 | 
					                return this.add(data)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (data.type === 'push') {
 | 
				
			||||||
 | 
					                console.log('新上线客户端:', data)
 | 
				
			||||||
 | 
					                return this.add(data)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (data.type === 'pull') {
 | 
				
			||||||
 | 
					                console.log('移除客户端:', data)
 | 
				
			||||||
 | 
					                return this.remove(data)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (data.type === 'offer') {
 | 
				
			||||||
 | 
					                console.log('收到对方 offer', data)
 | 
				
			||||||
 | 
					                const webrtc = new RTCPeerConnection()
 | 
				
			||||||
 | 
					                webrtc.createDataChannel('music')
 | 
				
			||||||
 | 
					                //webrtc.onicecandidate = event => {
 | 
				
			||||||
 | 
					                //    console.log('clientlist onicecandidate X', event)
 | 
				
			||||||
 | 
					                //    if (event.candidate) {
 | 
				
			||||||
 | 
					                //        this.websocket.send(JSON.stringify({ type: 'candidate', id: data.id, candidate: event.candidate }))
 | 
				
			||||||
 | 
					                //    }
 | 
				
			||||||
 | 
					                //}
 | 
				
			||||||
 | 
					                this.clientlist.push({ id: data.id, name: data.name, webrtc })
 | 
				
			||||||
 | 
					                console.log('发送给对方 answer')
 | 
				
			||||||
 | 
					                await webrtc.setRemoteDescription(data.offer)
 | 
				
			||||||
 | 
					                const answer = await webrtc.createAnswer()
 | 
				
			||||||
 | 
					                await webrtc.setLocalDescription(answer)
 | 
				
			||||||
 | 
					                this.websocket.send(JSON.stringify({ type: 'answer', id: data.id, answer }))
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (data.type === 'answer') {
 | 
				
			||||||
 | 
					                console.log('收到对方 answer', data)
 | 
				
			||||||
 | 
					                const pc = this.clientlist.find(client => client.id === data.id).webrtc
 | 
				
			||||||
 | 
					                await pc.setRemoteDescription(data.answer)
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (data.type === 'candidate') {
 | 
				
			||||||
 | 
					                const pc = this.clientlist.find(client => client.id === data.id).webrtc
 | 
				
			||||||
 | 
					                await pc.addIceCandidate(data.candidate)
 | 
				
			||||||
 | 
					                return console.log('收到 candidate 并将其添加到远程端', data.candidate)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            console.log('收到未知数据:', data)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    add(item) {
 | 
				
			||||||
 | 
					        //this.clientlist.push(item)
 | 
				
			||||||
 | 
					        this.ul.appendChild(ListItem({
 | 
				
			||||||
 | 
					            id: item.id,
 | 
				
			||||||
 | 
					            innerText: item.name ?? item.id,
 | 
				
			||||||
 | 
					            onclick: event => {
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            chidren: []
 | 
				
			||||||
 | 
					        }))
 | 
				
			||||||
 | 
					        //// 与对方建立连接(即使不传输数据)
 | 
				
			||||||
 | 
					        //const webrtc = new RTCPeerConnection()
 | 
				
			||||||
 | 
					        //const channel = webrtc.createDataChannel('music')
 | 
				
			||||||
 | 
					        //channel.onopen = event => {
 | 
				
			||||||
 | 
					        //    console.log('clientlist music: channel.onopen')
 | 
				
			||||||
 | 
					        //    channel.send('hello')
 | 
				
			||||||
 | 
					        //}
 | 
				
			||||||
 | 
					        //channel.onmessage = event => {
 | 
				
			||||||
 | 
					        //    console.log('clientlist music: channel.onmessage', event.data)
 | 
				
			||||||
 | 
					        //}
 | 
				
			||||||
 | 
					        //// 监听 ICE 候选事件
 | 
				
			||||||
 | 
					        //webrtc.onicecandidate = event => {
 | 
				
			||||||
 | 
					        //    if (event.candidate) {
 | 
				
			||||||
 | 
					        //        console.log('clientlist onicecandidate', event.candidate)
 | 
				
			||||||
 | 
					        //        // 发送给对方(通过服务器)
 | 
				
			||||||
 | 
					        //    }
 | 
				
			||||||
 | 
					        //}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    remove(item) {
 | 
				
			||||||
 | 
					        this.clientlist = this.clientlist.filter(client => client.id !== item.id)
 | 
				
			||||||
 | 
					        this.ul.removeChild(document.getElementById(item.id))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    update(item) { }
 | 
				
			||||||
 | 
					    get(id) { }
 | 
				
			||||||
 | 
					    getAll() { }
 | 
				
			||||||
 | 
					    clear() { }
 | 
				
			||||||
 | 
					    on(event, callback) { }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -15,7 +15,6 @@ export default class IndexedDB {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    open() {
 | 
					    open() {
 | 
				
			||||||
        console.log('open')
 | 
					 | 
				
			||||||
        return new Promise((resolve, reject) => {
 | 
					        return new Promise((resolve, reject) => {
 | 
				
			||||||
            const request = indexedDB.open(this.databaseName, this.databaseVersion)
 | 
					            const request = indexedDB.open(this.databaseName, this.databaseVersion)
 | 
				
			||||||
            request.onerror = (event) => {
 | 
					            request.onerror = (event) => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,24 +9,64 @@
 | 
				
			|||||||
<body>
 | 
					<body>
 | 
				
			||||||
    <div>
 | 
					    <div>
 | 
				
			||||||
        <h1>webRTC</h1>
 | 
					        <h1>webRTC</h1>
 | 
				
			||||||
        <p>message</p>
 | 
					        <p>选择音乐使频道内所有设备同步播放</p>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <script type="module">
 | 
					    <script type="module">
 | 
				
			||||||
        import IndexedDB from './database.js'
 | 
					        import IndexedDB from './database.js'
 | 
				
			||||||
        import MusicList from './music.js'
 | 
					        import MusicList from './music.js'
 | 
				
			||||||
        const musicObjectStore = new IndexedDB('musicDatabase', 1, 'musicObjectStore')
 | 
					        import ClientList from './client.js'
 | 
				
			||||||
        await musicObjectStore.open()
 | 
					 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        // 音乐列表
 | 
					        // 初始化音乐列表
 | 
				
			||||||
        const musicList = new MusicList()
 | 
					        const musicList = new MusicList()
 | 
				
			||||||
        console.log('musicList:', musicList)
 | 
					
 | 
				
			||||||
        //musicList.on('add', async item => {
 | 
					        // 初始化客户端列表
 | 
				
			||||||
        //    console.log('musicList add:', item)
 | 
					        const clientList = new ClientList()
 | 
				
			||||||
        //    const { name, size, type, lastModified, lastModifiedDate, arrayBuffer } = item
 | 
					
 | 
				
			||||||
        //    const id = Date.now()
 | 
					        //// 初始化音乐频道
 | 
				
			||||||
        //    // 存储到 IndexDB
 | 
					        //const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws'
 | 
				
			||||||
        //    await musicObjectStore.add({ id, name, size, type, lastModified, lastModifiedDate, arrayBuffer })
 | 
					        //const host = window.location.host
 | 
				
			||||||
        //})
 | 
					        //const ws = new WebSocket(`${protocol}://${host}/webrtc/music`)
 | 
				
			||||||
 | 
					        //ws.onopen = function () {
 | 
				
			||||||
 | 
					        //    console.log('music ws open')
 | 
				
			||||||
 | 
					        //}
 | 
				
			||||||
 | 
					        //ws.onmessage = function (event) {
 | 
				
			||||||
 | 
					        //    const data = JSON.parse(event.data)
 | 
				
			||||||
 | 
					        //    console.log('ws message:', data)
 | 
				
			||||||
 | 
					        //    if (data.type === 'push') {
 | 
				
			||||||
 | 
					        //        console.log('收到 type:push 将设备增加', data.id)
 | 
				
			||||||
 | 
					        //        clientList.add(data.id, data.channel)
 | 
				
			||||||
 | 
					        //        return
 | 
				
			||||||
 | 
					        //    }
 | 
				
			||||||
 | 
					        //    if (data.type === 'pull') {
 | 
				
			||||||
 | 
					        //        console.log('收到 type:pull 将设备删除', data.id)
 | 
				
			||||||
 | 
					        //        clientList.remove(data)
 | 
				
			||||||
 | 
					        //        return
 | 
				
			||||||
 | 
					        //    }
 | 
				
			||||||
 | 
					        //    if (data.type === 'error') {
 | 
				
			||||||
 | 
					        //        console.log('收到 type:error 没什么可操作的', data.id)
 | 
				
			||||||
 | 
					        //        return
 | 
				
			||||||
 | 
					        //    }
 | 
				
			||||||
 | 
					        //    if (data.offer) {
 | 
				
			||||||
 | 
					        //        console.log('收到 offer 并将其设置为远程描述')
 | 
				
			||||||
 | 
					        //        //clientList.setRemoteDescription(data)
 | 
				
			||||||
 | 
					        //        pc.setRemoteDescription(new RTCSessionDescription(data.offer))
 | 
				
			||||||
 | 
					        //        // 创建SDP answer并将其设置为本地描述, 发送给远程端
 | 
				
			||||||
 | 
					        //        pc.createAnswer().then(function (answer) {
 | 
				
			||||||
 | 
					        //            pc.setLocalDescription(answer);
 | 
				
			||||||
 | 
					        //            ws.send(JSON.stringify({ answer }))
 | 
				
			||||||
 | 
					        //        })
 | 
				
			||||||
 | 
					        //        return
 | 
				
			||||||
 | 
					        //    }
 | 
				
			||||||
 | 
					        //    if (data.answer) {
 | 
				
			||||||
 | 
					        //        console.log('收到 answer 并将其设置为远程描述')
 | 
				
			||||||
 | 
					        //        pc.setRemoteDescription(new RTCSessionDescription(data.answer))
 | 
				
			||||||
 | 
					        //        return
 | 
				
			||||||
 | 
					        //    }
 | 
				
			||||||
 | 
					        //    if (data.candidate) {
 | 
				
			||||||
 | 
					        //        console.log('收到 candidate 并将其添加到远程端')
 | 
				
			||||||
 | 
					        //        pc.addIceCandidate(new RTCIceCandidate(data.candidate))
 | 
				
			||||||
 | 
					        //    }
 | 
				
			||||||
 | 
					        //}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // webRTC 传递音乐(分别传输文件和操作事件能更流畅)
 | 
					        // webRTC 传递音乐(分别传输文件和操作事件能更流畅)
 | 
				
			||||||
        const music = async function () {
 | 
					        const music = async function () {
 | 
				
			||||||
@@ -71,7 +111,6 @@
 | 
				
			|||||||
                audioSource?.stop()
 | 
					                audioSource?.stop()
 | 
				
			||||||
                audioSource = null
 | 
					                audioSource = null
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
 | 
					 | 
				
			||||||
            // 监听 ICE 候选事件
 | 
					            // 监听 ICE 候选事件
 | 
				
			||||||
            pc.onicecandidate = event => {
 | 
					            pc.onicecandidate = event => {
 | 
				
			||||||
                if (event.candidate) {
 | 
					                if (event.candidate) {
 | 
				
			||||||
@@ -144,55 +183,8 @@
 | 
				
			|||||||
                    return
 | 
					                    return
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            // 从数据库读取音乐文件
 | 
					 | 
				
			||||||
            musicObjectStore.getAll().then(data => {
 | 
					 | 
				
			||||||
                console.log('从数据库读取音乐文件', data)
 | 
					 | 
				
			||||||
                const ol = document.createElement('ol')
 | 
					 | 
				
			||||||
                data.forEach(item => {
 | 
					 | 
				
			||||||
                    const li = document.createElement('li')
 | 
					 | 
				
			||||||
                    li.innerText = `${item.name} - ${item.size} - ${item.type} - ${item.id}`
 | 
					 | 
				
			||||||
                    const start = document.createElement('button')
 | 
					 | 
				
			||||||
                    start.innerText = '播放'
 | 
					 | 
				
			||||||
                    start.onclick = async () => {
 | 
					 | 
				
			||||||
                        console.log('播放音乐', item)
 | 
					 | 
				
			||||||
                        // 传输音乐文件
 | 
					 | 
				
			||||||
                        const arrayBuffer = item.arrayBuffer
 | 
					 | 
				
			||||||
                        const audioContext = new AudioContext()
 | 
					 | 
				
			||||||
                        audioContext.decodeAudioData(arrayBuffer, async audioBuffer => {
 | 
					 | 
				
			||||||
                            // 将音乐流添加到 RTCPeerConnection
 | 
					 | 
				
			||||||
                            const mediaStreamDestination = audioContext.createMediaStreamDestination()
 | 
					 | 
				
			||||||
                            mediaStreamDestination.stream.getAudioTracks().forEach(function (track) {
 | 
					 | 
				
			||||||
                                pc.addTrack(track, mediaStreamDestination.stream)
 | 
					 | 
				
			||||||
                            })
 | 
					 | 
				
			||||||
                            // 播放音乐(远程)
 | 
					 | 
				
			||||||
                            const audioSource = audioContext.createBufferSource()
 | 
					 | 
				
			||||||
                            audioSource.buffer = audioBuffer
 | 
					 | 
				
			||||||
                            audioSource.connect(mediaStreamDestination)
 | 
					 | 
				
			||||||
                            audioSource.start()
 | 
					 | 
				
			||||||
                            // 播放音乐(本地)
 | 
					 | 
				
			||||||
                            const audioPlayer = new Audio()
 | 
					 | 
				
			||||||
                            audioPlayer.srcObject = mediaStreamDestination.stream
 | 
					 | 
				
			||||||
                            audioPlayer.play()
 | 
					 | 
				
			||||||
                            // 创建SDP offer并将其设置为本地描述, 发送给远程端
 | 
					 | 
				
			||||||
                            const id = clients[0].id
 | 
					 | 
				
			||||||
                            await pc.setLocalDescription(await pc.createOffer())     // 设置本地描述为 offer
 | 
					 | 
				
			||||||
                            ws.send(JSON.stringify({ id, offer: pc.localDescription }))  // 发送给远程终端 offer
 | 
					 | 
				
			||||||
                        })
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
                    li.appendChild(start)
 | 
					        //music()
 | 
				
			||||||
                    const remove = document.createElement('button')
 | 
					 | 
				
			||||||
                    remove.innerText = '移除'
 | 
					 | 
				
			||||||
                    remove.onclick = async () => {
 | 
					 | 
				
			||||||
                        await musicObjectStore.delete(item.id)
 | 
					 | 
				
			||||||
                        li.remove()
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    li.appendChild(remove)
 | 
					 | 
				
			||||||
                    ol.appendChild(li)
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
                document.body.appendChild(ol)
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        music()
 | 
					 | 
				
			||||||
    </script>
 | 
					    </script>
 | 
				
			||||||
    <!--script type="module">
 | 
					    <!--script type="module">
 | 
				
			||||||
        // 创建 RTCPeerConnection
 | 
					        // 创建 RTCPeerConnection
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,8 +8,7 @@ export default class MusicList {
 | 
				
			|||||||
        this.store = new IndexedDB('musicDatabase', 1, 'musicObjectStore')
 | 
					        this.store = new IndexedDB('musicDatabase', 1, 'musicObjectStore')
 | 
				
			||||||
        this.store.open().then(() => {
 | 
					        this.store.open().then(() => {
 | 
				
			||||||
            this.store.getAll().then((data) => {
 | 
					            this.store.getAll().then((data) => {
 | 
				
			||||||
                console.log(data)
 | 
					                data.forEach(item => this.__add(item))
 | 
				
			||||||
                data.forEach(item => this.add(item))
 | 
					 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        document.body.appendChild(this.ul)
 | 
					        document.body.appendChild(this.ul)
 | 
				
			||||||
@@ -29,7 +28,6 @@ export default class MusicList {
 | 
				
			|||||||
        input.multiple = true
 | 
					        input.multiple = true
 | 
				
			||||||
        input.accept = 'audio/*'
 | 
					        input.accept = 'audio/*'
 | 
				
			||||||
        input.onchange = event => {
 | 
					        input.onchange = event => {
 | 
				
			||||||
            console.log('event.target.files', event.target.files)
 | 
					 | 
				
			||||||
            for (const file of event.target.files) {
 | 
					            for (const file of event.target.files) {
 | 
				
			||||||
                const id = 'music' + Date.now()
 | 
					                const id = 'music' + Date.now()
 | 
				
			||||||
                const { name, size, type } = file
 | 
					                const { name, size, type } = file
 | 
				
			||||||
@@ -43,8 +41,8 @@ export default class MusicList {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        document.body.appendChild(input)
 | 
					        document.body.appendChild(input)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    add(item) {
 | 
					    // 仅添加UI
 | 
				
			||||||
        this.store.add(item)
 | 
					    __add(item) {
 | 
				
			||||||
        const li = ListItem({
 | 
					        const li = ListItem({
 | 
				
			||||||
            id: item.id,
 | 
					            id: item.id,
 | 
				
			||||||
            innerText: `${item.name} - ${item.size} - ${item.type} - ${item.id}`,
 | 
					            innerText: `${item.name} - ${item.size} - ${item.type} - ${item.id}`,
 | 
				
			||||||
@@ -78,6 +76,11 @@ export default class MusicList {
 | 
				
			|||||||
        })
 | 
					        })
 | 
				
			||||||
        this.ul.appendChild(li)
 | 
					        this.ul.appendChild(li)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    // 添加数据并添加UI
 | 
				
			||||||
 | 
					    add(item) {
 | 
				
			||||||
 | 
					        this.store.add(item)
 | 
				
			||||||
 | 
					        this.__add(item)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    delete(item) {
 | 
					    delete(item) {
 | 
				
			||||||
        this.store.delete(item.id)
 | 
					        this.store.delete(item.id)
 | 
				
			||||||
        this.ul.removeChild(this.ul.querySelector(`#${item.id}`))
 | 
					        this.ul.removeChild(this.ul.querySelector(`#${item.id}`))
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user