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

dropdown源码分析 -- ant-design-vue系列

组件结构

dropdown 组件对参数做了一些处理,然后直接调用了vc-trigger组件来进行渲染,先看一下整体的组件调用结构。

在这里插入图片描述

极简实现

这个组件需要满足以下几个基本的功能:

  1. 可以传入两个插槽 default popupdefault 是默认展示的节点,点击后可以弹出 popup
  2. popup 可以指定在文档中的位置,默认是插入到body节点下面。
  3. popup 可以相对于 default 来进行定位。

效果如下:

在这里插入图片描述

同时,popup也插入到了body节点下面。

在这里插入图片描述

简易代码

先看一下整体的数据流转过程,用户传入的两个插槽是如何渲染到页面中的。这两个查擦的传递过程需要仔细看一下。

在这里插入图片描述

接下来逐步解释一下从底层到上层的代码。

Align.tsx

  1. 用户传入的信息就是default插槽的内容,给它套一个div节点,用来获取引用,方便定位。
return () => {const child = slots.default?.();if (child) {return <div ref={nodeRef}>{child}</div>;}return null;
};
  1. 当组件挂载或者挂载位置变化的时候,调用对齐的方法。
onMounted(() => {align();
});watch(() => [props.align, props.target],() => {align();},{ immediate: true, deep: true, flush: 'post' }
);
  1. 上面用到了一个方法align,这个方法的主要作用就是让用户传入的 default 节点和target对齐。targetprops传入的节点;default 被手动加的一层div包裹,通过ref来进行代理。
import { alignElement } from 'dom-align';const nodeRef = ref<HTMLElement | null>(null);const align = () => {if (!nodeRef.value) return;const { align: latestAlign, target: latestTarget } = props;let result: any;let targetElement: HTMLElement | null = null;if (typeof latestTarget === 'function') {targetElement = latestTarget();}if (targetElement && targetElement.nodeType === Node.ELEMENT_NODE) {result = alignElement(nodeRef.value, targetElement, latestAlign);}
};

🥇 定位是通过dom-align实现的,地址如下:https://yiminghe.me/dom-align/ 。具体用法请见后选源码章节。

PopupInner.tsx

主要是增加一个动画效果,用户传入的popup直接传递到Align组件。同时也要通过props 把定位的target传递下去。

return () => (<Transition>{props.visible ? (<Align align={props.align} target={props.target}>{slots.default?.()}</Align>) : null}</Transition>
)

Popup.tsx

主要作用是增加一个蒙层。但是dropdown这个组件不使用蒙层,所以先注释掉。

return () => {if (!props.visible) return null;return (<div class="v-popup">{/* <Mask visible /> */}<PopupInner target={props.target} align={props.align} visible>{slots.default?.()}</PopupInner></div>);
};

Trigger.tsx

  1. 需要接受用户传入的defaultpopupdefault 需要拿到引用,传递到Align组件进行定位;popup传递到Popup组件中。
  2. 用户的定位传递的是"top"、"topRight"等字符串,需要转换成 dom-align需要的配置对象。
const align: any = computed(() => {const { placement } = props;return placements[placement];
});const getComponent = () => {return (<Popupstyle={{ position: 'absolute' }}target={() => triggerRef.value!}align={align.value}visible={props.visible}>{slots.popup?.()}</Popup>);
};const triggerRef = ref<HTMLElement>();return () => {const portal = <Portal>{getComponent()}</Portal>;const trigger = (<div style={{ display: 'inline-block' }} ref={triggerRef}>{slots.default?.()}</div>);return (<>{portal}{trigger}</>);
};

源码分析

🎯 代码较多,后续会分开每个组件写一篇源码解析文档。


http://www.mrgr.cn/news/20767.html

相关文章:

  • LLM 进化分岔口:多模态、成本、代码推理
  • RockyLinux8.9上yum安装redis6
  • python 打包tkinter图标问题
  • vue metamask 获取钱包地址
  • shell脚本编写之函数
  • 目标检测-YOLOv4
  • C 语言内存管理语法全解析(malloc、calloc、free)
  • 笔记整理—uboot番外(6)针对x210的网卡说明
  • 蓄水池漂浮物识别摄像机
  • 为什么 2!=false 和 2!=true 返回的都是true
  • C# 加解密之RSA
  • 828华为云征文 | Flexus X实例与华为云EulerOS的Tomcat安装指南
  • 文本字符分割算法尝试
  • React-CSS
  • C++ 在给定斜率的线上找到给定距离处的点(Find points at a given distance on a line of given slope)
  • iOS——APP启动流程
  • 【C语言从不挂科到高绩点】13-二维数组以及数组元素增加和删除
  • 盘古信息IMS MOM,高效灵活的企业数字化解决方案
  • 开放式运动耳机好不好用?超靠谱好评榜单实物测评
  • 美团面试:mysql 索引失效?怎么解决? (重点知识,建议收藏,读10遍+)