可拖拽悬浮框菜单

本文介绍了使用 Vue.js 实现一个悬浮导航图标,当鼠标悬停和拖动时,二级菜单会出现并随着拖动角度旋转。通过监听 mouse 和 touch 事件,实现了移动设备上的拖拽功能,并确保元素在窗口内正确约束。同时,详细展示了 Vue 单文件组件的 HTML、JS 和 CSS 代码实现。
摘要由CSDN通过智能技术生成

浮动效果:图片依次为未触发,触发,拖拽

 

 

 

 

view模块

<template>
    <div>
        <div id="moveDiv"  @mouseleave="yichu()" @mousedown="down()" @mousemove="move" @mouseup="end" @touchend="end" class="NMH-g-plugin NMH-g-navicon" :class='[jinruD==1?"Jnmh-open":""]'>
			<button class="Jnmh-btnlogo" @mouseover="jinru()" ></button>
			<ins class="Jnmh-btnlogohover"></ins>
			<ul class="Jnmh-m-submenu">
				<li class="Jnmh-subli" v-for="(item,index) in tabList" :key="index" :style="{transform: 'rotate('+item.jd+'deg)'}">
					<dl class="Jnmh-subdl">
						<dt class="NMH-subdt">{{item.name}}</dt>
						<dd class="NMH-subdd"></dd>
					</dl>
				</li>
			</ul>
		</div>
    </div>
</template>

js动态监听处理数据变化

<script>
export default {
    data() {
        return {
            flags: false,
            positionTemp: { x: 0, y: 0 },   // 记录手指点击的位置
            nx: '',
			ny: '',
			dx: '', 
			dy: '', 
			xPum: '', 
			yPum: '',
			tabList:[{name:"电商平台"},{name:"电商平台2"},{name:"电商平台2"},{name:"电商平台2"},{name:"电商平台3"},{name:"电商平台4"}],
			jinruD:0
        }
    },
    methods: {
		jinru(){
			this.jinruD=1
			this.jiaodu()
		},
		yichu(){
			this.jinruD=0
			this.tabList.map((item)=>{
				item.jd=0
			})
		},
		jiaodu(){
			var lilen = this.tabList.length;
			var avgDeg =  180/(lilen-1);// 平均角度
			var initDeg = 0;// 起始方向角度
			let windowWidth = document.documentElement.clientWidth
			var WidthR = windowWidth/2
			if(this.xPum < WidthR){
				// 如果悬浮球被拖拽到左边,则二级菜单则显示右侧
				initDeg =  180;
			}else{
				// 默认悬浮球在右边,二级菜单显示在左侧
				initDeg =  0;
			}
			for(var i=0,j=lilen-1; i<lilen; i++,j--) {
				var d =  initDeg - (i*avgDeg);
				var z = initDeg?j:i;
				this.tabList[i].jd = d
			}
		},
        // 实现移动端拖拽
        down(){
            if (this.fixed) {
                return
            }
            this.flags = true;
            var touch;
            // 该if判断是用touch还是mouse来移动
            if (event.touches) {
                touch = event.touches[0];
            } else {
                touch = event;
            }
            this.positionTemp.x = touch.clientX;   // 手指点击后的位置
            this.positionTemp.y = touch.clientY;
            
            this.dx = moveDiv.offsetLeft;    // 移动的div元素的位置
            this.dy = moveDiv.offsetTop;
            // console.log("moveDiv.offsetLeft", moveDiv.offsetLeft)
            // console.log("touch.clientX", touch.clientX)
        },
        move(){
            if(this.flags) {
                var touch ;
                if(event.touches){
                    touch = event.touches[0];
                }else {
                    touch = event;
                }
                this.nx = touch.clientX - this.positionTemp.x;   // 手指移动的变化量
                this.ny = touch.clientY - this.positionTemp.y;
                
                this.xPum = this.dx + this.nx;   // 移动后,div元素的位置
                this.yPum = this.dy + this.ny;
                
                let windowWidth = document.documentElement.clientWidth
                let windowHeight = document.documentElement.clientHeight
                // console.log("window.clientWidth", windowWidth)
                // console.log(this.xPum)
                // console.log(" moveDiv.clientWidth",  moveDiv.clientWidth)
                if (this.xPum > 0 && (this.xPum + moveDiv.clientWidth < windowWidth)) {
                	// movediv的左右边,未出界
                    moveDiv.style.left = this.xPum + "px";
                } else if (this.xPum <= 0) {
                    // 左边出界,则左边缘贴边
                    moveDiv.style.left = 0 + "px";
                } else if (this.xPum + moveDiv.clientWidth >= windowWidth) {
                    // 右边缘出界
                    moveDiv.style.left = (windowWidth - moveDiv.clientWidth) + "px";
                    // console.log("dx", windowWidth - moveDiv.clientWidth)
                }
                // 上下未出界
                if (this.yPum > 0 && (this.yPum + moveDiv.clientHeight < windowHeight)) {
                    moveDiv.style.top = this.yPum +"px";
                } else if (this.yPum <= 0) {
                    // 上边缘出界
                    moveDiv.style.top = 0 + "px"
                } else if (this.yPum + moveDiv.clientHeight >= windowHeight) {
                    // 下边缘
                    // console.log("windowHeight:", windowHeight)
                    moveDiv.style.top = windowHeight - moveDiv.clientHeight + "px"
                }
				
				this.jiaodu()
                document.addEventListener("touchmove", this.preventDefault, { passive: false })
                document.addEventListener("mousemove", this.preventDefault, { passive: false })
            }
        },
        //鼠标释放时候的函数,鼠标释放,移除之前添加的侦听事件,将passive设置为true,不然背景会滑动不了
        end(){
            this.flags = false
            // 注意事项,在添加和删除监听事件时,其function必须是同名的函数,不能为匿名函数。
            document.removeEventListener('touchmove',this.preventDefault, false)
            document.removeEventListener('mousemove',this.preventDefault, false)
            // 下面两句是保证在移除监听事件后,除了悬浮球的部分还能够滑动,如果不添加,则无法滑动
            document.addEventListener("touchmove", function(e) {
                window.event.returnValue = true
            })
            document.addEventListener("mousemove", function(e) {
                window.event.returnValue = true
            })
        },
        preventDefault(e) {
            e.preventDefault()
        }
    },
    mounted() {
		this.xPum = document.documentElement.clientWidth
	}
}
</script>

