Skip to content

Commit

Permalink
fix: #1501
Browse files Browse the repository at this point in the history
  • Loading branch information
GleanCoder1116 authored and Wugaoliang committed Jan 6, 2021
2 parents 4547b2f + a8031d7 commit 733caad
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 64 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

## 3.3.1

- 优化组件弹出层自动计算合适的左右位置 [#1494](https://github.com/XiaoMi/hiui/issues/1494)
- 修复 `SelectTree` 搜索输入框在输入值时失焦问题 [#1491](https://github.com/XiaoMi/hiui/issues/1491)
- 修复 `Select` 组件分组形态 filterOption 函数无法使用问题 [#1497](https://github.com/XiaoMi/hiui/issues/1497)
- 修复 `Select` 组件分组形态全选以及受控问题 [#1501](https://github.com/XiaoMi/hiui/issues/1501)
- 修复 `Tabs` 组件垂直方向样式显示异常问题 [#1493](https://github.com/XiaoMi/hiui/issues/1493)
## 3.3.0
- 新增 `Card` 模式模式下 loading 加载中状态 [#1454](https://github.com/XiaoMi/hiui/issues/1454)
Expand Down
121 changes: 78 additions & 43 deletions components/popper/utils/positionUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,57 +60,93 @@ const positionAuto = (attachEleRect, popperHeight, popperRef, height, containerH
}
return placement
}
const getPlacement = (attachEleRect, container, props, state) => {
let { popperHeight, popperRef } = state

const caclLeftOrRightPlacement = (leftPlacement, rightPlacement, popperRef, widthConstant) => {
let { width, popperWidth, poperLeft, containerWidth, attachEleWidth } = widthConstant
let placement = rightPlacement
if (popperWidth === undefined) {
const clientWidth = popperRef || {}
popperWidth = clientWidth || 0
} // 自动探测边界,第一次时需设置为不可见,否则会闪跳,用来设置class hi-popper__content--hide
if (popperRef || width) {
// 元素已挂载到dom且当前popper处于显示状态
if (width) {
popperWidth = width
} else if (popperRef.clientWidth && popperWidth !== popperRef.clientWidth) {
popperWidth = popperRef.clientWidth
}
poperLeft = poperLeft + (popperWidth - (attachEleWidth || 0))
if (poperLeft >= containerWidth) {
placement = leftPlacement
}
}
return placement
}
// 计算popper在元素上面或下面
const caclBottomOrTopPlacement = (bottomPlacement, topPlacement, popperRef, heightConstant, widthConstant) => {
let { popperHeight, height, poperTop, containerHeight } = heightConstant
let placement = bottomPlacement
popperHeight === undefined && (popperHeight = 0) // 自动探测边界,第一次时需设置为不可见,否则会闪跳,用来设置class hi-popper__content--hide
if (popperRef || height) {
// 元素已挂载到dom且当前popper处于显示状态
if (height) {
popperHeight = height
} else if (popperRef.clientHeight && popperHeight !== popperRef.clientHeight) {
popperHeight = popperRef.clientHeight
}
poperTop += popperHeight
if (poperTop >= containerHeight) {
placement = topPlacement
}
}
const topOrbottom = placement === 'top-start' ? 'top' : 'bottom'
placement = topOrbottom + '-' + caclLeftOrRightPlacement('end', 'start', popperRef, widthConstant)
return placement
}
const getPlacement = (attachEleRect, container, props, state, attachEleWidth) => {
const { popperHeight, popperRef, popperWidth } = state
let { attachEle, placement, height, width = 0, leftGap = 0 } = props

if (!attachEle) return
let containerHeight = document.documentElement.clientHeight || document.body.clientHeight
let containerWidth = document.documentElement.clientWidth || document.body.clientWidth

if (isFixed(attachEle)) {
containerHeight = container.clientHeight
containerWidth = container.clientWidth
}
if (isBody(container)) {
containerHeight = document.documentElement.clientHeight || document.body.clientHeight
containerWidth = document.documentElement.clientWidth || document.body.clientWidth
}

let poperTop = attachEleRect.top + attachEleRect.height
const caclBottomOrTopPlacement = (bottomPlacement, topPlacement) => {
// 计算popper在元素上面或下面
placement = bottomPlacement
popperHeight === undefined && (popperHeight = 0) // 自动探测边界,第一次时需设置为不可见,否则会闪跳,用来设置class hi-popper__content--hide
if (popperRef || height) {
// 元素已挂载到dom且当前popper处于显示状态
if (height) {
popperHeight = height
} else if (popperRef.clientHeight && popperHeight !== popperRef.clientHeight) {
popperHeight = popperRef.clientHeight
}
poperTop += popperHeight
if (poperTop >= containerHeight) {
placement = topPlacement
}
}
}
const caclLeftOrRightPlacement = (leftPlacement, RightPlacement) => {
// 计算popper在元素上面或下面
placement = leftPlacement
const _width = popperRef ? popperRef.clientWidth : width
if (attachEleRect.right > _width + leftGap) {
placement = RightPlacement
}
if (attachEleRect.left > _width + leftGap) {
placement = leftPlacement
}
const poperTop = attachEleRect.top + attachEleRect.height
const poperLeft = attachEleRect.left + attachEleRect.width

const widthConstant = {
width,
popperWidth,
poperLeft,
containerWidth,
attachEleWidth,
leftGap
}
const heightConstant = {
popperHeight,
height,
poperTop,
containerHeight,
leftGap
}

if (placement === 'top-bottom-start') {
caclBottomOrTopPlacement('bottom-start', 'top-start')
placement = caclBottomOrTopPlacement('bottom-start', 'top-start', popperRef, heightConstant, widthConstant)
} else if (placement === 'top-bottom') {
caclBottomOrTopPlacement('bottom', 'top')
placement = caclBottomOrTopPlacement('bottom', 'top', popperRef, heightConstant, widthConstant)
} else if (placement === 'left-right-start') {
caclLeftOrRightPlacement('left-start', 'right-start')
placement = caclLeftOrRightPlacement('left-start', 'right-start', popperRef, widthConstant)
} else if (placement === 'left-right') {
caclLeftOrRightPlacement('left', 'right')
placement = caclLeftOrRightPlacement('left', 'right', popperRef, width, widthConstant)
} else if (placement === 'auto') {
positionAuto(attachEleRect, popperHeight, popperRef, height, containerHeight)
}
Expand All @@ -120,7 +156,7 @@ export const getOffset = (props, state, status) => {
let { attachEle, topGap, leftGap, width, container, preventOverflow } = props
if (!attachEle) return

const { popperHeight } = state
const { popperHeight, popperWidth } = state
let rect = attachEle.getBoundingClientRect()

if (isFixed(attachEle) && !isBody(container)) {
Expand All @@ -137,10 +173,9 @@ export const getOffset = (props, state, status) => {

let top = rect.top + _scrollTop
let left = rect.left + _scrollLeft

width = width === false ? '' : width === undefined ? rect.width : width

let placement = getPlacement(rect, container, props, state) || 'bottom-start'
const _width = width === false ? '' : width === undefined ? rect.width : width
width = width === false ? popperWidth : width === undefined ? rect.width : width
let placement = getPlacement(rect, container, props, state, rect.width) || 'bottom-start'
const rectHeight = rect.height
switch (placement) {
case 'bottom':
Expand Down Expand Up @@ -173,11 +208,11 @@ export const getOffset = (props, state, status) => {
break
case 'left-start':
top = top + topGap
left = left - rect.width
left = left - width
break
case 'left-end':
top = top + rect.height - topGap - popperHeight
left = left - rect.width
left = left - width
break

case 'right':
Expand All @@ -190,7 +225,7 @@ export const getOffset = (props, state, status) => {
break
case 'right-end':
top = top + rect.height - topGap - popperHeight
left = left + rect.width + leftGap
left = left + width + leftGap
break
}

Expand All @@ -199,7 +234,7 @@ export const getOffset = (props, state, status) => {
}

return {
width,
width: _width,
top,
left,
placement: placement
Expand Down
32 changes: 18 additions & 14 deletions components/select/Select.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import SelectInput from './SelectInput'
import SelectDropdown from './SelectDropdown'
import Provider from '../context'
import HiRequest from '../_util/hi-request'
import { resetSelectedItems, transKeys } from './utils'
import { resetSelectedItems, transKeys, uniqBy } from './utils'

const InternalSelect = (props) => {
const {
Expand Down Expand Up @@ -83,7 +83,7 @@ const InternalSelect = (props) => {
})
)
}
historyData.current = _.uniqBy(data.concat(dropdownItems, historyData.current), transKeys(fieldNames, 'id'))
historyData.current = uniqBy(data.concat(dropdownItems, historyData.current), transKeys(fieldNames, 'id'))
}, [dropdownItems, data])

useEffect(() => {
Expand All @@ -103,7 +103,7 @@ const InternalSelect = (props) => {
// 处理默认值的问题
const selectedItems = resetSelectedItems(
value,
_.uniqBy(cacheSelectItem.concat(dropdownItems), transKeys(fieldNames, 'id')),
uniqBy(cacheSelectItem.concat(dropdownItems), transKeys(fieldNames, 'id')),
transKeys(fieldNames, 'id')
)
setSelectedItems(selectedItems)
Expand Down Expand Up @@ -211,7 +211,8 @@ const InternalSelect = (props) => {
: dropdownItems[direction === 'down' ? 0 : l - 1][transKeys(fieldNames, 'children')]
focusedGroup[1] = direction === 'down' ? -1 : _dropdownItems.length
} else {
_dropdownItems = dropdownItems[focusedGroup[0]][transKeys(fieldNames, 'children')] || []
_dropdownItems =
(dropdownItems[focusedGroup[0]] && dropdownItems[focusedGroup[0]][transKeys(fieldNames, 'children')]) || []
_group = focusedGroup[0]
}
return { _dropdownItems, _focusedIndex: focusedGroup[1], group: _group }
Expand Down Expand Up @@ -519,17 +520,20 @@ const InternalSelect = (props) => {
}
const _selectedItems = [...selectedItems]
const changedItems = []
filterItems.forEach((item) => {
if (!item[transKeys(fieldNames, 'disabled')] && matchFilter(item)) {
if (
!_selectedItems
.map((selectItem) => selectItem[transKeys(fieldNames, 'id')])
.includes(item[transKeys(fieldNames, 'id')])
) {
_selectedItems.push(item)
changedItems.push(item)
filterItems.forEach((filterItem) => {
const filterItemOrGroupChilds = isArray(filterItem.children) ? filterItem.children : [filterItem]
filterItemOrGroupChilds.forEach((item) => {
if (!item[transKeys(fieldNames, 'disabled')] && matchFilter(item)) {
if (
!_selectedItems
.map((selectItem) => selectItem[transKeys(fieldNames, 'id')])
.includes(item[transKeys(fieldNames, 'id')])
) {
_selectedItems.push(item)
changedItems.push(item)
}
}
}
})
})
onChange(_selectedItems, changedItems, () => {})
}
Expand Down
21 changes: 17 additions & 4 deletions components/select/SelectDropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const SelectDropdown = ({
}) => {
const [filterItems, setFilterItems] = useState(dropdownItems)
const [searchbarValue, setSearchbarValue] = useState('')
const [ischeckAll, setIscheckAll] = useState(false)
const [isCheckAll, setIsCheckAll] = useState(false)
const searchbar = useRef('')
const dropdownWrapper = useRef('')
useEffect(() => {
Expand All @@ -51,13 +51,26 @@ const SelectDropdown = ({
group--
}
}
dropdownWrapper.current.scrollTop = (_focusedIndex - 6) * 36
const _scrollTop = dropdownWrapper.current.scrollTop
const focusedIndexTop = (_focusedIndex - 6) * 36
// 防止点击上下滚动问题
dropdownWrapper.current.scrollTop =
_scrollTop >= focusedIndexTop && focusedIndexTop > 0 ? _scrollTop : focusedIndexTop
}
}, [focusedIndex])

// 监控全选功能
useEffect(() => {
setIscheckAll(selectedItems.length > 0 && selectedItems.length === filterItems.length)
const selectedItemIds = selectedItems.map((item) => {
return item[transKeys(fieldNames, 'id')]
})
const _isCheckAll = filterItems.every((filterItem) => {
const filterItemOrGroupChilds = Array.isArray(filterItem.children) ? filterItem.children : [filterItem]
return filterItemOrGroupChilds.every((item) => {
return selectedItemIds.includes(item[transKeys(fieldNames, 'id')])
})
})
setIsCheckAll(_isCheckAll)
}, [selectedItems, filterItems])
// 让搜索框获取焦点
useEffect(() => {
Expand Down Expand Up @@ -306,7 +319,7 @@ const SelectDropdown = ({
<div>
{showCheckAll && (
<Checkbox
checked={ischeckAll}
checked={isCheckAll}
onChange={(e) => {
checkAll(e, filterItems, e.target.checked)
}}
Expand Down
1 change: 0 additions & 1 deletion components/select/SingleInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ const SingleInput = (props) => {
const selectedItems = propsSelectItem.length > 0 ? propsSelectItem : cacheselectedItems

placeholder = selectedItems.length > 0 ? selectedItems[0][transKeys(fieldNames, 'title')] : placeholder

return (
<div
className={classNames(
Expand Down
11 changes: 10 additions & 1 deletion components/select/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ export const resetSelectedItems = (value, dropdownItems = [], key) => {
const selectedItems = dropdownItems.filter((item) => {
return values.includes(item[key])
})

// 处理子节点
dropdownItems.forEach((item) => {
if (item.children) {
Expand All @@ -29,3 +28,13 @@ export const resetSelectedItems = (value, dropdownItems = [], key) => {
export const transKeys = (fieldNames, key) => {
return fieldNames[key] || key
}
export const uniqBy = (array, key) => {
const haseMap = {}
array.forEach((item) => {
const _key = typeof item.groupId !== 'undefined' ? item.groupId : item[key]
haseMap[_key] = item
})
return Object.keys(haseMap).map((key) => {
return haseMap[key]
})
}
3 changes: 2 additions & 1 deletion docs/demo/select/select-group.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ class Demo extends React.Component {
const {value,data} = this.state
return (
<Select
type='single'
type='multiple'
data={data}
placeholder='请选择'
showCheckAll
style={{ width: 200 }}
onChange={(item) => {
this.setState({
Expand Down

0 comments on commit 733caad

Please sign in to comment.