当前位置: 首页 > wzjs >正文

深圳做网站最好的公哪个网站做网销更好

深圳做网站最好的公,哪个网站做网销更好,网站和网页的设计原则,网站建设的销售渠道本组件支持hover和click两种触发方式,需要更多的触发方式,可自行去扩展!!! 1.传递三个参数: content:要展示的文本 position:文本出现的位置("top" | "t…

本组件支持hover和click两种触发方式,需要更多的触发方式,可自行去扩展!!!

 

1.传递三个参数:

  • content:要展示的文本
  • position:文本出现的位置("top" | "top-start" | "top-end" | "bottom" | "bottom-start" | "bottom-end" | "left" | "right")

  • trigger:触发的方式("hover" | "click")

  • appendToBody:是否添加到body上去

2.使用方式:

<ToolTipcontent="测试ToolTip":appendToBody="true"trigger="click"position="top"
><span class="key-word">测试ToolTip</span>
</ToolTip>

3.封装的ToolTip组件详细代码如下: 

<template><divclass="tooltip-container":class="{ 'tooltip-click': props.trigger === 'click' }"@mouseover="handleMouseOver"@mouseout="handleMouseOut"@click="handleClick"ref="triggerEl"><slot></slot><teleport to="body" :disabled="!props.appendToBody"><transition name="tooltip"><div v-if="isTooltipVisible" :class="tooltipClass" :style="tooltipStyle" ref="tooltipEl"><div class="tooltip-inner">{{ props.content }}</div></div></transition></teleport></div>
</template><script setup lang="ts">
import { ref, computed, watch, onMounted, onBeforeUnmount, CSSProperties } from "vue";// 定义提示框可能出现的位置选项
const positionOptions = ["top", "top-start", "top-end", "bottom", "bottom-start", "bottom-end", "left", "right"] as const;
// 定义位置和触发方式的类型
type Position = (typeof positionOptions)[number];
type Trigger = ["hover" | "click"][number];
const defaultTrigger: Trigger = "hover";// 定义组件的 props 接口
interface TooltipProps {content: string; // 提示框内容position?: Position; // 提示框位置trigger?: Trigger; // 触发方式appendToBody?: boolean; // 是否将提示框添加到 body 中
}// 设置 props 的默认值
const props = withDefaults(defineProps<TooltipProps>(), {position: "top",trigger: defaultTrigger,appendToBody: false
});// 创建响应式引用
const triggerEl = ref<HTMLElement | null>(null); // 触发元素引用
const tooltipEl = ref<HTMLElement | null>(null); // 提示框元素引用
const isTooltipVisible = ref(false); // 提示框是否可见
const tooltipPosition = ref({ top: "0px", left: "0px" }); // 提示框位置// 处理点击外部事件
const handleClickOutside = (event: MouseEvent) => {if (props.trigger === "click" && isTooltipVisible.value) {const target = event.target as Node;if (triggerEl.value && tooltipEl.value && !triggerEl.value.contains(target) && !tooltipEl.value.contains(target)) {hideTooltip();}}
};// 更新提示框位置的函数
const updatePosition = () => {if (!triggerEl.value || !tooltipEl.value || !props.appendToBody) return;// 获取各种位置和尺寸信息const triggerRect = triggerEl.value.getBoundingClientRect();const tooltipRect = tooltipEl.value.getBoundingClientRect();const scrollTop = window.pageYOffset || document.documentElement.scrollTop;const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;const viewportWidth = window.innerWidth;const viewportHeight = window.innerHeight;let top = 0;let left = 0;const gap = 4; // 设置间隙// 计算提示框位置的核心函数const calculatePosition = () => {switch (props.position) {// 处理顶部位置的情况(top, top-start, top-end 三种)case "top":case "top-start":case "top-end": {// 检查顶部空间是否足够放置提示框(触发元素顶部位置是否大于提示框高度+间隙)if (triggerRect.top > tooltipRect.height + gap) {// 设置提示框的垂直位置:触发元素顶部位置 - 提示框高度 - 间隙top = triggerRect.top + scrollTop - tooltipRect.height - gap;// 根据不同的顶部对齐方式计算水平位置if (props.position === "top") {// top:水平居中对齐left =triggerRect.left + // 触发元素的左边界scrollLeft + // 加上页面水平滚动距离(triggerRect.width - tooltipRect.width) / 2; // 居中对齐的偏移量} else if (props.position === "top-start") {// top-start:左对齐left = triggerRect.left + scrollLeft; // 直接与触发元素左边界对齐} else {// top-end:右对齐left =triggerRect.left + // 触发元素的左边界scrollLeft + // 加上页面水平滚动距离triggerRect.width - // 加上触发元素的宽度tooltipRect.width; // 减去提示框宽度,实现右对齐}} else {// 如果顶部空间不足,自动切换到底部显示top = triggerRect.bottom + scrollTop + gap; // 设置到触发元素底部left = calculateHorizontalPosition(); // 重新计算水平位置tooltipEl.value?.classList.remove(props.position); // 移除原有位置类名tooltipEl.value?.classList.add("bottom"); // 添加底部位置类名}break;}// 处理底部位置的情况(bottom, bottom-start, bottom-end 三种)case "bottom":case "bottom-start":case "bottom-end": {// 设置提示框的垂直位置:触发元素底部 + 间隙top = triggerRect.bottom + scrollTop + gap;// 根据不同的底部对齐方式计算水平位置if (props.position === "bottom") {// bottom:水平居中对齐left =triggerRect.left + // 触发元素的左边界scrollLeft + // 加上页面水平滚动距离(triggerRect.width - tooltipRect.width) / 2; // 居中对齐的偏移量} else if (props.position === "bottom-start") {// bottom-start:左对齐left = triggerRect.left + scrollLeft; // 直接与触发元素左边界对齐} else {// bottom-end:右对齐left =triggerRect.left + // 触发元素的左边界scrollLeft + // 加上页面水平滚动距离triggerRect.width - // 加上触发元素的宽度tooltipRect.width; // 减去提示框宽度,实现右对齐}break;}// 处理左侧位置的情况case "left": {const arrowWidth = 18; // 箭头的宽度// 检查左侧空间是否足够(触发元素左侧位置是否大于提示框宽度+间隙+箭头宽度)if (triggerRect.left > tooltipRect.width + gap + arrowWidth) {// 设置水平位置:触发元素左侧 - 提示框宽度 - 间隙 - 箭头宽度left = triggerRect.left + scrollLeft - tooltipRect.width - gap - arrowWidth;// 垂直居中对齐top = triggerRect.top + scrollTop + (triggerRect.height - tooltipRect.height) / 2;} else {// 如果左侧空间不足,自动切换到右侧显示left = triggerRect.right + scrollLeft + gap; // 设置到触发元素右侧// 保持垂直居中top = triggerRect.top + scrollTop + (triggerRect.height - tooltipRect.height) / 2;tooltipEl.value?.classList.remove("left"); // 移除左侧位置类名tooltipEl.value?.classList.add("right"); // 添加右侧位置类名}break;}// 处理右侧位置的情况case "right": {const arrowWidth = 18; // 箭头的宽度// 检查右侧空间是否足够(触发元素右侧位置+提示框宽度+间隙是否小于视口宽度)if (triggerRect.right + tooltipRect.width + gap <= viewportWidth) {// 设置水平位置:触发元素右侧 + 间隙left = triggerRect.right + scrollLeft + gap;// 垂直居中对齐top = triggerRect.top + scrollTop + (triggerRect.height - tooltipRect.height) / 2;} else {// 如果右侧空间不足,自动切换到左侧显示// 确保左侧位置不小于间隙值left = Math.max(gap, triggerRect.left + scrollLeft - tooltipRect.width - gap - arrowWidth);// 保持垂直居中top = triggerRect.top + scrollTop + (triggerRect.height - tooltipRect.height) / 2;tooltipEl.value?.classList.remove("right"); // 移除右侧位置类名tooltipEl.value?.classList.add("left"); // 添加左侧位置类名}break;}}};// 计算水平位置,确保提示框在视口内const calculateHorizontalPosition = () => {let calculatedLeft = triggerRect.left + scrollLeft + (triggerRect.width - tooltipRect.width) / 2;if (calculatedLeft < 0) {calculatedLeft = gap;}if (calculatedLeft + tooltipRect.width > viewportWidth) {calculatedLeft = viewportWidth - tooltipRect.width - gap;}return calculatedLeft;};calculatePosition();// 确保提示框在视口范围内if (top < scrollTop) {top = scrollTop + gap;} else if (top + tooltipRect.height > scrollTop + viewportHeight) {top = scrollTop + viewportHeight - tooltipRect.height - gap;}left = Math.max(gap, Math.min(left, viewportWidth - tooltipRect.width - gap));// 更新提示框位置tooltipPosition.value = {top: `${Math.round(top)}px`,left: `${Math.round(left)}px`};
};// 显示提示框
const showTooltip = () => {isTooltipVisible.value = true;setTimeout(updatePosition, 0);
};// 隐藏提示框
const hideTooltip = () => {isTooltipVisible.value = false;
};// 处理鼠标移入事件
const handleMouseOver = () => {if (props.trigger === "hover") {showTooltip();}
};// 处理鼠标移出事件
const handleMouseOut = () => {if (props.trigger === "hover") {hideTooltip();}
};// 处理点击事件
const handleClick = () => {if (props.trigger === "click") {isTooltipVisible.value = !isTooltipVisible.value;if (isTooltipVisible.value) {setTimeout(updatePosition, 0);}}
};// 组件挂载时添加事件监听
onMounted(() => {window.addEventListener("scroll", updatePosition);window.addEventListener("resize", updatePosition);document.addEventListener("click", handleClickOutside);
});// 组件卸载前移除事件监听
onBeforeUnmount(() => {window.removeEventListener("scroll", updatePosition);window.removeEventListener("resize", updatePosition);document.removeEventListener("click", handleClickOutside);
});// 监听触发方式的变化
watch(() => props.trigger,newTrigger => {if (newTrigger === "click" && isTooltipVisible.value) {hideTooltip();}},{ immediate: true }
);// 计算提示框的 class
const tooltipClass = computed(() => {return `tooltip-content ${props.position} ${isTooltipVisible.value ? "active" : ""}`;
});// 计算提示框的样式
const tooltipStyle = computed<CSSProperties>(() => {if (!props.appendToBody) return {};return {position: "fixed",top: tooltipPosition.value.top,left: tooltipPosition.value.left,zIndex: 9999};
});
</script><style lang="scss" scoped>
@use "sass:math";
$basicW: 6px;
$arrowSize: 6px;
$backgroundColor: #454545;.tooltip-container {width: 100%;position: relative;display: inline-block;z-index: 1;
}.tooltip-content {position: absolute;z-index: 9999;pointer-events: none;.tooltip-inner {position: relative;background-color: #454545;color: #fff;padding: 8px 12px;border-radius: 4px;font-size: 14px;line-height: 1.4;white-space: normal;min-width: max-content;max-width: 300px;width: auto;word-wrap: break-word;box-shadow: 2px 2px 8px rgb(0 0 0);&::before {position: absolute;content: "";width: 0;height: 0;border: $arrowSize solid transparent;}}&.active {pointer-events: auto;}&.top,&.top-start,&.top-end {padding-bottom: $arrowSize;.tooltip-inner::before {bottom: -$arrowSize * 2;border-top-color: $backgroundColor;}}&.bottom,&.bottom-start,&.bottom-end {padding-top: $arrowSize;.tooltip-inner::before {top: -$arrowSize * 2;border-bottom-color: $backgroundColor;}}&.left {padding-right: $arrowSize;.tooltip-inner::before {right: -$arrowSize * 2;border-left-color: $backgroundColor;}}&.right {padding-left: $arrowSize;.tooltip-inner::before {left: -$arrowSize * 2;border-right-color: $backgroundColor;}}&.top,&.bottom {.tooltip-inner::before {left: 50%;transform: translateX(-50%);}}&.top-start,&.bottom-start {.tooltip-inner::before {left: $arrowSize;}}&.top-end,&.bottom-end {.tooltip-inner::before {right: $arrowSize;}}&.left,&.right {.tooltip-inner::before {top: 50%;transform: translateY(-50%);}}
}// 动画相关样式
.tooltip-enter-active,
.tooltip-leave-active {transition: opacity 0.2s ease, transform 0.2s ease-out;
}.tooltip-enter-from,
.tooltip-leave-to {opacity: 0;transform: scale(0.95);
}.tooltip-enter-to,
.tooltip-leave-from {opacity: 1;transform: scale(1);
}
</style>


文章转载自:

http://nByA6CEo.kkdbz.cn
http://CbOiEqTq.kkdbz.cn
http://9P1lI7iX.kkdbz.cn
http://gfIpycU6.kkdbz.cn
http://BhJWweIF.kkdbz.cn
http://DD2FS3dh.kkdbz.cn
http://NqIQ9IIB.kkdbz.cn
http://Q6TBx77I.kkdbz.cn
http://hmkDAl85.kkdbz.cn
http://tVuG2RTP.kkdbz.cn
http://BFZF7Ihp.kkdbz.cn
http://wEGOY5yQ.kkdbz.cn
http://ZfOBFual.kkdbz.cn
http://8okmLMzF.kkdbz.cn
http://JdhtdAdC.kkdbz.cn
http://STBu9mcN.kkdbz.cn
http://yuVszSi8.kkdbz.cn
http://EzUeggXh.kkdbz.cn
http://rJeC8WHA.kkdbz.cn
http://0w0IcTuR.kkdbz.cn
http://eG8lBQ9s.kkdbz.cn
http://15edq5ZY.kkdbz.cn
http://U67hx0Gj.kkdbz.cn
http://5cnStO6i.kkdbz.cn
http://hLIB8UbB.kkdbz.cn
http://3OOM7eyG.kkdbz.cn
http://FTkZHSck.kkdbz.cn
http://xC4Wl0JD.kkdbz.cn
http://5tcMqXBl.kkdbz.cn
http://VZamXmVP.kkdbz.cn
http://www.dtcms.com/wzjs/724012.html

相关文章:

  • 承包网站建设的公司外贸网站设计公司价格
  • 网站新闻字体汇天网络科技有限公司
  • 创建网站用突唯阿做响应式网站新能源汽车价格走势
  • 查网站是否正规大作设计app
  • 垂直网站内容建设做电影网站怎么接广告
  • 沈阳大型网站建设网页界面设计想法
  • 医疗网站建设流程营销网络的建设有哪些
  • 做网站用到什么开发语言做彩票网站是违法的吗
  • 开发电子商务网站和开发新闻类网站什么异同企业网站建设哪家快
  • 二级域名网站有哪些新乡网站制作
  • 彩票网站开发搭建小题狂做+官方网站
  • 申请域名建立网站短视频seo排名系统
  • 移动建站平台龙海网站建设价格
  • 做公司网站需如何做婚庆公司的网站
  • 摄影网站建设开题报告5分钟建站wordpress
  • 网站域名不备案山东鸿泰建设集团有限公司网站
  • 手机网站建设 cms网站建设收费分几次
  • linux网站如何做ip解析郑州不错的软件开发公司
  • 上海做网站的网站wordpress页面多打开空白页
  • 国外网站排行榜微信做网站的公司
  • 广州高端网站建设定制动易网站论坛
  • 长春网站长春网络推广建设公司网站建设案例
  • 网站建设需要哪些职位搜索关键词查询
  • 南通营销网站建设国外互联网资讯网站
  • 县直门户网站建设管理哈尔滨网站设计公司
  • 温州网站推广模板数据库网站 建设费用
  • 无忧网站建设哪家好搜索引擎seo是什么意思
  • 平和网站建设郑州各区房价一览表
  • 麻涌公司网站建设公司焦溪翠冠梨做的网站
  • 网站后台邮箱设置在线做ppt模板下载网站有哪些