【sgThumbPreviewTip】自定义组件:缩略图预览组件,移入缩略图等待1秒后出现浮动气泡框显示更大的缩略图或预览播放视频
sgThumbPreviewTip
<!--缩略图预览组件-->
<template>
<div :class="$options.name" v-if="visible">
<!-- 提示框 -->
<div
class="float-tip"
ref="floatTip"
:style="floatTipData.style"
:show="floatTipData.show"
:theme="theme"
>
<div class="container" :style="containerData.style">
<template v-if="form.hasOwnProperty('img')">
<img ref="img" :src="form.img" @load="loadImg" />
</template>
<template v-else-if="form.hasOwnProperty('video')">
<video
ref="video"
autoplay
loop
muted
preload
playsinline="true"
webkit-playsinline="true"
:src="form.video"
@canplay="loadVideo"
/>
</template>
<template v-else-if="form.hasOwnProperty('text')">
<div v-html="form.text"></div>
</template>
</div>
</div>
</div>
</template>
<script>
export default {
name: "sgThumbPreviewTip",
components: {},
data() {
return {
theme: `default`, //主题
form: {},
visible: false,
floatTipData: {
show: false,
style: {},
},
containerData: { style: {} },
maxWidth: 400, //最大宽度
maxHeight: 400, //最大高度
padding: 5, //边界
load: null,
};
},
props: ["value", "data"],
computed: {},
watch: {
value: {
handler(d) {
this.visible = d;
},
deep: true,
immediate: true,
},
visible(d) {
if (d) {
this.g(this.data);
} else {
this.floatTipData.show = false;
}
this.$emit("input", d);
},
data: {
handler(newValue, oldValue) {
//console.log(`深度监听${this.$options.name}:`, newValue, oldValue);
if (Object.keys(newValue || {}).length) {
this.g(newValue);
}
},
deep: true, //深度监听
immediate: true, //立即执行
},
floatTipData: {
handler(newValue, oldValue) {
//console.log(`深度监听${this.$options.name}:`, newValue, oldValue);
if (Object.keys(newValue || {}).length) {
if (newValue.show) {
this.$emit(`load`, newValue);
this.load && this.load(newValue);
}
}
},
deep: true, //深度监听
immediate: true, //立即执行
},
},
created() {},
mounted() {},
beforeDestroy() {},
methods: {
g(newValue = this.form) {
this.form = newValue || {};
this.$g.convertForm2ComponentParam(`theme`, this);
this.$g.convertForm2ComponentParam(`load`, this);
this.$g.convertForm2ComponentParam(`maxWidth`, this);
this.$g.convertForm2ComponentParam(`maxHeight`, this);
this.$g.convertForm2ComponentParam(`padding`, this);
this.$nextTick(() => {
if (this.$el && this.$el.style) {
this.$el.style.setProperty("--maxWidth", `${this.maxWidth}px`); //js往css传递局部参数
this.$el.style.setProperty("--maxHeight", `${this.maxHeight}px`); //js往css传递局部参数
this.$el.style.setProperty("--padding", `${this.padding}px`); //js往css传递局部参数
}
});
this.mouseFollowFloatTip(this.form.mouseEvent);
},
loadImg(d) {
let img = this.$refs.img;
this.containerData.style = this.$g.calcScaleWidthHeigth({
containerWidth: this.maxWidth, //容器宽度
containerHeight: this.maxHeight, //容器高度
originWidth: img.naturalWidth, //图片原始宽度
originHeight: img.naturalHeight, //图片原始高度
});
this.floatTipData.show = true;
},
loadVideo(d) {
let video = this.$refs.video;
this.containerData.style = this.$g.calcScaleWidthHeigth({
containerWidth: this.maxWidth, //容器宽度
containerHeight: this.maxHeight, //容器高度
originWidth: video.videoWidth, //图片原始宽度
originHeight: video.videoHeight, //图片原始高度
});
this.floatTipData.show = true;
},
mouseFollowFloatTip(e) {
if (!e) return;
this.$nextTick(() => {
let floatTip = this.$refs.floatTip;
if (floatTip) {
// 鼠标跟随tip
let x = e.clientX,
y = e.clientY;
let mouseOffsetX = 20,
mouseOffsetY = 20;
let left = x + mouseOffsetX;
let top = y + mouseOffsetY;
let floatTipRect = floatTip.getBoundingClientRect();
//边界判断
left + floatTipRect.width > innerWidth &&
(left = innerWidth - floatTipRect.width);
top + floatTipRect.height > innerHeight &&
(top = innerHeight - floatTipRect.height);
this.floatTipData.style = { left: `${left}px`, top: `${top}px` };
this.text && (this.floatTipData.show = true);
}
});
},
},
};
</script>
<style lang="scss" scoped>
.sgThumbPreviewTip {
$maxWidth: var(--maxWidth); //最大宽度
$maxHeight: var(--maxHeight); //最大高度
$padding: var(--padding); //边界
// ----------------------------------------
position: fixed;
z-index: 999999;
left: 0;
top: 0;
pointer-events: none;
// 气泡框样式----------------------------------------
.float-tip {
transition: opacity 0.382s, left 0.05s, top 0.05s;
position: absolute;
word-wrap: break-word;
word-break: break-all;
white-space: break-spaces;
font-size: 12px;
pointer-events: none;
border-radius: 4px;
background-color: white;
box-shadow: 0 5px 20px 0 #00000022;
box-sizing: border-box;
padding: $padding;
opacity: 0;
&[show] {
opacity: 1;
}
.container {
border-radius: 4px;
overflow: hidden;
width: $maxWidth;
height: $maxHeight;
max-width: $maxWidth;
max-height: $maxHeight;
img,
video {
width: 100%;
height: 100%;
object-fit: contain;
object-position: center;
background: transparent;
}
}
//windows7主题
&[theme="win7"] {
border-radius: 8px;
background: linear-gradient(
180deg,
#fafafa1a 0%,
#ffffff66 30%,
#46464633 40%,
#aaaaaa1a 100%
) !important;
box-shadow: 0 0 0 1px #ffffffcc, 0 0 8px 3px #0a0a0acc;
backdrop-filter: blur(7px) brightness(0.9);
.container {
background-color: white;
}
}
}
}
</style>
demo
<template>
<div :class="$options.name">
<img
src="https://www.baidu.com/img/flexible/logo/pc/result.png"
@mouseover="mouseoverThumb"
@mousemove="mousemoveThumb"
@mouseout="mouseoutThumb"
/>
<!-- 预览缩略图 -->
<sgThumbPreviewTip ref="sgThumbPreviewTip" />
</div>
</template>
<script>
import sgThumbPreviewTip from "@/vue/components/admin/sgThumbPreviewTip";
export default {
components: {
sgThumbPreviewTip,
},
data() {
return {
// 全局缩略图气泡框----------------------------------------
mouseoverThumbTimeout: null, //记录鼠标移入封面的时间
mousemoveThumbData: null,
// ----------------------------------------
};
},
props: ["data"],
computed: {},
watch: {},
created() {},
mounted() {},
destroyed() {},
methods: {
// 移入封面预览气泡框■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
get_sgThumbPreviewTip() {
return this.$refs.sgThumbPreviewTip;
},
showThumbTip({ w = true, d = {} } = {}) {
let sgThumbPreviewTip = this.get_sgThumbPreviewTip();
if (sgThumbPreviewTip) {
sgThumbPreviewTip.g(d);
sgThumbPreviewTip.visible = true;
}
},
hideThumbTip() {
let sgThumbPreviewTip = this.get_sgThumbPreviewTip();
sgThumbPreviewTip.visible = false;
},
mouseoverThumb(d) {
clearTimeout(this.mouseoverThumbTimeout);
this.mouseoverThumbTimeout = setTimeout(() => {
this.showThumbTip({ d: this.mousemoveThumbData });
}, 1000); // 停留时长
},
mousemoveThumb(d) {
let mousemoveThumbData = {
mouseEvent: d,
img: `https://www.baidu.com/img/flexible/logo/pc/result@2.png`,
// theme: `win7`, //主题
};
this.mousemoveThumbData = mousemoveThumbData; //传入气泡框的内容
this.get_sgThumbPreviewTip().visible &&
this.showThumbTip({ d: this.mousemoveThumbData });
},
mouseoutThumb(d) {
clearTimeout(this.mouseoverThumbTimeout);
this.hideThumbTip();
},
},
};
</script>
引用了【推荐】实现跟随鼠标移动的浮动提示框、浮动气泡框、Tip效果_实现鼠标移动提示框也移动-CSDN博客文章浏览阅读2.9k次,点赞3次,收藏13次。这个示例展示了如何在Vue应用中创建一个跟随鼠标移动的提示框。当鼠标悬停在特定元素上时,提示框会显示该元素内的文本,并在鼠标离开时隐藏。实现包括CSS样式和JavaScript事件监听,用于调整提示框的位置以避免超出窗口边界。https://blog.csdn.net/qq_37860634/article/details/127115152