在项目中使用到了自定义滚动条的功能,简单记录下心得,跟网易云音乐自定义播放器进度的拖动原理类似,只是自己在项目中并没有使用Rxjs的方式去实现。
自定义滚动条的核心逻辑是用dom模拟滚动条的样式,用鼠标事件来使滚动条跟着鼠标移动而移动,过程中也涉及到滚动条距离页面边距的计算。
首先,定义滚动条组件ScrollBarComponent,核心代码如下:
1、先定义一些组件相关的属性,具体看代码注释:
canMove = false; // 滚动条是否可以移动
disLeft: number; // 鼠标按下时距离滚动条最左边的距离
moveLeft: number; // 滚动条移动的时候距离页面左边的距离
mostLeft = window.innerWidth * 2 / 3; // 这里简单处理设置滚动条长度为1/3页面宽度,滚动条最右侧时页距离最左边为2/3页面宽度
ViewChild('bar') bar ElementRef; // 获取定义的滚动条dom对象
@Output() barMoveEvent = new EventEmitter<number>(); 鼠标移动抛出事件
constructor(private renderer: Renderer2) {
}
2、滚动条对应的鼠标事件,在移动事件对应的方法中设置滚动条移动,并在结尾抛出滚动条的移动的事件:
// 鼠标按下事件
barMouseDown(e) {
this.canMove = true; // 设置可以移动
this.disLeft = e.pageX - this.bar.nativeElement.offsetLeft; // 设置disLeft
}
// 鼠标移动事件
barMouseMove(e) {
if (this.isMove) {
this.moveLeft = e.pageX - this.disLeft;
if (this.moveLeft <= 0) { // 当移动到最左侧时
this.moveLeft = 0;
this.renderer.setStyle(this.bar.nativeElement, 'left', '0px); // 设置滚动条距离页面左侧距离,滚动条的样式的position属性已设置为relative
} else if (this.moveLeft >= this.mostleft) { // 移动到最右侧时
this.moveLeft = this.mostleft;
this.renderer.setStyle(this.bar.nativeElement, 'left', this.mostleft + 'px);
} else {
this.renderer.setStyle(this.bar.nativeElement, 'left', this.moveLeft + 'px);
}
this.barMoveEvent.emit(this.moveLeft / this.mostleft); // 抛出事件
}
}
// 鼠标松开事件
barMouseUp(e) {
this.canMove = false;
}
其次,就是滚动条组件在父组件中的引用,代码如下:
// 父组件dom内容
<div #container></div>
<app-scroll-bar (barMoveEvent)="barMoveEvent($event)"></app-scroll-bar>
ViewChild('container') container: ElementRef;
constructor(private renderer: Renderer2) {
}
// barMoveEvent对应的事件,这里主要处理父组件需要移动内容根据滚动条移动的百分比计算移动距离
barMoveEvent(e) {
// 此处计算父组件需要滚动div移动的距离为:div的宽度 - 页面的宽度 * 滚动条移动百分比;
const left = container.nativeElement.style.width - window.innerWidth
this.renderer.setStyle(this.container.nativeElement, 'marginLeft', -left * e + 'px');
}
这里基本实现了一个简单的滚动条的核心逻辑,在工作中还实现了一个仿华为云流水线的滚动条,但核心的滚动逻辑跟这个例子类似,也是在此基础上扩展的,下边是实现的效果。
在工作中实现的滚动条方法都是基于传统的方法去写的,这里的逻辑有也有一个关键的地方有问题,导致滚动条拖动很不好用。最后实现的流水线滚动条主要是点击阶段移动为主,影响不是很大,但在学习网易云音乐的项目中,播放器的播放位置移动功能基本是基于Rxjs去实现的,这个还是很值得去对比学习的,后边也将工作中对应的传统实现方式转化为Rxjs方式去实现。之后会总结一个简单的Rxjs实现的滚动条逻辑。