New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: allow overflow in horizontal mode #159
Conversation
src/MenuItem.jsx
Outdated
}); | ||
// scrollIntoView(ReactDOM.findDOMNode(this), ReactDOM.findDOMNode(this.props.parentMenu), { | ||
// onlyScrollIfNeeded: true, | ||
// }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yesmeck do we still need this with the new feature?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
当然
src/DOMWrap.jsx
Outdated
if (selectedIndex !== -1 && selectedIndex > lastVisibleIndex) { | ||
const selectedIndexInOverflow = this.overflowedItems.findIndex(ele => ele.props.eventKey === this.childrenCache[selectedIndex].props.eventKey) | ||
const tmp = this.props.children[lastVisibleIndex - 1]; | ||
this.props.children[lastVisibleIndex] = this.overflowedItems[selectedIndexInOverflow]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might not be the best way since we're modifying this.props.children. Suggestions appreciated!
src/DOMWrap.jsx
Outdated
debouncedHandleResize = debounce(this.handleResize, 500); | ||
|
||
componentDidMount() { | ||
window.addEventListener('resize', this.debouncedHandleResize); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
window.addEventListener('resize', this.resize, { passive: true });
加上这个稍微提升点性能
src/DOMWrap.jsx
Outdated
return childNode; | ||
} else if (index === this.state.overflowingIndex) { | ||
// put all the overflowed item inside a submenu with a title of overflow indicator ('...') | ||
const copy = this.props.children[this.state.overflowingIndex]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
overflowingIndex 用了好多次
搞个临时变量比较好
39e584f
to
7672518
Compare
701f3ad
to
64ce8ba
Compare
@chenshuai2144 @yesmeck 再看下,加了test, 可以checkout出来感受下,看 examples/antd |
@@ -76,6 +76,7 @@ | |||
"babel-runtime": "6.x", | |||
"classnames": "2.x", | |||
"dom-scroll-into-view": "1.x", | |||
"lodash": "^4.17.10", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
可以直接引用 lodash/debounce 包
src/DOMWrap.jsx
Outdated
renderChildren(children) { | ||
// need to take care of overflowed items in horizontal mode | ||
if (this.props.mode === 'horizontal') { | ||
const lastVisibleIndex = this.state.lastVisibleIndex; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const { lastVisibleIndex} = this.state;
src/DOMWrap.jsx
Outdated
delete rest.visible; | ||
delete rest.prefixCls; | ||
delete rest.overflowedIndicator; | ||
delete rest.mode; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
为什么不直接在结构赋值就不要引入?
src/DOMWrap.jsx
Outdated
delete rest.visible; | ||
delete rest.prefixCls; | ||
delete rest.overflowedIndicator; | ||
delete rest.mode; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
为什么不直接在结构赋值就不要引入?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
为什么不呢
src/DOMWrap.jsx
Outdated
@@ -1,7 +1,7 @@ | |||
import React from 'react'; | |||
import ReactDOM from 'react-dom'; | |||
import PropTypes from 'prop-types'; | |||
import debounce from 'lodash/debounce'; | |||
import debounce from 'lodash.debounce'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why change this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
应该都可以?
e028ba3
to
5e1c8aa
Compare
package.json
Outdated
@@ -76,6 +76,7 @@ | |||
"babel-runtime": "6.x", | |||
"classnames": "2.x", | |||
"dom-scroll-into-view": "1.x", | |||
"lodash.debounce": "^4.0.8", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
统一用 lodash/debounce
,这样不会跟其他包重复装依赖。
src/DOMWrap.jsx
Outdated
}; | ||
|
||
componentDidMount() { | ||
this.setChildrenCache(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
children
变化了呢?
src/DOMWrap.jsx
Outdated
|
||
componentDidMount() { | ||
this.setChildrenCache(); | ||
this.setOverflowedIndicatorSize(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indicator
变化了呢?
src/DOMWrap.jsx
Outdated
} | ||
|
||
componentWillUnmount() { | ||
window.removeEventListener('resize', this.debouncedHandleResize); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
debounced 的方法最后一次调用要 cancel 掉。
this.debouncedHandleResize.cancel()
src/DOMWrap.jsx
Outdated
newState = { | ||
...newState, | ||
children: nextProps.children, | ||
childrenUpdated: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
不应该用这个状态,应该在 children 发生变化的时候直接更新 childrenCache
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个状态是为了让组件有机会重新直接渲染 children, 见 https://github.com/react-component/menu/pull/159/files#diff-e2fa48f75c2dd2318295cde428556a76R239, 否则没有机会拿到正确的 childrenCahe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
componentDidUpdate 里能直接比较 preProps.children === this.props.children
。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2b53cbf
to
c46b2d1
Compare
src/DOMWrap.jsx
Outdated
this.overflowedItems[selectedIndexInOverflow] = tmp; | ||
|
||
this.overflowedItems.splice(selectedIndexInOverflow, 1); | ||
this.overflowedItems.unshift(tmp); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/DOMWrap.jsx
Outdated
@@ -185,18 +173,6 @@ class DOMWrap extends React.Component { | |||
|
|||
lastVisibleIndex = lastVisibleIndex - 1; | |||
} | |||
|
|||
// try to hoist hidden selected item | |||
if (selectedIndex !== -1 && selectedIndex > lastVisibleIndex) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
先 revert 了,选中项被隐藏的场景比较多比较复杂,如果有 feature request 再考虑加进来吧 @yesmeck @chenshuai2144
e34879b
to
949614f
Compare
src/DOMWrap.jsx
Outdated
@@ -27,7 +28,7 @@ class DOMWrap extends React.Component { | |||
} | |||
|
|||
componentDidUpdate(prevProps) { | |||
if (prevProps.children !== this.props.children | |||
if (menuChildrenChanged(prevProps.children, this.props.children) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yesmeck 发现原来的版本在 antd 里每次hover children 都不一样,就会一致刷。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
什么意思,组件从父组件 render 过来的话 children 就是每次都不一样的。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
孙子节点有变化呢?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
我改成了比较 key,假定 key 变了才认为 menuItem 改变
奇怪的是只是 hover 在 menuItem 上,为什么会触发父组件的 render
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
孙子节点的变化不影响顶级的渲染啊
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
没懂,所以你认为目前的方案有问题么
我是说孙子节点要是变化了,并不需要updateChildrenCache,因为不会影响第一层MenuItems。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
class App extends React.Component {
render() {
return (
<Menu>
<Menu.Item key="1"><Foo /><Menu.Item>
</Menu>
);
}
}
App
重新 render,Foo 发生变化,这种情况,需不需要 updateChildrenCache
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
没意识到 MenuItem 的孩子才是真正的内容 Foo 发生变化咋比较好 不能直接比较 reference 否则每次都不一样,不比较 reference 比较啥啊?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
引用比较有什么问题?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
每次 componentDidUpdate 都会重新 setState,在 antd 里 hover �在一个 popup 上会闪
@chenshuai2144 @yesmeck ready to go!!!! |
FYI @afc163 |
好的,edge case 有点多,这个我到时候再加进去也计算一下 你先整体再确认一下,看实现有啥问题 |
const container = document.body.appendChild(document.createElement('div')); | ||
container.setAttribute('style', 'position: absolute; top: 0; visibility: hidden'); | ||
ReactDOM.render(this.props.overflowedIndicator, container, () => { | ||
this.overflowedIndicatorWidth = getWidth(container) + 40; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ReactDOM.unmountComponentAtNode(container)
src/DOMWrap.jsx
Outdated
}); | ||
|
||
this.originalScrollWidth = scrollWidth; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ReactDOM.unmountComponentAtNode(container)
@yesmeck 修复了 简化了代码 |
fix leftover corner cases fixing selected keys issue fix selected menuItem got hidden scenario cleaning up fix lint fix scroll into view fix more item eventkey issue and cleanup addressing corner cases extract getWidth and getScrollWidth for test adding test update tests update readme adding more docs fix lint address cr handle children or overflowedIndicator changes fix lint use componentDidUpdate rather than getDerivedStateFromProps update debounce time and example fix uncontrolled mode fixing lint and adding text try to keep order while hoisting hidden selected items revert hoisting selected keys
没啥问题,合了哈 |
addressing #148
TODO: