在开发项目时,防一个网站上面的动态飘窗效果,网站是使用jq进行开发的,不过自己的项目用的是vue进行开发,准备手写一个飘窗效果,网上看了vue很多案例,感觉功能不是很完善,会存在一些问题,自己根据一套使用js编写的案例进行完善了下vue的飘窗效果
功能分析
需要的飘窗就是一个元素在屏幕上从一侧飘到另一侧,但是还要随着屏幕的宽高变化,不改变飘动方向,且还要获取到最新的边界值,当鼠标移入禁止飘动,移出继续飘动
先写一个盒子
<template>
<div>
<div
v-if="show"
@mouseover="mouseover"
@mouseout="mouseout"
class="box"
:style="{ top: top + 'px', left: left + 'px' }"
ref="boxRef"
>
<span @click="close" style="color: white" class="closeBtn">关闭</span>
<div class="info-text">我不是大瓢虫</div>
</div>
</div>
</template>
在进行处理飘动逻辑
// 移动函数
move() {
// 因为刚开始默元素位置是 0,0 在屏幕的左上角
//判断移动方向
//1 向右移动时
if (this.directionX == "right") {
// 判断 移动的距离加上元素的宽度加上步长 是否大于 可视屏幕的宽度
// 如果大于屏幕宽度就表示碰到了 右侧的边界 并进行修改方向
if (this.left + this.width + this.stepX > this.clientWidth) {
this.directionX = "left";
}
//2 向左移动时
} else {
// 只需要判断 用之前移动的左侧距离减去步长 当小于0时就表示碰到了左侧的边界
if (this.left - this.stepX < 0) {
this.directionX = "right";
}
}
// 3 向下移动
if (this.directionY == "down") {
// 同理 需要判断当前 距离头部的距离加上元素的高度加上步长 是否大于可视屏幕的高度
// 如果大于可视屏幕高度就表示碰到了 屏幕底部的边界
if (this.top + this.height + this.stepY > this.clientHeight) {
this.directionY = "up";
}
// 4 向上移动
} else {
// 只需要判断 用之前移动的头部距离减去步长 当小于0时就表示碰到了屏幕上边的边界
if (this.top - this.stepY < 0) {
this.directionY = "down";
}
}
//移动操作
// 向右移动时将左侧的距离根据定时器的触发进行加上每次的步长
if (this.directionX == "right") {
this.left += this.stepX;
// 向左移动时就需要将之前获取到的左侧距离减去步长
} else {
this.left -= this.stepX;
}
// 向下移动时将距离头部的距离根据定时器的触发加上每次的步长
if (this.directionY == "down") {
this.top += this.stepY;
// 向上移动时需要将之前获取到的头部距离减去步长
} else {
this.top -= this.stepY;
}
},
鼠标移入进行清除定时器禁止移动
// 鼠标悬浮在飘窗时停止移动
mouseover() {
clearInterval(this.timer);
},
鼠标移出开始移动
// 鼠标离开飘窗时恢复移动
mouseout() {
this.start();
},
还需要一些默认声明字段,统一贴出完整代码
<template>
<div>
<div
v-if="show"
@mouseover="mouseover"
@mouseout="mouseout"
class="box"
:style="{ top: top + 'px', left: left + 'px' }"
ref="boxRef"
>
<span @click="close" style="color: white" class="closeBtn">关闭</span>
<div class="info-text">我不是大瓢虫</div>
</div>
</div>
</template>
<script>
export default {
name: "dome",
data() {
return {
show: true, // 是否展现飘窗
directionX: "right", //飘窗的x轴方向 right left
directionY: "down", //飘窗的Y轴方向 down up
stepX: 1, // 水平方向的步长
stepY: 1, // 垂直方向的步长
timer: "", // 定时器
clientHeight: 0, // 最大的 top 值
clientWidth: 0, // 最大的 left 值
height: 0, //元素的高
width: 0, //元素的宽
top: 0, //头部距离
left: 0 //左侧距离
};
},
mounted() {
this.$nextTick(() => {
this.init();
this.onresize();
});
},
beforeDestroy() {
// dom 销毁前清除定时器
clearInterval(this.timer);
},
methods: {
// 初始化飘窗规则
init() {
// 获取元素的高度
this.height = this.$refs.boxRef.offsetHeight;
// 获取元素的宽度
this.width = this.$refs.boxRef.offsetWidth;
// 获取可视屏幕的高度
this.clientHeight = document.documentElement.clientHeight;
// 获取可视屏幕的宽度
this.clientWidth = document.documentElement.clientWidth;
// 开始移动函数
this.start();
},
// 开始设置定时器进行移动
start() {
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
this.timer = setInterval(() => {
this.move();
}, 15);
},
// 移动函数
move() {
// 因为刚开始默元素位置是 0,0 在屏幕的左上角
//判断移动方向
//1 向右移动时
if (this.directionX == "right") {
// 判断 移动的距离加上元素的宽度加上步长 是否大于 可视屏幕的宽度
// 如果大于屏幕宽度就表示碰到了 右侧的边界 并进行修改方向
if (this.left + this.width + this.stepX > this.clientWidth) {
this.directionX = "left";
}
//2 向左移动时
} else {
// 只需要判断 用之前移动的左侧距离减去步长 当小于0时就表示碰到了左侧的边界
if (this.left - this.stepX < 0) {
this.directionX = "right";
}
}
// 3 向下移动
if (this.directionY == "down") {
// 同理 需要判断当前 距离头部的距离加上元素的高度加上步长 是否大于可视屏幕的高度
// 如果大于可视屏幕高度就表示碰到了 屏幕底部的边界
if (this.top + this.height + this.stepY > this.clientHeight) {
this.directionY = "up";
}
// 4 向上移动
} else {
// 只需要判断 用之前移动的头部距离减去步长 当小于0时就表示碰到了屏幕上边的边界
if (this.top - this.stepY < 0) {
this.directionY = "down";
}
}
//移动操作
// 向右移动时将左侧的距离根据定时器的触发进行加上每次的步长
if (this.directionX == "right") {
this.left += this.stepX;
// 向左移动时就需要将之前获取到的左侧距离减去步长
} else {
this.left -= this.stepX;
}
// 向下移动时将距离头部的距离根据定时器的触发加上每次的步长
if (this.directionY == "down") {
this.top += this.stepY;
// 向上移动时需要将之前获取到的头部距离减去步长
} else {
this.top -= this.stepY;
}
},
// 鼠标悬浮在飘窗时停止移动
mouseover() {
clearInterval(this.timer);
},
// 鼠标离开飘窗时恢复移动
mouseout() {
this.start();
},
// 关闭飘窗
close() {
clearInterval(this.timer);
this.show = false;
},
// 窗口大小调整时重置飘窗规则
onresize() {
const that = this;
window.onresize = function() {
that.init();
};
}
}
};
</script>
<style scoped lang="scss">
.box {
z-index: 2000;
background-color: #84a7e7;
background-size: contain;
width: 235px;
height: 167px;
border-radius: 5px;
position: fixed;
text-align: left;
padding: 10px;
color: #ffffff;
top: 0;
left: 0;
.closeBtn {
img {
width: 15px;
height: 15px;
}
}
.info {
width: 55px;
height: 55px;
background-color: rgba(#84a7e7, 0.4);
border-radius: 50%;
position: relative;
margin: -3px auto 0;
.info-back {
width: 43px;
height: 43px;
background-color: rgba(#84a7e7, 0.5);
border-radius: 50%;
position: absolute;
top: 5.5px;
right: 6.5px;
img {
width: 30px;
height: 30px;
top: 7px;
right: 7px;
position: absolute;
}
}
}
> span {
text-align: right;
position: absolute;
right: 10px;
top: 10px;
color: #1e87f0;
cursor: pointer;
}
> div {
margin-top: 30px;
}
.info-text {
font-size: 20px;
font-family: PingFang SC;
font-weight: 400;
color: #333333;
margin: 30px auto 0;
text-align: center;
}
}
</style>