微信小程序音乐小程序项目(小程序定制版【小程序】实现一个定制的音乐播放器)

发布日期:2023-10-27 22:41:57 浏览次数:247

应用地址:https://spacexcode.com/player

介绍

这是为自己制作的一个在线 Web 版的音乐播放器。众所周知,现在市面上的所有的音乐平台都是会员制。而免费的资源却分散在网络上的各个角落,为此,我收集了自己 喜欢的音乐,放到自己的服务器上,并制作了这样一个专属歌单的简单的音乐播放器。

实现讲解

该播放器虽然简单,但也是五脏俱全,该有的功能一个都没少。比如常见的音乐播放器,我们能想到的功能有:

暂停/开始播放按键调节播放进度的进度条调节声音大小的按键切换下一首/上一首按键查看歌单的界面

界面

如果不考虑界面, Web 端的音频播放有现成的标签 audio 支持

<audio controls src="https://spacexcode.oss-cn-hangzhou.aliyuncs.com/mp3/那女孩对我说.mp3"

 />

这是浏览器渲染的默认样式,各个浏览器可能会有差异。我们要实现一个音乐播放器,当然要所有端的样式统一。这个时候,我们就移除 controls 属性,让 实际的播放组件在页面上什么都不显示。然后我们自己去实现上面的所有控件。

由于这个站点引入的是 Material UI,为了统一视觉,就使用里面现成的组件去实现。

function player () 

{

  const [paused, setPaused] = React.useState(true

);

  return

 (

    <Box sx={{ width: 100%, overflow: hidden }}>      <div style={{        padding: 16

,

        borderRadius: 16

,

        width: 343

,

        maxWidth: 100

%,

        margin: auto

,

        position: relative

,

        zIndex: 1

,

        backgroundColor: rgba(255,255,255,0.4

),

        backdropFilter: blur(40px

)

      }}>
        <Box sx={{ display: flexalignItems: centerposition: relative }}>          <div style={{            width: 100

,

            height: 100

,

            objectFit: cover

,

            overflow: hidden

,

            flexShrink: 0

,

            borderRadius: 8

,

            backgroundColor: rgba(0,0,0,0.08

),

            & >

 img: {

              width: 100%,

            }

          }}>

            <img alt=那女孩对我说 src=https://spacexcode.oss-cn-hangzhou.aliyuncs.com/1697270523238-8b4b11a5-b5a3-4ac3-b6bd-1e264f526c76.png />          </div>          <Box sx={{ position: absolutetop: 0right: 0 }}>            <IconButton aria-label="music queue">              <QueueMusicIcon fontSize="small" htmlColor=rgba(0,0,0,0.4) />            </IconButton>          </Box>          <Box sx={{ ml: 1.5minWidth: 0 }}>            <Typography variant="caption" color="text.secondary" fontWeight={500}> 林俊杰 </Typography>            <Typography noWrap> <b>那女孩对我说</b> </Typography>            <Typography noWrap letterSpacing={-0.25}> 心很空 天很大 云很重 我很孤单 </Typography>          </Box>        </Box>        <Slider aria-label="time-indicator" size="small" value={30} min={0} step={1} max={405}          sx={{            color: rgba(0,0,0,0.87

),

            height: 4

,

            & .MuiSlider-thumb:

 {

              width: 8

,

              height: 8

,

              transition: 0.3s cubic-bezier(.47,1.64,.41,.8

),

              &:before:

 {

                boxShadow: 0 2px 12px 0 rgba(0,0,0,0.4

),

              },

              &:hover, &.Mui-focusVisible:

 {

                boxShadow: `0px 0px 0px 8px

 ${

                  rgb(0 0 0 / 16

%)

                }`,

              },

              &.Mui-active:

 {

                width: 20

,

                height: 20

,

              },

            },

            & .MuiSlider-rail:

 {

              opacity: 0.28

,

            },

          }}

        />
        <Box sx={{ display: flexalignItems: centerjustifyContent: space-betweenmt: -2

 }}

        >
          <div style={{ fontSize: 0.75remopacity: 0.38fontWeight: 500letterSpacing: 0.2 }}>00:30</div>          <div style={{ fontSize: 0.75remopacity: 0.38fontWeight: 500letterSpacing: 0.2 }}>-04:00</div>        </Box>        <Box sx={{ display: flexalignItems: centerjustifyContent: centermt: -1

 }}

        >
          <audio src=https://spacexcode.oss-cn-hangzhou.aliyuncs.com/mp3/那女孩对我说.mp3 />          <IconButton aria-label="previous song">            <FastRewindRounded fontSize="large" htmlColor=#000 />          </IconButton>          <IconButton aria-label=pause>            <PauseRounded sx={{ fontSize: 3rem }} htmlColor=#000 />          </IconButton>          <IconButton aria-label="next song">            <FastForwardRounded fontSize="large" htmlColor=#000 />          </IconButton>        </Box>        <Stack spacing={2} direction="row" sx={{ mb: 1px: 1 }} alignItems="center">          <VolumeDownRounded htmlColor=rgba(0,0,0,0.4) />          <Slider aria-label="Volume" value={0.3} min={0} step={0.01} max={1}            sx={{              color: rgba(0,0,0,0.87

),

              & .MuiSlider-track:

 {

                border: none

,

              },

              & .MuiSlider-thumb:

 {

                width: 16

,

                height: 16

,

                backgroundColor: #fff

,

                &:before:

 {

                  boxShadow: 0 4px 8px rgba(0,0,0,0.4

),

                },

                &:hover, &.Mui-focusVisible, &.Mui-active:

 {

                  boxShadow: none

,

                },

              },

            }}

          />
          <VolumeUpRounded htmlColor=rgba(0,0,0,0.4) />        </Stack>      </div>    </Box>

  )

}

