Material UI Autocomplete-Popper 不会停留在渲染它的组件上
Posted
技术标签:
【中文标题】Material UI Autocomplete-Popper 不会停留在渲染它的组件上【英文标题】:Material UI Autocomplete- Popper not STUCk to the component which rendered it 【发布时间】:2021-05-25 22:01:44 【问题描述】:我的自动完成的当前输出在附加的视频链接中,当窗口滚动时,自动完成建议在页面周围跳舞:https://www.screencast.com/t/atbTdIaXpzu
我正在尝试将自动完成建议修复到自动完成控件,并且自动建议下拉菜单以某种方式粘在自动完成上,但自动完成中的滚动体验并不那么流畅
解决方案如下:
使用自动完成属性 PopperComponent =PopperMy
const PopperMy = function (props)
return <Popper ...props placement="bottom-start" disablePortal=true />;
;
或者这个 popperVariant :
<Popper
...props
disablePortal=true
placement="bottom-start"
popperOptions= positionFixed: true
/>
感谢任何建议和修复。谢谢!
在此处添加文件内容以供参考:
import React, useState, useEffect from "react";
import
TextInputField,
InputLabelField,
BoxField,
CustomWhiteTooltip,
from "../../atoms";
import Autocomplete,
createFilterOptions,
from "@material-ui/lab/Autocomplete";
import
IsArrayNotEmpty,
IsNotEmpty,
IsString,
IsObject,
IsFunction,
ThrowException,
IsObjectNotEmpty,
ObjectHasKey,
IsNotUndefined,
from "../../../utility";
import UserMessages from "../../../constants/UserMessages";
import TextField from "@material-ui/core/TextField";
import InfoIcon from "../../../resources/ThemeIcons";
import Popper from "@material-ui/core";
const TypeaheadField = (
id = "",
renderInputId = "",
listOptions,
mainListOptionsKey = IsString(mainListOptionsKey)
? mainListOptionsKey
: "title",
getPropertyFromSingleObject = IsString(getPropertyFromSingleObject)
? getPropertyFromSingleObject
: false,
//defaultSelected='',
isCreatable = false,
onChange,
addNewLabel = "Add",
disableClearable = false,
className = "",
textFieldClassName = "",
isSelectMultiple = false,
limitTags = -1,
filterSelectedOptions = true,
openOnFocus = true,
blurOnSelect = false,
labelAtTop = false,
labelClassName = "",
popupIcon,
size = "small",
disabled = false,
variant = "standard",
label = "",
required = false,
placeholder = "",
fullWidth = true,
value = "",
ChipProps = ,
inputLabelProps = ,
helperText = "",
error = false,
onBlur = "",
name = "",
tooltipMessage = "",
tooltipIcon = "",
...rest
) =>
/* Required props: listOptions, onChange */
const isListOptionsProvided = IsArrayNotEmpty(listOptions);
const isOnChangeProvided = IsFunction(onChange);
if (!isListOptionsProvided || !isOnChangeProvided)
//ThrowException(UserMessages.warnings.missingRequiredProps);
const [autovalue, setValue] = React.useState(value);
useEffect(() =>
const IsMultipleSelectAllowed = isSelectMultiple === true;
if (IsMultipleSelectAllowed)
setValue(autovalue && IsArrayNotEmpty(autovalue) ? autovalue : []);
else if (!IsMultipleSelectAllowed)
setValue(autovalue && IsNotEmpty(autovalue) ? autovalue : null);
, []);
const handleOnChange = (event, newValue) =>
let selectedValue = newValue;
if (newValue && IsObject(newValue))
if (newValue[mainListOptionsKey])
// Create a new value from the user input
if (newValue.type === "new")
if (IsString(listOptions[0]))
selectedValue = newValue.value;
listOptions.push(newValue.value);
else
selectedValue = newValue.value;
listOptions.push(
[mainListOptionsKey]: newValue.value,
);
else
const LastObject = IsArrayNotEmpty(newValue)
? newValue[newValue.length - 1]
: null;
const IsNewValueAdded =
LastObject && LastObject.type === "new" && LastObject.value;
if (IsNewValueAdded)
// Create a new value from the user input
const CurrentValues =
autovalue && IsArrayNotEmpty(autovalue) ? [...autovalue] : [];
if (IsString(listOptions[0]))
selectedValue = [...CurrentValues, LastObject.value];
listOptions.push(LastObject.value);
else
selectedValue = [
...CurrentValues,
[mainListOptionsKey]: LastObject.value ,
];
listOptions.push( [mainListOptionsKey]: LastObject.value );
setValue(selectedValue);
if (
getPropertyFromSingleObject !== false &&
isSelectMultiple === false &&
IsObjectNotEmpty(selectedValue) &&
ObjectHasKey(selectedValue, getPropertyFromSingleObject)
)
onChange(selectedValue[getPropertyFromSingleObject]);
return;
onChange(selectedValue);
;
const handleFilterOptions = (options, params) =>
const filter = createFilterOptions();
const filtered = filter(options, params);
// Suggest the creation of a new value
const IsSuggestNewValue = params.inputValue !== "" && isCreatable === true;
if (IsSuggestNewValue)
filtered.push(
value: params.inputValue,
type: "new",
[mainListOptionsKey]: `$addNewLabel "$params.inputValue"`,
);
return filtered;
;
const handleGetOptionLabel = (option) =>
if (typeof option === "string")
return option;
return option ? option[mainListOptionsKey] : null;
;
const handleGetOptionSelected = (option, value) =>
if (value && IsObject(value) && IsObjectNotEmpty(value))
return option[mainListOptionsKey] === value[mainListOptionsKey];
else if (
option &&
IsObject(option) &&
IsObjectNotEmpty(option) &&
value &&
IsString(value) &&
IsNotEmpty(value)
)
return option[mainListOptionsKey] === value;
else
return option === value;
;
const handleEmptyValue = (valueParam) =>
/**
* TODO:: Add these in utility folder.
*/
if (isSelectMultiple)
return value && IsArrayNotEmpty(value)
? value
: valueParam && IsArrayNotEmpty(valueParam)
? valueParam
: [];
else
if (IsObject(valueParam) || IsObject(value))
return IsNotUndefined(value) &&
value !== null &&
IsObjectNotEmpty(value)
? value
: IsNotUndefined(valueParam) &&
valueParam !== null &&
IsObjectNotEmpty(valueParam)
? valueParam
: null;
else if (IsString(valueParam) || IsString(value))
return IsNotEmpty(value)
? value
: IsNotEmpty(valueParam)
? valueParam
: null;
;
const handleOnBlur = () =>
if (IsFunction(onBlur))
onBlur();
;
const autocompleteValue = handleEmptyValue(autovalue);
const inputRequired =
required === true &&
(isSelectMultiple
? !IsArrayNotEmpty(autocompleteValue)
: !IsNotEmpty(autocompleteValue));
return (
<Autocomplete
className=className
multiple=isSelectMultiple
value=autocompleteValue
filterSelectedOptions=filterSelectedOptions
id=id
size=size
ChipProps=ChipProps
disableClearable=disableClearable
popupIcon=popupIcon
openOnFocus=openOnFocus
blurOnSelect=blurOnSelect
options=listOptions
limitTags=limitTags
onChange=handleOnChange
disabled=disabled
filterOptions=handleFilterOptions
getOptionLabel=handleGetOptionLabel
getOptionSelected=handleGetOptionSelected
name=name
onBlur=handleOnBlur
renderInput=(params) => (
<div>
<TextField
...params
id=renderInputId ? renderInputId : label
variant=variant
label=!labelAtTop && label
className=textFieldClassName
required=inputRequired
//onChange=()=>
placeholder=placeholder
fullWidth=fullWidth
InputLabelProps=inputLabelProps
helperText=helperText
error=error
/>
</div>
)
/>
);
;
export default TypeaheadField;
【问题讨论】:
【参考方案1】:我想了解更多关于您的代码的信息,以便获得更好的上下文。第一个建议是使用道具 anchorEl 并引用您的 Textfield。您可以在此处的文档中找到有关它的更多信息和示例:
https://material-ui.com/es/components/popper/
而且我不知道你是否直接使用自动完成组件,如果你是,请告诉我。
【讨论】:
感谢您的时间@LittleOrange。基本上,我写了一个通用自动完成,它消耗了自动完成变体(分组,限制标签)可以拥有的所有可能的道具。我在我的应用程序中引用了这个。在我上面的主要问题中添加了 AutComplete 的整个源代码。 我分享的 Popper 代码只是为了修复自动完成的选项,否则我实际上不需要它。我宁愿让自动完成功能在 UI 中自行执行默认选项。但遗憾的是,这里并非如此。以上是关于Material UI Autocomplete-Popper 不会停留在渲染它的组件上的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Material-ui 中的 onFocus 上隐藏 Autocomplete 的标签?
将 Material-UI 的 Autocomplete 组件与 Formik 一起使用
Material-ui <Autocomplete /> getOptionLabel - 将空字符串作为值传递
获取 React Material-UI Autocomplete 中的值