11<script lang="ts">
2- import { defineComponent , h , VNode } from ' vue' ;
2+ import { defineComponent , h , VNode , Teleport , ref , Transition } from ' vue' ;
33import type { PropType } from ' vue' ;
44
5- function getFirstSlotVNode( vnodes ? : VNode []) {
6- if (vnodes != null ) {
7- return vnodes [0 ];
5+ function getFirstTriggerVNode( slots : any ) : VNode | null {
6+ if (slots . trigger != null ) {
7+ return slots . trigger () [0 ];
88 }
99 return null ;
1010}
1111
1212export default defineComponent ({
1313 props: {
14+ /** 触发方式: hover - 渲染, click - 点击 */
1415 trigger: {
1516 type: String as PropType <' hover' | ' click' >,
1617 default: ' hover' ,
1718 },
19+ /** 显示的内容,也可以通过写入默认 slot 修改显示内容 */
20+ content: String ,
1821 },
19- setup(props , { slots }) {
22+ setup(props , { slots , attrs }) {
23+ const show = ref (false );
24+ const posStyle = ref ({});
25+
2026 function handleMouseEnter(e : Event ) {
21- console .log (' mouseenter' );
27+ const $target = e .target as HTMLElement ;
28+ const rect = $target .getBoundingClientRect ();
29+ console .log (rect );
30+ console .log ($target .offsetParent .getBoundingClientRect ());
31+ posStyle .value = {
32+ top: 500 + ' px' ,
33+ left: ` ${rect .left }px ` ,
34+ };
35+ show .value = true ;
2236 }
2337
24- function hanldeMouseLeave(e : Event ) {
25- console .log (' mouseleave' );
38+ /** 鼠标离开事件 */
39+ function hanldeMouseLeave() {
40+ show .value = false ;
2641 }
2742
2843 function handleClick(e : Event ) {
2944 console .log (' click' );
3045 }
3146
3247 return () => {
33- const firstVNode = getFirstSlotVNode (
34- slots .default != null ? slots .default () : undefined ,
35- );
48+ const firstVNode = getFirstTriggerVNode (slots );
3649 if (firstVNode == null ) {
3750 return null ;
3851 }
@@ -43,7 +56,38 @@ export default defineComponent({
4356 } else {
4457 prop .onClick = handleClick ;
4558 }
46- return h (' div' , h (firstVNode , prop ));
59+ return [
60+ h (firstVNode , prop ),
61+ h (
62+ Teleport ,
63+ { to: ' body' },
64+ h (
65+ Transition ,
66+ { name: ' nt-opacity' },
67+ {
68+ default : () =>
69+ show .value
70+ ? h (
71+ ' div' ,
72+ {
73+ ... attrs ,
74+ class: [' nt-popover' , attrs .class ],
75+ style: [posStyle .value ],
76+ },
77+ [
78+ slots .default != null
79+ ? slots .default ()
80+ : props .content != null
81+ ? h (' span' , props .content )
82+ : null ,
83+ h (' span' , { class: ' nt-popover-arrow' }),
84+ ],
85+ )
86+ : null ,
87+ },
88+ ),
89+ ),
90+ ];
4791 };
4892 },
4993});
0 commit comments