至此以上代码,初步实现了基本的播放器界面,然后我们需要对每个功能控件添加事件实现它应该有的功能。

播放按钮

控制播放器的播放,我们可以通过 audio 提供的 play() 和 pause() 接口,首先我们使用 useRef 获取音频组件的实例,然后通过判断 当前的播放状态,调用播放和暂停接口。

function Player () 

{

  const

 audioPlayer = useRef();

  const [paused, setPaused] = useState(true

);

  const onPlayOrPause = () =>

 {

    paused ? audioPlayer.current.play() : audioPlayer.current.pause();

    setPaused(!paused)

  }

}

下面所有使用的变量 audioPlayer 代表获取的 <audio ref="audioPlayer" /> 播放器实例

调节进度

在 Slider 组件上绑定 onChange 事件,此时 Slider 组件中的最大值即为该音频资源的最大时长。回调中拿到设置的进度值后赋值给 currentTime 属性。

const [position, setPosition] = useState(0); // 表示当前的播放进度值const onChangeProgress = (val) =>

 {

  setPosition(val);

  audioPlayer.current.currentTime = val;

}

这个音频的资源时长,可以通过监听资源加载完成事件,通过 duration 属性获取。它单位为**毫秒(ms)**。

audioPlayer.current.addEventListener(loadeddata

, () => {

  setDuration(audioPlayer.current?.duration)

});

调节音量

音量的调节和进度同样使用的是 Slider 组件,不过它的最大值为 1,步长为 0.01。

改变音量时,将获取到的音量值赋给 audioPlayer 实例的 volumn 属性。

const onChangeVolume = (val) =>

 {

  setVolume(val);

  audioPlayer.current.volume = val;

};

切换歌单

切换上一首/下一首,无非就是改变当前播放的音频资源。该音频资源对应到资源列表的索引值,我们通过控制索引值去列表中获取不同的音乐素材。

这里要考虑边界值的情况,当切换的时候碰到最大值和最小值,如果允许循环,那么在索引值等于数组长度时,将它的值重置为 0。

