浅析Angular+rxjs怎么实现拖拽功能?

 2737

Angular+rxjs怎么实现拖拽功能?下面本篇文章给大家介绍一下Angular 结合 rxjs 实现拖拽的方法,希望对大家有所帮助!


浅析Angular+rxjs怎么实现拖拽功能?


在之前的文章,我们学习了 Angular 中自定义 Video 操作,没有度过的读者可先了解。

现在有这么一个需求,你会怎么实现呢?

页面中 video 标签,当滚动高度超过其位置之后,将其设置为可在可视区域自由拖拽。

一个不错的 Idea,如果你使用 Angular 的 @angular/cdk/drag-drop 可以轻松实现,但是我们这里不使用工具。

好吧,我们来分析下实现的思路:

页面滚动高度大于视频所在的位置:那么就是视频的 bottom 值相对可视窗口的值要小于0,我们需要设定一个包裹 video 标签的 div 方便计算,其高度是原设定 video 的高度。即元素脱离原文档布局

video 元素可以拖拽,那么其定位需要被改变为 fixed

video 元素在可视区内自由拖动,那么需要对其 topleft 值进行限定

所以我们设定下面的 demo 布局:

  1. <div id="anchor" #anchor>
  2.   <div class="video" id="video" #video>
  3.     <div class="masker"></div>
  4.     <video width="100%" height="100%" controls poster="assets/poster.png">
  5.       <source src="../assets/demo.mp4" type="video/mp4" />
  6.       Your browser does not support.
  7.     </video>
  8.   </div>
  9. </div>

有下面这些预定的样式:

  1. <!-- styles.scss -->
  2. <!-- 这部分需要放在全局样式中 -->
  3. html, body {
  4.   height: 6000px;
  5.   background-color: #fff;
  6. }
  1. <!-- demo.component.scss -->
  2.  
  3. #anchor {
  4.   height: 360px;
  5.   width: 100%;
  6.   background-color: #F0F0F0;
  7. }
  8.  
  9. .video {
  10.   width: 640px;
  11.   height: 360px;
  12.   margin: 0 auto;
  13.   background-color: black;
  14.   <!-- video fixed 布局的样式,默认布局中是没有的 -->
  15.   &.video-fixed { 
  16.     position: fixed;
  17.     top: 10px;
  18.     left: 10px;
  19.     width: 320px;
  20.     height: 150px;
  21.     cursor: all-scroll;
  22.     .masker {
  23.          display: none;
  24.       }
  25.     &:hover {
  26.       .masker {
  27.         display: block;
  28.         position: absolute;
  29.         width: 100%;
  30.         height: 100%;
  31.         background-color: rgba(0, 0, 0, 0.8);
  32.         z-index: 2;
  33.       }
  34.     }
  35.   }
  36. }

这里还引入了 rxjs 来操作。


元素脱离原文档布局

刚才已经分析了 video 元素脱离文档的临界调节了:

video 的外 div,即 #anchor 元素的相对视图的 bottom < 0。所以我们有:

  1. @ViewChild('anchor', { static: false })
  2. public anchor!: ElementRef;
  3. @ViewChild('video', { static: false })
  4. public video!: ElementRef;
  5.  
  6. public scroll!: any;
  7.  
  8. ngAfterViewInit(): void {
  9.   this.scroll = fromEvent(document, 'scroll');
  10.   this.scrollFn();
  11. }
  12.  
  13. // 页面滚动
  14. public scrollFn() {
  15.   this.scroll
  16.     .pipe(
  17.       debounceTime(50), // 防抖
  18.       map(() => this.anchor.nativeElement.getBoundindClientRect().bottom < 0)
  19.     )
  20.     .subscribe((flag: boolean) => {
  21.       // 添加和移除样式
  22.       if(flag) {
  23.         this.video.nativeElement.classList.add('video-fixed');
  24.       } else {
  25.         this.video.nativeElement.classList.remove('video-fixed');
  26.       }
  27.     })
  28. }


浅析Angular+rxjs怎么实现拖拽功能?


先获取 anchor 元素对象,监听页面对象 document 滚动(我们这里加入了防抖函数优化),当 bottom < 0 的时候,将相关的样式 video-fixed 添加给 video 。


元素拖拽

接下来就是实现 video 元素的拖拽。这里我们要监听 video 元素的三个事件,分别是鼠标按下 mousedown,鼠标移动 mousemove 和鼠标抬起 mouseup

  1. // demo.component.ts
  2.  
  3. public mouseDown!: any;
  4. public mouseUp!: any;
  5. public mouseMove!: any;
  6.  
  7. ngAfterViewInit(): void {
  8.   this.mouseDown = fromEvent(this.video.nativeElement, 'mousedown'); // 目标元素按下,即 video
  9.   this.mouseMove = fromEvent(document, 'mousemove'); // 元素在文档内移动
  10.   this.mouseUp = fromEvent(document, 'mouseup'); // 鼠标抬起
  11.    
  12.   this.moveFn()
  13. }
  14.  
  15. // 目标元素移动
  16. public moveFn() {
  17.   this.mouseDown
  18.     .pipe(
  19.       filter(() => this.video.nativeElement.classList.contains('video-fixed')),
  20.       map(() => this.mouseMove.pipe(
  21.         throttleTime(50), // 节流
  22.         takeUntil(this.mouseUp)
  23.       )),
  24.       // concatAll 顺序接受上游抛出的各个数据流作为它的数据, 若前面的数据流不能同步的完结,它会暂存后续数据流,当前数据流完成后它才会订阅后一个暂存的数据流
  25.       concatAll(),
  26.       withLatestFrom(this.mouseDown, (move:any, down:any) => {
  27.         return {
  28.           x: this.validValue(move.clientX - down.offsetX, window.innerWidth - this.video.nativeElement.offsetWidth, 0),
  29.           y: this.validValue(move.clientY - down.offsetY, window.innerHeight - this.video.nativeElement.offsetHeight, 0)
  30.         }
  31.       })
  32.     )
  33.     .subscribe((position: {
  34.       x: number,
  35.       y: number
  36.     }) => {
  37.       this.video.nativeElement.style.top = position.+ 'px';
  38.       this.video.nativeElement.style.left = position.+ 'px';
  39.     })
  40. }
  41.  
  42. // 校验边界值
  43. public validValue = (value:number, max:number, min: number) => {
  44.   return Math.min(Math.max(value, min), max)
  45. }

我们监听目标元素(filter 函数)被鼠标按下,然后鼠标可以在 document 范围内移动(这里用节流函数优化了下),直到监听到鼠标抬起。在移动的过程中,计算目标元素的相对可视窗口左侧和顶部的距离,将值赋予到 left 和 top

这里的计算 move.clientX - down.offsetX, window.innerWidth - this.video.nativeElement.offsetWidth,相关的概念也许你不是很清楚,不过没关系,上面的内容,理解思路即可。相关的知识点会在接下来的文章介绍。

最后,我们得到的效果如下


浅析Angular+rxjs怎么实现拖拽功能?


本文网址:https://www.zztuku.com/detail-11796.html
站长图库 - 浅析Angular+rxjs怎么实现拖拽功能?
申明:本文转载于《掘金社区》,如有侵犯,请 联系我们 删除。

评论(0)条

您还没有登录,请 登录 后发表评论!

提示:请勿发布广告垃圾评论,否则封号处理!!

    编辑推荐