import { defineComponent, ref, reactive, onMounted } from 'vue' import './index.scss' export default defineComponent({ name: 'Music', setup(props:Props, context) { const musicConfig:State = reactive({ src: '/src/assets/tokyo.mp3' }) const isPlay:Ref<boolean> = ref(true) const audioRef:Ref<any> = ref(null) const canvasRef:Ref<any> = ref(null) class Audio { constructor(audio,fftSize) { this.audioCtx = new AudioContext() this.analyser = this.audioCtx.createAnalyser() this.audio = audio this.audio.crossOrigin = 'anonymous' this.audioSrc = this.audioCtx.createMediaElementSource(this.audio) this.analyser.fftSize = fftSize this.audioSrc.connect(this.analyser) this.analyser.connect(this.audioCtx.destination) this.freqArr = new Uint8Array(this.analyser.frequencyBinCount) } } class Canvas { constructor(canvas,audio,options={}) { this.canvas = canvas this.analyser = audio.analyser this.freqArr = audio.freqArr this.ctx = canvas.getContext('2d') //方块的宽度 this.meterWidth = options.meterWidth || 5 //方块的间距 this.gap = options.gap || 2 //方块最小高度 this.minHeight = options.minHeight || 2 this.cwidth = this.canvas.width this.cheight = this.canvas.height - 2 this.capHeight = 0 //根据宽度和间距计算出可以放多少个方块 this.meterNum = this.cwidth / (this.meterWidth + this.gap) } draw() { let gradient = this.ctx.createLinearGradient(0, 0, 0, 300) gradient.addColorStop(1, '#0f00f0') gradient.addColorStop(0.5, '#ff0ff0') gradient.addColorStop(0, '#f00f00') this.ctx.fillStyle = gradient } render() { const freqArr = new Uint8Array(this.analyser.frequencyBinCount) this.analyser.getByteFrequencyData(freqArr) //从频谱数据中每隔step均匀取出meterNum个数据. const step = Math.round(freqArr.length / this.meterNum) this.ctx.clearRect(0, 0, this.cwidth, this.cheight) for (var i = 0; i < this.meterNum; i++) { const value = freqArr[i * step] //绘制 this.ctx.fillRect(i * (this.meterWidth + this.gap), this.cheight - value + this.capHeight, this.meterWidth, this.cheight || this.minHeight) } requestAnimationFrame(()=>{ this.render() }) } } onMounted(() => { const audio = audioRef.value const canvas = canvasRef.value //音频获取频谱部分 const audioExp = new Audio(audio,512) const canvasExp = new Canvas(canvas,audioExp) canvasExp.draw() canvasExp.render() }) return()=>( <> <canvas id='canvas' ref={canvasRef} width="375" height="300"></canvas> <audio id="audio" ref={audioRef} src={musicConfig.src} autoplay controls loop></audio> </> ) } })