vue?懸浮窗且?guī)ё詣游焦δ軐?shí)現(xiàn)demo
封裝的組件代碼
之前寫過懸浮窗的效果,這次做了個總結(jié),網(wǎng)頁端和移動端都可以用兼容,封裝的組件代碼,可以引到頁面直接使用
代碼
做了簡單的注釋 大家自行了解
HTML
<template>
<div
ref="floatDrag"
class="float-position"
:style="{ left: left + 'px', top: top + 'px', zIndex: zIndex }"
@touchmove.prevent
@mousemove.prevent
@mousedown="mouseDown"
@mouseup="mouseUp"
>
<div id="side-windows">
<div class="shrink">
<div class="problem-feedback" @click.stop="showDialog()">
<img :src="feedback" alt="" />
<p>問題<br />反饋</p>
</div>
</div>
</div>
</div>
</template>JS
<script>
export default {
name: "DragBall",
props: {
distanceRight: { // 初始化定位
type: Number,
default: 0
},
distanceBottom: { // 初始化定位
type: Number,
default: 100
},
isScrollHidden: { //滾動是否 隱藏
type: Boolean,
default: false
},
isCanDraggable: { //是否允許拖拽
type: Boolean,
default: true
},
zIndex: { // 初始化層級
type: Number,
default: 50
},
value: {
type: String,
default: "懸?。?
}
},
//data 域
data() {
return {
clientWidth: null,
clientHeight: null,
left: 0,
top: 0,
timer: null,
currentTop: 0,
mousedownX: 0,
mousedownY: 0,
feedback: require('') // 問題
};
},
created() {
this.clientWidth = document.documentElement.clientWidth;
this.clientHeight = document.documentElement.clientHeight;
},
mounted() {
this.isCanDraggable &&
this.$nextTick(() => {
this.floatDrag = this.$refs.floatDrag;
// 獲取元素位置屬性
this.floatDragDom = this.floatDrag.getBoundingClientRect();
// 設(shè)置初始位置
this.left =
this.clientWidth - this.floatDragDom.width - this.distanceRight;
this.top =
this.clientHeight - this.floatDragDom.height - this.distanceBottom;
this.initDraggable();
});
this.isScrollHidden && window.addEventListener("scroll", this.handleScroll);
window.addEventListener("resize", this.handleResize);
},
methods: {
showDialog() {
let url
window.open(url, '_blank')
},
/**
* 設(shè)置滾動時隱藏懸浮按鈕,停止時顯示
*/
handleScroll() {
this.timer && clearTimeout(this.timer);
this.timer = setTimeout(() => {
this.handleScrollEnd();
}, 200);
this.currentTop =
document.documentElement.scrollTop || document.body.scrollTop;
if (this.left > this.clientWidth / 2) {
// 判斷元素位置再左側(cè)還是右側(cè)
this.left = this.clientWidth + this.floatDragDom.width;
} else {
this.left = -this.floatDragDom.width;
}
},
/**
* 滾動結(jié)束
*/
handleScrollEnd() {
let scrollTop =
document.documentElement.scrollTop || document.body.scrollTop;
if (scrollTop === this.currentTop) {
console.log(this.left);
if (this.left > this.clientWidth / 2) {
// 判斷元素位置
this.left = this.clientWidth - this.floatDragDom.width;
} else {
this.left = 0;
}
clearTimeout(this.timer);
}
},
/**
* 窗口監(jiān)聽
*/
handleResize() {
this.clientWidth = document.documentElement.clientWidth;
this.clientHeight = document.documentElement.clientHeight;
this.checkDraggablePosition();
},
/**
* 初始化
*/
initDraggable() {
this.floatDrag.addEventListener("touchstart", this.toucheStart);
this.floatDrag.addEventListener("touchmove", e => this.touchMove(e));
this.floatDrag.addEventListener("touchend", this.touchEnd);
},
mouseDown(e) {
const event = e || window.event;
this.mousedownX = event.screenX;
this.mousedownY = event.screenY;
const that = this;
let floatDragWidth = this.floatDragDom.width / 2;
let floatDragHeight = this.floatDragDom.height / 2;
if (event.preventDefault) {
event.preventDefault();
}
this.canClick = false;
this.floatDrag.style.transition = "none";
setTimeout(() => {
document.onmousemove = function(e) {
var event = e || window.event;
that.left = event.clientX - floatDragWidth;
that.top = event.clientY - floatDragHeight;
if (that.left < 0) that.left = 0;
if (that.top < 0) that.top = 0;
if (that.left >= that.clientWidth - floatDragWidth * 2) {
that.left = that.clientWidth - floatDragWidth * 2;
}
if (that.top >= that.clientHeight - floatDragHeight * 2) {
that.top = that.clientHeight - floatDragHeight * 2;
}
// 解決鼠標(biāo)移出窗口 松開鼠標(biāo)后 回到窗口內(nèi) 懸浮繼續(xù)跟隨問題
if(event.clientX<=0 || event.clientY<=0 || event.clientY>= that.clientHeight || event.clientX>= that.clientWidth){
that.mouseUp(event)
}
};
}, 20);
},
mouseUp(e) {
const event = e || window.event;
//判斷只是單純的點(diǎn)擊,沒有拖拽
if (
this.mousedownY == event.screenY &&
this.mousedownX == event.screenX
) {
this.$emit("handlepaly");
}
document.onmousemove = null;
this.checkDraggablePosition();
this.floatDrag.style.transition = "all 0.3s";
},
toucheStart() {
this.canClick = false;
this.floatDrag.style.transition = "none";
},
touchMove(e) {
this.canClick = true;
if (e.targetTouches.length === 1) {
let touch = event.targetTouches[0];
this.left = touch.clientX - this.floatDragDom.width / 2;
this.top = touch.clientY - this.floatDragDom.height / 2;
}
},
touchEnd() {
if (!this.canClick) return; // 解決點(diǎn)擊事件和touch事件沖突的問題
this.floatDrag.style.transition = "all 0.3s";
this.checkDraggablePosition();
},
/**
* 判斷元素顯示位置
* 在窗口改變和move end時調(diào)用
*/
checkDraggablePosition() {
let details = document.querySelector('.details')
if (this.left + this.floatDragDom.width / 2 >= this.clientWidth / 2) {
// 判斷位置是往左往右滑動
this.left = this.clientWidth - this.floatDragDom.width;
details.style.right = '56px'
} else {
this.left = 0;
details.style.right = '-233px'
}
if (this.top < 0) {
// 判斷是否超出屏幕上沿
this.top = 0;
}
if (this.top + this.floatDragDom.height >= this.clientHeight) {
// 判斷是否超出屏幕下沿
this.top = this.clientHeight - this.floatDragDom.height;
}
}
},
beforeDestroy() {
window.removeEventListener("scroll", this.handleScroll);
window.removeEventListener("resize", this.handleResize);
}
};
</script>樣式
<style lang="less" scoped>
.float-position{
font-size: 12px;
position: fixed;
z-index: 500!important;
right: 0;
top: 50%;
width: 48px;
height: 168px;
display: flex;
align-items: center;
justify-content: center;
user-select: none;
}
</style>以上就是vue 懸浮窗且?guī)ё詣游焦δ軐?shí)現(xiàn)demo的詳細(xì)內(nèi)容,更多關(guān)于vue 懸浮窗自動吸附的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vue CLI3搭建的項(xiàng)目中路徑相關(guān)問題的解決
這篇文章主要介紹了Vue CLI3搭建的項(xiàng)目中路徑相關(guān)問題的解決,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-09-09
vue中集成省市區(qū)街四級地址組件的實(shí)現(xiàn)過程
我們在開發(fā)中常會遇到選擇地址的需求,有時候只需要選擇省就可以,有時候則需要選擇到市、縣,以至于鄉(xiāng)鎮(zhèn),甚至哪個村都有可能,下面這篇文章主要給大家介紹了關(guān)于vue中集成省市區(qū)街四級地址組件的相關(guān)資料,需要的朋友可以參考下2022-12-12
Vue生態(tài)系統(tǒng)工具庫Vueuse的使用示例詳解
Vueuse 是一個功能強(qiáng)大的 Vue.js 生態(tài)系統(tǒng)工具庫,它提供了一系列的可重用的 Vue 組件和函數(shù),本文將介紹 Vueuse 的主要特點(diǎn)和用法,以及它在 Vue.js 開發(fā)中的作用和優(yōu)勢,感興趣的可以了解下2024-02-02
vue實(shí)現(xiàn)把頁面導(dǎo)出成word文件的方法
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)把頁面導(dǎo)出成word文件的方法,文中的實(shí)現(xiàn)步驟講解詳細(xì),并且有詳細(xì)的代碼示例,需要的小伙伴可以參考一下2023-10-10
vue實(shí)現(xiàn)給某個數(shù)據(jù)字段添加顏色
這篇文章主要介紹了vue實(shí)現(xiàn)給某個數(shù)據(jù)字段添加顏色方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-03-03
vue + socket.io實(shí)現(xiàn)一個簡易聊天室示例代碼
本篇文章主要介紹了vue + socket.io實(shí)現(xiàn)一個簡易聊天室示例代碼,具有一定的參考價值,有興趣的可以了解一下。2017-03-03

