init
This commit is contained in:
@@ -0,0 +1 @@
|
||||
无样式的基础组件
|
||||
@@ -0,0 +1 @@
|
||||
export { default as NTooltip } from "./tooltip"
|
||||
@@ -0,0 +1,150 @@
|
||||
import { syncRefs, useVModel } from "@vueuse/core"
|
||||
import type { CSSProperties, PropType } from "vue";
|
||||
import { Teleport, Transition, computed, defineComponent, nextTick, reactive, ref, renderSlot, watch } from "vue"
|
||||
import { provideShow } from "../hooks/show"
|
||||
|
||||
export const tooltipProps = {
|
||||
popClass: {
|
||||
type: String
|
||||
},
|
||||
position: {
|
||||
type: String as PropType<"bottom" | "top" | "left" | "right" | "auto">,
|
||||
default: () => "auto"
|
||||
},
|
||||
offset: {
|
||||
type: Number,
|
||||
default: () => 8
|
||||
},
|
||||
lazy: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
},
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
}
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: "ITooltip",
|
||||
props: tooltipProps,
|
||||
emits: ["change", "update:visible"],
|
||||
setup(props, { slots, emit }) {
|
||||
const isOpen = ref(props.visible)
|
||||
|
||||
syncRefs(useVModel(props, "visible"), isOpen)
|
||||
|
||||
provideShow(isOpen)
|
||||
|
||||
let timer: NodeJS.Timeout
|
||||
|
||||
const triggerRef = ref<HTMLElement>()
|
||||
const popupRef = ref<HTMLElement>()
|
||||
|
||||
const dropdownPosition = reactive({ x: 0, y: 0 })
|
||||
|
||||
const isShow = computed(() => isOpen.value && triggerRef.value && popupRef.value && dropdownPosition.x + dropdownPosition.y > 0)
|
||||
|
||||
const dropdownStyle = computed<CSSProperties>(() => {
|
||||
return {
|
||||
left: `${dropdownPosition.x}px`,
|
||||
top: `${dropdownPosition.y}px`,
|
||||
visibility: isShow.value ? "visible" : "hidden"
|
||||
}
|
||||
})
|
||||
|
||||
const mounted = ref(false)
|
||||
|
||||
function onMouseover() {
|
||||
if (props.disabled) {
|
||||
return
|
||||
}
|
||||
timer = setTimeout(
|
||||
() => {
|
||||
isOpen.value = true
|
||||
emit("change", true)
|
||||
},
|
||||
props.lazy ? 800 : 100
|
||||
)
|
||||
}
|
||||
|
||||
function onMouseout() {
|
||||
if (props.disabled) {
|
||||
return
|
||||
}
|
||||
clearTimeout(timer)
|
||||
isOpen.value = false
|
||||
emit("change", false)
|
||||
}
|
||||
|
||||
function resize() {
|
||||
const trigger = triggerRef.value
|
||||
const popup = popupRef.value
|
||||
|
||||
if (!!trigger && !!popup) {
|
||||
const { width, height, left, top } = trigger.getBoundingClientRect()
|
||||
|
||||
const { clientWidth: pWidth, clientHeight: pHeight } = popup
|
||||
|
||||
let x = 0
|
||||
let y = 0
|
||||
|
||||
const offset = props.offset
|
||||
|
||||
switch (props.position) {
|
||||
case "auto":
|
||||
case "bottom":
|
||||
x = left + width / 2
|
||||
y = top + height + offset
|
||||
break
|
||||
case "top":
|
||||
x = left
|
||||
y = top - pHeight - offset
|
||||
break
|
||||
case "left":
|
||||
x = left - pWidth - offset
|
||||
y = top
|
||||
break
|
||||
case "right":
|
||||
x = left + width + offset
|
||||
y = top
|
||||
break
|
||||
}
|
||||
if (props.position == "auto") {
|
||||
x = window.innerWidth - x > 500 ? x + 20 : x - 20 - 310
|
||||
y = window.innerHeight - y > popup.offsetHeight + 50 ? y : window.innerHeight - (popup.offsetHeight + 50)
|
||||
}
|
||||
dropdownPosition.x = x
|
||||
dropdownPosition.y = y
|
||||
}
|
||||
}
|
||||
|
||||
watch(isOpen, val => {
|
||||
if (val) {
|
||||
mounted.value = true
|
||||
}
|
||||
nextTick(resize)
|
||||
})
|
||||
|
||||
return () => {
|
||||
return (
|
||||
<div {...{ onMouseout, onMouseover }} ref={triggerRef}>
|
||||
{renderSlot(slots, "default")}
|
||||
<Teleport to="body">
|
||||
<Transition name="dropdown" mode="out-in">
|
||||
{mounted.value && !props.disabled && (
|
||||
<div class={["i-popper z-999", props.popClass]} style={dropdownStyle.value} ref={popupRef}>
|
||||
{renderSlot(slots, "popper")}
|
||||
</div>
|
||||
)}
|
||||
</Transition>
|
||||
</Teleport>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user