angular+rxjs怎么实现拖拽功能?下面本篇文章给大家介绍一下angular 结合 rxjs 实现拖拽的方法,希望对大家有所帮助!
在之前的文章,我们学习了 angular 中自定义 video 操作,没有度过的读者可先了解。
现在有这么一个需求,你会怎么实现呢?
页面中 video 标签,当滚动高度超过其位置之后,将其设置为可在可视区域自由拖拽。
一个不错的 idea,如果你使用 angular 的 @angular/cdk/drag-drop 可以轻松实现,但是我们这里不使用工具。【相关教程推荐:《angular教程》】
好吧,我们来分析下实现的思路:
页面滚动高度大于视频所在的位置:那么就是视频的 bottom 值相对可视窗口的值要小于0,我们需要设定一个包裹 video 标签的 div 方便计算,其高度是原设定 video 的高度。即元素脱离原文档布局video 元素可以拖拽,那么其定位需要被改变为 fixedvideo 元素在可视区内自由拖动,那么需要对其 top, left 值进行限定所以我们设定下面的 demo 布局:
<div id="anchor" #anchor> <div class="video" id="video" #video> <div class="masker"></div> <video width="100%" height="100%" controls poster="assets/poster.png"> <source src="../assets/demo.mp4" type="video/mp4" /> your browser does not support. </video> </div></div>
有下面这些预定的样式:
<!-- styles.scss --><!-- 这部分需要放在全局样式中 -->html, body { height: 6000px; background-color: #fff;}
<!-- demo.component.scss -->#anchor { height: 360px; width: 100%; background-color: #f0f0f0;}.video { width: 640px; height: 360px; margin: 0 auto; background-color: black; <!-- video fixed 布局的样式,默认布局中是没有的 --> &.video-fixed { position: fixed; top: 10px; left: 10px; width: 320px; height: 150px; cursor: all-scroll; .masker { display: none; } &:hover { .masker { display: block; position: absolute; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.8); z-index: 2; } } }}
这里还引入了 rxjs 来操作。
元素脱离原文档布局
刚才已经分析了 video 元素脱离文档的临界调节了:
video 的外 div,即 #anchor 元素的相对视图的 bottom < 0。所以我们有:
@viewchild('anchor', { static: false })public anchor!: elementref;@viewchild('video', { static: false })public video!: elementref;public scroll!: any;ngafterviewinit(): void { this.scroll = fromevent(document, 'scroll'); this.scrollfn();}// 页面滚动public scrollfn() { this.scroll .pipe( debouncetime(50), // 防抖 map(() => this.anchor.nativeelement.getboundindclientrect().bottom < 0) ) .subscribe((flag: boolean) => { // 添加和移除样式 if(flag) { this.video.nativeelement.classlist.add('video-fixed'); } else { this.video.nativeelement.classlist.remove('video-fixed'); } })}
先获取 anchor 元素对象,监听页面对象 document 滚动(我们这里加入了防抖函数优化),当 bottom < 0 的时候,将相关的样式 video-fixed 添加给 video 。
元素拖拽
接下来就是实现 video 元素的拖拽。这里我们要监听 video 元素的三个事件,分别是鼠标按下 mousedown,鼠标移动 mousemove 和鼠标抬起 mouseup。
// demo.component.tspublic mousedown!: any;public mouseup!: any;public mousemove!: any;ngafterviewinit(): void { this.mousedown = fromevent(this.video.nativeelement, 'mousedown'); // 目标元素按下,即 video this.mousemove = fromevent(document, 'mousemove'); // 元素在文档内移动 this.mouseup = fromevent(document, 'mouseup'); // 鼠标抬起 this.movefn()}// 目标元素移动public movefn() { this.mousedown .pipe( filter(() => this.video.nativeelement.classlist.contains('video-fixed')), map(() => this.mousemove.pipe( throttletime(50), // 节流 takeuntil(this.mouseup) )), // concatall 顺序接受上游抛出的各个数据流作为它的数据, 若前面的数据流不能同步的完结,它会暂存后续数据流,当前数据流完成后它才会订阅后一个暂存的数据流 concatall(), withlatestfrom(this.mousedown, (move:any, down:any) => { return { x: this.validvalue(move.clientx - down.offsetx, window.innerwidth - this.video.nativeelement.offsetwidth, 0), y: this.validvalue(move.clienty - down.offsety, window.innerheight - this.video.nativeelement.offsetheight, 0) } }) ) .subscribe((position: { x: number, y: number }) => { this.video.nativeelement.style.top = position.y + 'px'; this.video.nativeelement.style.left = position.x + 'px'; })}// 校验边界值public validvalue = (value:number, max:number, min: number) => { return math.min(math.max(value, min), max)}
我们监听目标元素(filter 函数)被鼠标按下,然后鼠标可以在 document 范围内移动(这里用节流函数优化了下),直到监听到鼠标抬起。在移动的过程中,计算目标元素的相对可视窗口左侧和顶部的距离,将值赋予到 left 和 top。
这里的计算 move.clientx - down.offsetx, window.innerwidth - this.video.nativeelement.offsetwidth,相关的概念也许你不是很清楚,不过没关系,上面的内容,理解思路即可。相关的知识点会在接下来的文章介绍。
最后,我们得到的效果如下
【完】
更多编程相关知识,请访问:编程视频!!
以上就是浅析angular+rxjs怎么实现拖拽功能?的详细内容。