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 中的值

Material-UI 中的 Autocomplete 组件不会导致任何渲染

在 Material-ui Autocomplete 组件上设置文本颜色、轮廓和填充