vue 悬浮框 可拖动

效果图:

首先是样式布局:

 <div class="ys-float-btn" :style="{'width':itemWidth+'px','height':itemHeight+'px','left':left+'px','top':top+'px'}"
           ref="div"
           @click ="onBtnClicked">
        <slot name="icon"></slot>
        <image class="su_img" src="../../../static/clouddisk/icon_qiye.svg"></image>
      </div>

第二步首次进入页面时,按钮应该处于一个初始位置。我们在created钩子中进行初始化。

created(){
      this.left = document.documentElement.clientWidth - 50;
      this.top = document.documentElement.clientHeight*0.8;
    },

第三步,在写一个监听事件

 mounted(){
      window.addEventListener('scroll', this.handleScrollStart);
      this.$nextTick(()=>{
        const div = this.$refs.div;
        div.addEventListener("touchstart",()=>{
          div.style.transition = 'none';
        });
        div.addEventListener("touchmove",(e)=>{
          if (e.targetTouches.length === 1) {
            let touch = event.targetTouches[0];
            this.left = touch.clientX - this.itemWidth/2;
            this.top = touch.clientY - this.itemHeight/2;
          }
        });
        div.addEventListener("touchend",()=>{
          div.style.transition = 'all 0.3s';
           if(this.left>this.clientWidth/2){
             this.left = this.clientWidth - this.itemWidth - this.gapWidth;
           }else{
             this.left = this.gapWidth;
           }
        });

      });
    },

第四步,需要在popos里面定义初始值:

props:{
      itemWidth:{
        type:Number,
        default:60
      },
      itemHeight:{
        type:Number,
        default:60
      },
      gapWidth:{
        type:Number,
        default:10
      },
    
      coefficientHeight:{
        type:Number,
        default:0.8
      }
    },

第五步在对methods进行处理:

    methods:{
      onBtnClicked(){
        this.$emit("onFloatBtnClicked");
      },
  
    },

第六步在将created里面拖动的left和top进行处理,完整代码是这样子的:

 created(){
      this.clientWidth = document.documentElement.clientWidth;
      this.clientHeight = document.documentElement.clientHeight;
      this.left = this.clientWidth - this.itemWidth - this.gapWidth;
      this.top = this.clientHeight*this.coefficientHeight;
    },

最后补充一点,我这边因为需要,我将拖动的上下距离在mounted里面做了判断,让他拖动的时候不会超出我的头部的高度和底部的高度

mounted(){
this.$nextTick(()=>{
const div = this.$refs.div;
div.addEventListener("touchstart",(e)=>{
e.stopPropagation();
div.style.transition = 'none';
});
div.addEventListener("touchmove",(e)=>{
e.stopPropagation();
if (e.targetTouches.length === 1) {
let touch = event.targetTouches[0];
this.left = touch.clientX - this.itemWidth/2;
this.top = touch.clientY - this.itemHeight/2;
}
},
false
);
div.addEventListener("touchend",(e)=>{
e.stopPropagation();
div.style.transition = 'all 0.3s';
if(this.left>this.clientWidth/2){
this.left = this.clientWidth - this.itemWidth - this.gapWidth;
}else{
this.left = this.gapWidth;
}
if(this.top<=36)
{
this.top=36+this.gapWidth
}
else{
let bottom=this.clientHeight-50-this.itemHeight-this.gapWidth
console.log(bottom,this.top)
if(this.top>=bottom)
{
this.top=bottom
}

}
});
});
},

如果你们没有头部和底部高度可以随意滚动就直接这样子写就行:

 mounted(){
      window.addEventListener('scroll', this.handleScrollStart);
      this.$nextTick(()=>{
        const div = this.$refs.div;
        div.addEventListener("touchstart",()=>{
          div.style.transition = 'none';
        });
        div.addEventListener("touchmove",(e)=>{
          if (e.targetTouches.length === 1) {
            let touch = event.targetTouches[0];
            this.left = touch.clientX - this.itemWidth/2;
            this.top = touch.clientY - this.itemHeight/2;
          }
        });
        div.addEventListener("touchend",()=>{
          div.style.transition = 'all 0.3s';
           if(this.left>this.clientWidth/2){
             this.left = this.clientWidth - this.itemWidth - this.gapWidth;
           }else{
             this.left = this.gapWidth;
           }
        });

      });
    },

最后我直接就完整代码:

<template>
     <div class="ys-float-btn" :style="{'width':itemWidth+'px','height':itemHeight+'px','left':left+'px','top':top+'px'}"
           ref="div"
           @click ="onBtnClicked">
        <slot name="icon"></slot>
        <image class="su_img" src="../../../static/clouddisk/icon_qiye.svg"></image>
      </div>
</template>


<script>
  export default {
    name: "FloatImgBtn",
    props:{
      itemWidth:{
        type:Number,
        default:60
      },
      itemHeight:{
        type:Number,
        default:60
      },
      gapWidth:{
        type:Number,
        default:10
      },
    
      coefficientHeight:{
        type:Number,
        default:0.8
      }
    },
    created(){
      this.clientWidth = document.documentElement.clientWidth;
      this.clientHeight = document.documentElement.clientHeight;
      this.left = this.clientWidth - this.itemWidth - this.gapWidth;
      this.top = this.clientHeight*this.coefficientHeight;
    },
    mounted(){
      this.$nextTick(()=>{
        const div = this.$refs.div;
        div.addEventListener("touchstart",(e)=>{
                e.stopPropagation();
          div.style.transition = 'none';
        });
        div.addEventListener("touchmove",(e)=>{
                e.stopPropagation();
          if (e.targetTouches.length === 1) {
            let touch = event.targetTouches[0];
            this.left = touch.clientX - this.itemWidth/2;
            this.top = touch.clientY - this.itemHeight/2;
          }
        },
        false
        );
        div.addEventListener("touchend",(e)=>{
            e.stopPropagation();
          div.style.transition = 'all 0.3s';
           if(this.left>this.clientWidth/2){
             this.left = this.clientWidth - this.itemWidth - this.gapWidth;
           }else{
             this.left = this.gapWidth;
           }
           if(this.top<=36)
           {
               this.top=36+this.gapWidth
           }
           else{
               let bottom=this.clientHeight-50-this.itemHeight-this.gapWidth
               console.log(bottom,this.top)
               if(this.top>=bottom)
               {
                   this.top=bottom
               }

           }
        });
      });
    },

    methods:{
      onBtnClicked(){
        this.$emit("onFloatBtnClicked");
      },
  
    },
    data(){
      return{
        timer:null,
        currentTop:0,
        clientWidth:0,
        clientHeight:0,
        left:0,
        top:0,
      }
    }
  }
</script>



<style lang="scss" scoped>
    .ys-float-btn{
        background:rgba(56,181,77,1);
        box-shadow:0 2px 10px 0 rgba(0,0,0,0.1);
        border-radius:50%;
        color: #666666;
        z-index: 20;
        transition: all 0.3s;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        position: fixed;
        bottom: 20vw;
    
        img{
           50%;
          height: 50%;
          object-fit: contain;
          margin-bottom: 3px;
        }
      }
.su_img{
             40px;
            height: 40px;
            margin: 8px 0 0 0;
    }

</style>
原文地址:https://www.cnblogs.com/lovebear123/p/12836931.html