✨(component): [tooltip]新增 visible 参数;修复定位; content 变化时更新位置
This commit is contained in:
parent
4b30714dab
commit
20a49818a3
@ -23,8 +23,18 @@ export default {
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import "./index.less";
|
import "./index.less";
|
||||||
import postionFns from "./calcPosition";
|
import postionFns from "./calcPosition";
|
||||||
import { CSSProperties, ref, watch, onMounted } from "vue";
|
import {
|
||||||
|
CSSProperties,
|
||||||
|
ref,
|
||||||
|
watch,
|
||||||
|
onMounted,
|
||||||
|
watchEffect,
|
||||||
|
nextTick,
|
||||||
|
onBeforeUnmount,
|
||||||
|
useSlots,
|
||||||
|
} from "vue";
|
||||||
import { on } from "../../utils/domUtil";
|
import { on } from "../../utils/domUtil";
|
||||||
|
import { useThrottleFn } from "@vueuse/core";
|
||||||
|
|
||||||
export interface LayPopperProps {
|
export interface LayPopperProps {
|
||||||
el: any;
|
el: any;
|
||||||
@ -36,6 +46,7 @@ export interface LayPopperProps {
|
|||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
isCanHide?: boolean;
|
isCanHide?: boolean;
|
||||||
isAutoShow?: boolean;
|
isAutoShow?: boolean;
|
||||||
|
visible?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<LayPopperProps>(), {
|
const props = withDefaults(defineProps<LayPopperProps>(), {
|
||||||
@ -46,8 +57,11 @@ const props = withDefaults(defineProps<LayPopperProps>(), {
|
|||||||
isCanHide: true,
|
isCanHide: true,
|
||||||
isAutoShow: false,
|
isAutoShow: false,
|
||||||
trigger: "hover",
|
trigger: "hover",
|
||||||
|
visible: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const slots = useSlots();
|
||||||
|
|
||||||
const EVENT_MAP: any = {
|
const EVENT_MAP: any = {
|
||||||
hover: ["mouseenter", null, "mouseleave", false],
|
hover: ["mouseenter", null, "mouseleave", false],
|
||||||
click: ["click", document, "click", true],
|
click: ["click", document, "click", true],
|
||||||
@ -62,13 +76,17 @@ const style = ref<CSSProperties>({ top: -window.innerHeight + "px", left: 0 });
|
|||||||
const checkTarget = ref(false);
|
const checkTarget = ref(false);
|
||||||
const popper = ref<HTMLDivElement>({} as HTMLDivElement);
|
const popper = ref<HTMLDivElement>({} as HTMLDivElement);
|
||||||
const innnerPosition = ref(props.position);
|
const innnerPosition = ref(props.position);
|
||||||
const innerVisible = ref(!props.isCanHide);
|
const innerVisible = ref(props.visible);
|
||||||
const isExist = ref(!props.isCanHide);
|
const isExist = ref(props.visible);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.isCanHide,
|
() => props.visible,
|
||||||
(val) => {
|
(val) => {
|
||||||
innerVisible.value = !val;
|
if (val) {
|
||||||
|
doShow();
|
||||||
|
} else {
|
||||||
|
doHidden();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -83,26 +101,25 @@ watch(popper, (val) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(
|
watch([() => props.content, () => slots.content && slots?.content()], (val) => {
|
||||||
() => props.content,
|
innerVisible.value && invokeShowPosistion();
|
||||||
(val) => {
|
});
|
||||||
innerVisible.value && invokeShowPosistion();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const doShow = function () {
|
const doShow = function () {
|
||||||
if (!props.disabled) {
|
if (!props.disabled) {
|
||||||
if (!isExist.value) {
|
if (!isExist.value) {
|
||||||
isExist.value = true;
|
isExist.value = true;
|
||||||
setTimeout(() => (innerVisible.value = true), 0);
|
nextTick(() => {
|
||||||
|
innerVisible.value = true;
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
innerVisible.value = true;
|
innerVisible.value = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const doHidden = function (e: MouseEvent) {
|
const doHidden = function (e?: MouseEvent) {
|
||||||
if (checkTarget.value && props.el.contains(e.target)) {
|
if (checkTarget.value && props.el.contains(e?.target)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,13 +144,41 @@ const showPosistion = function () {
|
|||||||
const invokeShowPosistion = function () {
|
const invokeShowPosistion = function () {
|
||||||
if (innerVisible.value) {
|
if (innerVisible.value) {
|
||||||
popper.value.offsetWidth === 0
|
popper.value.offsetWidth === 0
|
||||||
? setTimeout(showPosistion, 0)
|
? nextTick(() => showPosistion())
|
||||||
: showPosistion();
|
: showPosistion();
|
||||||
// 延时确保计算位置正确
|
nextTick(() => {
|
||||||
setTimeout(() => innerVisible.value && showPosistion(), 2);
|
showPosistion();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let scrollElements: HTMLElement[] | undefined;
|
||||||
|
|
||||||
|
const isScrollElement = (element: HTMLElement) => {
|
||||||
|
return (
|
||||||
|
element.scrollHeight > element.offsetHeight ||
|
||||||
|
element.scrollWidth > element.offsetWidth
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getScrollElements = (container: HTMLElement | undefined) => {
|
||||||
|
const scrollElements: HTMLElement[] = [];
|
||||||
|
let element: HTMLElement | undefined = container;
|
||||||
|
while (element && element !== document.documentElement) {
|
||||||
|
if (isScrollElement(element)) {
|
||||||
|
scrollElements.push(element);
|
||||||
|
}
|
||||||
|
element = element.parentElement ?? undefined;
|
||||||
|
}
|
||||||
|
return scrollElements;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleScroll = useThrottleFn(() => {
|
||||||
|
if (innerVisible.value) {
|
||||||
|
invokeShowPosistion();
|
||||||
|
}
|
||||||
|
}, 15);
|
||||||
|
|
||||||
// 事件绑定
|
// 事件绑定
|
||||||
on(props.el, triggerArr[0], doShow);
|
on(props.el, triggerArr[0], doShow);
|
||||||
on(triggerArr[1] ?? props.el, triggerArr[2], doHidden);
|
on(triggerArr[1] ?? props.el, triggerArr[2], doHidden);
|
||||||
@ -141,5 +186,20 @@ checkTarget.value = triggerArr[3];
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
invokeShowPosistion();
|
invokeShowPosistion();
|
||||||
|
scrollElements = getScrollElements(props.el);
|
||||||
|
for (const item of scrollElements) {
|
||||||
|
item.addEventListener("scroll", handleScroll);
|
||||||
|
}
|
||||||
|
window.addEventListener("resize", handleScroll);
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (scrollElements) {
|
||||||
|
for (const item of scrollElements) {
|
||||||
|
item.removeEventListener("scroll", handleScroll);
|
||||||
|
}
|
||||||
|
scrollElements = undefined;
|
||||||
|
}
|
||||||
|
window.removeEventListener("resize", handleScroll);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import "./index.less";
|
import "./index.less";
|
||||||
import LayPopper from "../popper/index.vue";
|
import LayPopper from "../popper/index.vue";
|
||||||
import { defineComponent, ref } from "vue";
|
import { defineComponent, PropType, ref } from "vue";
|
||||||
import { useEventListener } from "@vueuse/core";
|
import { useEventListener } from "@vueuse/core";
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "LayTooltip",
|
name: "LayTooltip",
|
||||||
@ -43,6 +43,14 @@ export default defineComponent({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
visible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
trigger: {
|
||||||
|
type: String as PropType<"click" | "hover">,
|
||||||
|
default: "hover",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const isMounted = ref(false);
|
const isMounted = ref(false);
|
||||||
|
@ -389,11 +389,11 @@ export default {
|
|||||||
| 属性 | 描述 | 类型 | 默认值 | 可选值 |
|
| 属性 | 描述 | 类型 | 默认值 | 可选值 |
|
||||||
| ------------------- | -------------------------------------------------- | ----------------------------------------- | -------- | ----------------------------- |
|
| ------------------- | -------------------------------------------------- | ----------------------------------------- | -------- | ----------------------------- |
|
||||||
| v-model | 当前激活 | `string` | - | - |
|
| v-model | 当前激活 | `string` | - | - |
|
||||||
| type | 主题样式 | `string` | - | - |
|
| type | 主题样式 | `string` | - | `brief` `card` |
|
||||||
| tabPosition | 位置 | `string` | `bottom` | `top` `bottom` `left` `right` |
|
| tabPosition | 位置 | `string` | `bottom` | `top` `bottom` `left` `right` |
|
||||||
| allow-close | 允许关闭 | `boolean` | `false` | `true` `false` |
|
| allow-close | 允许关闭 | `boolean` | `false` | `true` `false` |
|
||||||
| before-close | `Function`关闭之前的回调钩子函数 | 参数(`id`), `return false` 表示不进行关闭 | - | - |
|
| before-close | 关闭之前的回调钩子函数,参数(`id`), `return false` 表示不进行关闭 | `Function` | - | - |
|
||||||
| before-leave | `Function`切换标签之前的回调钩子函数 | 参数(`id`), `return false` 表示不进行切换 | - | - |
|
| before-leave | 切换标签之前的回调钩子函数, 参数(`id`), `return false` 表示不进行关闭 | `Function` | - | - |
|
||||||
| activeBarTransition | 是否开启 activeBar 动画,仅 brief 有效,默认 `false` | `boolean` | `false` | `true` `false` |
|
| activeBarTransition | 是否开启 activeBar 动画,仅 brief 有效,默认 `false` | `boolean` | `false` | `true` `false` |
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
@ -48,9 +48,35 @@ setup() {
|
|||||||
<lay-button>tooltip</lay-button>
|
<lay-button>tooltip</lay-button>
|
||||||
</lay-tooltip>
|
</lay-tooltip>
|
||||||
</template>
|
</template>
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: title 外部控制
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: demo
|
||||||
|
<template>
|
||||||
|
<lay-button @click="visible = !visible">{{visible ? '显示' : '隐藏'}}</lay-button>
|
||||||
|
<div style="padding: 100px">
|
||||||
|
<lay-tooltip position="right" content="时光都淡了,我还伴着你。" :visible="visible">
|
||||||
|
<lay-button>tooltip</lay-button>
|
||||||
|
</lay-tooltip>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref,watch } from 'vue';
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
const visible = ref(false)
|
||||||
|
return {
|
||||||
|
visible,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
<style>
|
<style>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
::: title 显示位置
|
::: title 显示位置
|
||||||
|
Loading…
x
Reference in New Issue
Block a user