请马上登录,朋友们都在花潮里等着你哦:)
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 马黑黑 于 2022-11-28 18:26 编辑
用普通标签模拟进度条的好处主要在于对浏览器的兼容性好,不会因浏览器的迭代而变成不可用。早些时候,大佬们改造过meter标签令其多姿多彩,遗憾的是,随着浏览器的发展,相关属性已被废弃,被改造的meter现在啥也看不到了。而用像div、span这样的普通标签封装的带滑块的模拟进度条不存在这样的境遇,因为这类标签一般没有实验性的属性,即使有,我们在做进度条时也不会用到。
用普通标签做带滑块的进度条也有局限,我们需要额外编程,以使得进度条拥有接近input[type=range]这样的拖曳滑块功能。此前,我们封装的音频播放器中,有两个用普通标签模拟滑块的插件,它们已经支持拖曳功能,但在交互操作上并不友好,也存在或多或少的bugs,需要改进。
模拟进度条的实现思路是,使用一个span标签及其两给伪元素来完成进度条的模拟,其中,span主标签充当底轨,伪元素一个做进度指示,另一个做滑块。进度指示和滑块通过CSS变量获得状态的实时变更。此前的成品问题在于,进度条轨道偏细的话,拖曳操作容易失效,会拖的话还能将进度指示和滑块拖出轨道以外。这些问题都需要解决,方法简述如下:
设置一个 mDrag 布尔变量,默认值为假,鼠标单击滑块(或轨道)时令其为真,滑块此时处于可拖曳的状态。就是说,要拖曳滑块,先按下鼠标键,且必须是在滑块(或轨道)上按下才准许。
拖曳过程我们用鼠标指针的移动事件来完成。拖曳交互动作,鼠标指针可能会滑出轨道之外,特别是轨道不够粗时常会发生,为此,我们另辟蹊径,onmousemove事件不交给进度条元素,而是其父元素,这样就可以大大扩展鼠标指针的有效拖曳的范围,拖曳功能将和range差不多。
mDrag 变量要适时变回假,否则任何时候鼠标指针滑过进度条轨道都可以拖曳滑块。进度条的载体即父元素范围可能还不能满足需要,为此我们可以扩展到整个文档,将onmouseup事件交由document处理,mDrag变量是自定义的变量,应该不太可能引发冲突。
我们还应考虑轨道上的点击事件,为此,还要给轨道一个 onclick 事件,该事件要做的事情和onmousemove事件相同,但要独立存在。为此,我们需要将滑块和进度指示状态的变更封装成一个函数提供给两个鼠标事件使用。下面是效果和实现代码:
<style>
/* 播放器父元素 */
#mplayer {
margin: 100px auto 0;
position: relative;
width: 200px;
display: grid;
place-items: center;
padding: 20px 0 20px 0;
border: 1px solid tan;
}
/* 进度条主元素 : 模拟进度条底轨 */
#prog {
--xx: 0px;
width: 100%;
height: 4px;
background: lightgray;
position: absolute;
display: grid;
place-items: center;
}
/* 进度条伪元素总设定 */
#prog::before, #prog::after {
position: absolute; content: '';
}
/* 进度条伪元素一 : 模拟进度指示 */
#prog::before {
left: 0;
width: var(--xx);
height: 100%;
border-radius: 6px;
background: teal;
}
/* 进度条伪元素二 : 模拟滑块 */
#prog::after {
left: calc(var(--xx) - 5px);
opacity: .85;
width: 16px;
height: 16px;
background: radial-gradient(transparent 2px, teal 0, black);
border-radius: 50%;
cursor: pointer;
}
</style>
<div id="mplayer">
<span id="prog"></span>
</div>
<script>
let mDrag = false; /* 拖曳标识 */
/* 进度条鼠标按下事件 : 可拖曳 */
prog.onmousedown = (e) => mDrag = true;
/* 文档鼠标松开 : 不可拖曳 */
document.onmouseup = () => mDrag = false;
/* 父元素 mplayer 鼠标移动事件 */
mplayer.onmousemove = (e) => {
if(mDrag) moveBar(e.offsetX);
};
/* 进度条单击事件 */
prog.onclick = (e) => moveBar(e.offsetX);
/* 自定义函数 : 通过CSS变量 --xx 处理进度条状态 */
let moveBar = (xx) => {
if(xx < 0) xx = 0;
if(xx > prog.offsetWidth - 5) xx = prog.offsetWidth - 5;
prog.style.setProperty('--xx', xx + 'px');
}
</script>
|