下拉选择组件从内部组件到 ant-design 不得不说的三个故事
2017-12-09 11:58
4003 查看
前言
昨天接到了第一个需求吧,目标就是一句话:把 @mtfe/react-dropdown 组件替换为 antd 的Select组件
用图来说就是从
到
分解一下工作点
表现当长度过长时,不会出现滚动条,而是向左或向右扩展
正常的过滤以及选择功能
具体实现:
要求 组件自由配置输入框与下拉框宽度样式 灵活配置下拉框相对位置
输入字符过滤,键盘上下键和回车可以在下拉框中控制选择内容
明确之后就可以具体开工了
步骤
一:熟悉旧代码
事情也比较简单,暂时需求只是替换页面一个组件,所以大致浏览一下页面代码,主要集中注意力到旧组件的逻辑
当然可能这里更难的是进行咱们美团内部 git 初始化,总之 clone 下仓库之后还是比较顺利的
二:熟悉ant-design
以前用过一些ant-design,所以简单熟悉一下各种 API,Select 中文文档还是说的比较直观的,说实话各种语法糖还是比较多的,这也是 ant 除了外观设计不错之外值得称道的点,不过过度设计和功能简洁实用之间度其实才是最难的点吧,虽然个人不太懂,但据说 ant 还是比较吊的,另外最近好像开始 SSE conf 报名了,感觉大神云集,想去看看啊,咳咳跑题了,总之设计要在 易用强大和过度设计之间取舍还是比较难的,希望自己有机会可以学习一下。
当阅读文档时还是比较顺利的,第二条(正常的过滤以及选择功能)ant 原生提供,所以这就完全不必费心,不得不再赞一个,功能确实比较强大,整体设计也简单、人性化
至于第一条,好像也可以很简单的解决了,直接用第二三个属性配置一下就就好了。ok,文章结束了
显然这个题目表示这篇文章尚未结束,第三个属性坑爹的失效了。
三:有一点问题
antd 的 dropdown 组件是相对页面绝对定位,并且是 JS 动态设置位置的,所以首先你得想办法把它的动态 left 属性干掉,否则你的 right: 0永远都不可能生效。
所以让我们看看 antd Select 里面是怎么实现的,我们的 dropdownStyle 属性最后在哪里生效
首先相同的是,为了扩展性,你传入的 props 一般来说都会被传到最底层的组件上
寻根溯源,是 react-component 中 Select 仓库中,SelectTrigger.jsx 中将其进行了处理
这段代码就是 dropdownMatchSelectWidth 生效的代码,如果传入 true,那么就将 width 写死,只能与输入框同宽;如果输入false,那么只是设置一个 min-width,限制宽度其不会小于输入框。
至于其他属性下面又将样式属性传给了 react-Trigger 组件,并最后设置生效,但位置属性是比较特殊的,antd 并没有将这些属性交给开发者控制。
似乎我们的路走到了尽头?换个思路,antd 内部一定存在使用 left 进行定位的逻辑,那么底层有没有这个接口呢,根据它的设计原理,我们只需要在最上层添加这个属性,那么层层传递下去后,一定会被这个属性的逻辑所应用
四:新思路,可有这个接口吗?
答案是有的,在 react-select 中发现其props中有 dropdownAlign 属性,马上跟踪了上去,到最后其实是到了react-align 组件上,他是参照 @yiminghe 的 @dom-align规则,所以最终的代码是
关键位置通知代码在 dropdownAlign,point内成员分别代表 target source 相对的位置,实现的效果是:在 left、top、right、bottom属性为零时,让 target element 的上边和右边与 souce element 的底边和右边对齐,更详细的可以看前面的 dom-align 规则,overflow 则表示 dropdown 不会覆盖输入框
至此需求其实就算暂时完成了,不过我还想另外再考量两个备选方案
五:来两个备选?
很容易想到的是,研究一下源码,在底层可能是用一种比较简单的方法整合在 react-select 中,而我们可以另辟蹊径,用两个组件 Input、Dropdown 组合形成一个下拉框筛选功能,这样样式的问题就比较好解决了,只是中间要加上 组件间数据联动的逻辑。
贴一个大概的框架
初步的效果如下:
数据同步的逻辑就忽略了,数据绑定的双向通信一般来说还是比较容易的,在 Search 中绑定 onChange 确定要展现的 Menu ,在 Dropdown 上绑定点击事件改变 Search 的 value。
另外,之前我们提过下拉框是相对容器进行定位的,而容器由 getPopupContainer 方法控制,默认是绑定在 body 上,相对于页面定位。
在 issue 中有人提出用 getPopupContainer 方法,改变 Dropdown 的容器为自己的 DOM,然后改变容器的定位,以此来随意控制下拉框的位置变化,这种方法显然也是适用于我们的需求的
总结一个,最后其实就是三个方案
推荐方案,其底层封装组件 rc-select 提供 dropdownAlign 接口(类 DOM-align 接口),目前发现存在 CSS 冲突
替代方案,使用 antd 组件 input + dropdown 组合实现功能,需要添加数据同步等逻辑
替代方案(antd issue 讨论区方案),借助 getPopupContainer 替换位置定位容器,并设置好相对定位
antd使用遇到问题的一般解决思路,一路封装上来其实很多扩展性的东西不会开放,只会对内使用,封装层次越高,设计程度越高,功能集成越强,那么考虑到设计原则冲突,必然留下的更多的通用、强大、简洁、实用的接口,这都是必然现象,所以我们解题的一般思路是
看文档,不要遗漏重要细节
看源码,了解他才能更好的使用它
看issue,你踩过的坑大多数都已经被人踩过了
开issue,真到了开issue的时候,恭喜你,或许你已经走到了绝大多数人前面,或许你也可以考虑提 PR,成为contributeor,从此名利双收,迎娶白富美,走上人生巅峰,成为人生赢家
昨天接到了第一个需求吧,目标就是一句话:把 @mtfe/react-dropdown 组件替换为 antd 的Select组件
用图来说就是从
到
分解一下工作点
表现当长度过长时,不会出现滚动条,而是向左或向右扩展
正常的过滤以及选择功能
具体实现:
要求 组件自由配置输入框与下拉框宽度样式 灵活配置下拉框相对位置
输入字符过滤,键盘上下键和回车可以在下拉框中控制选择内容
明确之后就可以具体开工了
步骤
一:熟悉旧代码
事情也比较简单,暂时需求只是替换页面一个组件,所以大致浏览一下页面代码,主要集中注意力到旧组件的逻辑
当然可能这里更难的是进行咱们美团内部 git 初始化,总之 clone 下仓库之后还是比较顺利的
二:熟悉ant-design
以前用过一些ant-design,所以简单熟悉一下各种 API,Select 中文文档还是说的比较直观的,说实话各种语法糖还是比较多的,这也是 ant 除了外观设计不错之外值得称道的点,不过过度设计和功能简洁实用之间度其实才是最难的点吧,虽然个人不太懂,但据说 ant 还是比较吊的,另外最近好像开始 SSE conf 报名了,感觉大神云集,想去看看啊,咳咳跑题了,总之设计要在 易用强大和过度设计之间取舍还是比较难的,希望自己有机会可以学习一下。
当阅读文档时还是比较顺利的,第二条(正常的过滤以及选择功能)ant 原生提供,所以这就完全不必费心,不得不再赞一个,功能确实比较强大,整体设计也简单、人性化
至于第一条,好像也可以很简单的解决了,直接用第二三个属性配置一下就就好了。ok,文章结束了
显然这个题目表示这篇文章尚未结束,第三个属性坑爹的失效了。
三:有一点问题
antd 的 dropdown 组件是相对页面绝对定位,并且是 JS 动态设置位置的,所以首先你得想办法把它的动态 left 属性干掉,否则你的 right: 0永远都不可能生效。
所以让我们看看 antd Select 里面是怎么实现的,我们的 dropdownStyle 属性最后在哪里生效
首先相同的是,为了扩展性,你传入的 props 一般来说都会被传到最底层的组件上
const { prefixCls, className = '', size, mode, ...restProps, } = this.props; <RcSelect {...restProps} // 其他略 />
寻根溯源,是 react-component 中 Select 仓库中,SelectTrigger.jsx 中将其进行了处理
const popupStyle = { ...dropdownStyle }; const widthProp = dropdownMatchSelectWidth ? 'width' : 'minWidth'; if (this.state.dropdownWidth) { popupStyle[widthProp] = `${this.state.dropdownWidth}px`; }
这段代码就是 dropdownMatchSelectWidth 生效的代码,如果传入 true,那么就将 width 写死,只能与输入框同宽;如果输入false,那么只是设置一个 min-width,限制宽度其不会小于输入框。
至于其他属性下面又将样式属性传给了 react-Trigger 组件,并最后设置生效,但位置属性是比较特殊的,antd 并没有将这些属性交给开发者控制。
似乎我们的路走到了尽头?换个思路,antd 内部一定存在使用 left 进行定位的逻辑,那么底层有没有这个接口呢,根据它的设计原理,我们只需要在最上层添加这个属性,那么层层传递下去后,一定会被这个属性的逻辑所应用
四:新思路,可有这个接口吗?
答案是有的,在 react-select 中发现其props中有 dropdownAlign 属性,马上跟踪了上去,到最后其实是到了react-align 组件上,他是参照 @yiminghe 的 @dom-align规则,所以最终的代码是
<Select> showSeach style={{ width: 100% }} placeholder="-- 不限 --" optionFilterProp="children" filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0} dropdownMatchSelectWidth={false} dropdownAlign={{ points: ['tr', 'br'], overflow: false, }} // 生成 <Option> </Select>
关键位置通知代码在 dropdownAlign,point内成员分别代表 target source 相对的位置,实现的效果是:在 left、top、right、bottom属性为零时,让 target element 的上边和右边与 souce element 的底边和右边对齐,更详细的可以看前面的 dom-align 规则,overflow 则表示 dropdown 不会覆盖输入框
至此需求其实就算暂时完成了,不过我还想另外再考量两个备选方案
五:来两个备选?
很容易想到的是,研究一下源码,在底层可能是用一种比较简单的方法整合在 react-select 中,而我们可以另辟蹊径,用两个组件 Input、Dropdown 组合形成一个下拉框筛选功能,这样样式的问题就比较好解决了,只是中间要加上 组件间数据联动的逻辑。
贴一个大概的框架
const { Menu, Dropdown, Icon, Input 4000 } = antd; const Search = Input.Search; const menu = ( <Menu> <Menu.Item> <a target="_blank" rel="noopener noreferrer" href="http://www.alipay.com/">1st menu item</a> </Menu.Item> <Menu.Item> <a target="_blank" rel="noopener noreferrer" href="http://www.taobao.com/">2nd menu item</a> </Menu.Item> <Menu.Item> <a target="_blank" rel="noopener noreferrer" href="http://www.tmall.com/">3rd menu item</a> </Menu.Item> </Menu> ); ReactDOM.render( <Dropdown overlay={menu} placement='bottomRight'> <Search style={{width: 100}} /> </Dropdown> , mountNode);
初步的效果如下:
数据同步的逻辑就忽略了,数据绑定的双向通信一般来说还是比较容易的,在 Search 中绑定 onChange 确定要展现的 Menu ,在 Dropdown 上绑定点击事件改变 Search 的 value。
另外,之前我们提过下拉框是相对容器进行定位的,而容器由 getPopupContainer 方法控制,默认是绑定在 body 上,相对于页面定位。
在 issue 中有人提出用 getPopupContainer 方法,改变 Dropdown 的容器为自己的 DOM,然后改变容器的定位,以此来随意控制下拉框的位置变化,这种方法显然也是适用于我们的需求的
总结一个,最后其实就是三个方案
推荐方案,其底层封装组件 rc-select 提供 dropdownAlign 接口(类 DOM-align 接口),目前发现存在 CSS 冲突
替代方案,使用 antd 组件 input + dropdown 组合实现功能,需要添加数据同步等逻辑
替代方案(antd issue 讨论区方案),借助 getPopupContainer 替换位置定位容器,并设置好相对定位
收获
antd 底层的了解 包括比较原始的 react-component 组件,高楼大厦的基石往往最美,罗马不是一天建成的,大概在15年 react 比较火的时候,其实很多基础组件就已经有了,一直积累到现在的 n 个好用组件的 antd@3.0,也支持到最新的 react 16antd使用遇到问题的一般解决思路,一路封装上来其实很多扩展性的东西不会开放,只会对内使用,封装层次越高,设计程度越高,功能集成越强,那么考虑到设计原则冲突,必然留下的更多的通用、强大、简洁、实用的接口,这都是必然现象,所以我们解题的一般思路是
看文档,不要遗漏重要细节
看源码,了解他才能更好的使用它
看issue,你踩过的坑大多数都已经被人踩过了
开issue,真到了开issue的时候,恭喜你,或许你已经走到了绝大多数人前面,或许你也可以考虑提 PR,成为contributeor,从此名利双收,迎娶白富美,走上人生巅峰,成为人生赢家
相关文章推荐
- Android组件-下拉列表、时间选择器、日期选择器、单选框、复选框
- vue省市区三联动下拉选择组件的实现
- Extjs2. 4000 0.2 datefield 日期组件在点击选择日期时下拉面板在chrome, firefox中样式乱掉的解决办法
- 下拉列表选择移动组件(jquery)
- ant-design-pro Login 组件 实现 rules 验证
- ant-design在create-react-app中配置按需加载组件
- C#.NET通用管理系统后台管理组件中选择组织机构选择功能增加默认选择内部组织机构的功能
- Android实现Ant Design 自定义表单组件
- 实现Ant Design 自定义表单组件
- 令人不得不深思的三个真实故事
- ant-design getFieldDecorator 无法获取自定义组件的值
- 令人不得不深思的三个真实故事
- 关于微信小程序下拉刷新组件加载图片(三个小点)不显示的问题
- 下拉列表选择移动组件(jquery)
- vue省市区三联动下拉选择组件的实现
- 下拉列表选择移动组件(jquery)
- [置顶] 下拉列表选择移动组件(jquery)
- C#.NET通用管理系统后台管理组件中选择组织机构选择功能增加默认选择内部组织机构的功能
- ant-design-vue组件的三种加载方式
- 《自定义组件》下拉快速选择组件