css样式

<style  scoped>
html,body{
	width: 100%;
	height: 100%;
	margin: 0;padding: 0;
}
/*导航图标*/
.NMH-g-navicon{
	position: fixed;
	top: 40%;
	right: 020px;
	width: 100px;
	height: 100px;
}
.NMH-g-navicon.Jnmh-onleft{
	right: auto;
	left: 020px;
}
/*导航图标logo按钮*/
.NMH-g-navicon .Jnmh-btnlogo{
	position: absolute;
	display: block;
	width: 100px;
	height: 100px;
	top: 50%;
	right: 0;
	margin-top: -50px;
	border: 0;
	background: url(../assets/logo.png) no-repeat center center;
    background-size: 95% 95%;
    border: 1px solid rgba(0, 0, 0, 0.1);
    box-shadow: rgba(0, 0, 0, 0.12) 0px 6px 10px 0px;
	outline: none;
	border-radius: 50%;
	z-index: 1;
}
.NMH-g-navicon .Jnmh-btnlogohover{
	position: absolute;
	display: block;
	width: 100px;
	height: 100px;
	top: 50%;
	right: 0;
	margin: 0;padding: 0;
	margin-top: -50px;
	border: 0;
	overflow: hidden;
	/*background-color: red;*/
}

/*导航图标logo按钮-鼠标经过*/
.NMH-g-navicon.Jnmh-open .Jnmh-btnlogohover{
	margin-top: -150px;	
	width: 200px;
	height: 300px;
	border-radius: 150px 0 0 150px;
}
.NMH-g-navicon.Jnmh-onleft .Jnmh-btnlogohover{
	left: 0;
	right: auto;
	border-radius: 0 150px 150px 0;
}
/*导航图标菜单子容器*/
.NMH-g-navicon .Jnmh-m-submenu{
	position: absolute;
	background-color: transparent;
	list-style: none;
	top: -020px;
	bottom: -020px;
	left: -020px;
	right: -020px;
	margin: 0;
	padding: 0;
}

.NMH-g-navicon .Jnmh-m-submenu .Jnmh-subli{
	position: absolute;
	width: 100%;height: 100%;
	transform: rotate(0deg);
    -webkit-transform: rotate(0deg);
    transition: all 0.8s ease-in-out;
}

.Jnmh-m-submenu .Jnmh-subdl{
	position: absolute;
    left: 50%;
    bottom: 100%;
    width: 0;
    height: 0;
    line-height: 1px;
    margin-left: 0;
    background: #fff;
    border-radius: 50%;
    text-align: center;
    font-size: 1px;
    overflow: hidden;
    cursor: pointer;
    box-shadow: none;
    transition: all 0.8s ease-in-out, color 0.1s, background 0.1s;
}
/*导航图标-展开菜单时*/
.NMH-g-navicon.Jnmh-open .Jnmh-m-submenu .Jnmh-subdl{
	width: 80px;
    height: 80px;
    line-height: 80px;
    margin-left: -40px;
    box-shadow: 0 3px 3px rgba(0, 0, 0, 0.1);
    font-size: 14px;
}
/*导航图标-三级菜单容器*/
.NMH-g-navicon.Jnmh-open .Jnmh-m-submenu .Jnmh-subdd{
	position: absolute;
	line-height: normal;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值