// 上一首const onPreview = () =>

 {

  if (currentIndex > 0

) {

    changeCurrentIndex(currentIndex - 1

); 

  }

}

// 下一首const onNext = () =>

 {

  if (currentIndex < songList.length - 1

) {

    changeCurrentIndex(currentIndex + 1

);

  } else

 {

    changeCurrentIndex(0

);

  }

}

查看歌单

除了所有的功能按钮,右上角还有一个查看歌单的按钮,点击从底部弹出一个 drawer 抽屉组件。里面列出了一个收藏的音乐列表。

function MusicQueue() 

{

  const

 songList = [

    {

      artists林俊杰

,

      name那女孩对我说

,

      avatarhttps://spacexcode.oss-cn-hangzhou.aliyuncs.com/1697270523238-8b4b11a5-b5a3-4ac3-b6bd-1e264f526c76.png

,

      linkhttps://spacexcode.oss-cn-hangzhou.aliyuncs.com/mp3/那女孩对我说.mp3

,

      lyric心很空 天很大 云很重 我很孤单

    },

    {

      artists张靓颖

,

      name终于等到你

,

      avatarhttps://spacexcode.oss-cn-hangzhou.aliyuncs.com/1697503257045-7a262b7d-0df0-4005-a69c-2a645ac24c27.png

,

      linkhttps://spacexcode.oss-cn-hangzhou.aliyuncs.com/mp3/终于等到你-张靓颖.mp3

,

      lyric到了某个年纪你就会知道 一个人的日子真的难熬

    },

    {

      artists张靓颖

,

      name饿狼传说

,

      avatarhttps://spacexcode.oss-cn-hangzhou.aliyuncs.com/1697503257045-7a262b7d-0df0-4005-a69c-2a645ac24c27.png

,

      linkhttps://spacexcode.oss-cn-hangzhou.aliyuncs.com/mp3/饿狼传说-张靓颖.mp3

,

      lyric她熄掉晚灯 幽幽掩两肩 交织了火花 拘禁在沉淀

    }

  ];

  return

 (

    <Box sx={{ width: auto }} role="presentation">      <List>

        {songList.map((item, index) => (

          <ListItem            key={index}            disablePadding>            <ListItemButton>              <ListItemIcon>                <Avatar alt={item.artists} src={item.avatar} />              </ListItemIcon>              <ListItemText secondary={                <React.Fragment>                  <Typography sx={{ display: inline }} component="span" variant="body1" color="text.primary">

                    {item.name}

                  </Typography>

                  { --  + item.artists}

                </React.Fragment>

              } />

            </ListItemButton>          </ListItem>

        ))}

      </List>    </Box>

  );

}

至此我们已经实现了界面上所有的控制按钮的功能。最后需要完善下一些边界和初始情况的处理。

当音频在播放的时候,进度条需要随着当前播放时间变化而变化。这里采用定时器,每隔一秒获取播放资源的当前播放时间点,同步给 Slider 组件的 value 属性来定位。

const [timer, setTimer] = useState(null

);

audioPlayer.current.addEventListener(play

, () => {

  if

 (timer) {

    clearInterval(timer);

  }

  setTimer(setInterval(() =>

 {

    setPosition(audioPlayer.current?.currentTime)

  }, 1000

));

});

audioPlayer.current.addEventListener(pause

, () => {

  if

 (timer) {

    clearInterval(timer);

  }

});

还有歌词的显示,下一步计划加上~

总结

实现一个定制的音乐播放器不复杂,控制功能的实现都有现成的接口:

播放 play()暂停 pause()播放进度通过 currentTime 获取音量控制通过 volumn 的值控制音频的自动播放通过 autoplay 属性控制音频播放的时候为静音 muted当前音频资源循环播放通过属性 loop

我们需要考虑的是如何优化界面,毕竟一款颜值高的播放器和动听的音乐才能给我们带来内心的愉悦。

- END -
如果您有什么问题,欢迎咨询技术员 点击QQ咨询