如何使用react根据输入简化用户建议的下拉列表?

时间:2019-07-05 06:00:43

标签: reactjs

我想根据用户输入显示建议下拉列表。以下代码可在3种情况下正常工作。

->用户仅输入@ char会显示所有用户建议

-> @,然后出现“ @user”字样,显示使用“ user”过滤的用户建议

->如果@根据光标位置和@之后的字符串(在光标位置过滤用户建议之前)在输入中的任意位置输入@(输入可能包含多个@)。

这可行,但我想进一步简化一下。有人可以帮我吗。谢谢。

class User extends React.PureComponent {
    state = {
        text: '',
        suggestions: [],
    };
    user_list =  [
        {name: 'user1'},
        {name: 'user2'},
    ];

    handle_input_change = (event) => {
        const {value} = event.target;
        if (value.includes('@') && value.indexOf('@') === value.length - 
        1) {
            this.setState({
                [event.target.name]: value,
                suggestions: [...this.user_mention_list],
            });
        } else if (value.includes('@') && value.length > 1) {
            let string_after_at;
            if (event.target.selectionStart > value.lastIndexOf('@')) {
                string_after_at = value.slice(value.lastIndexOf('@') + 
                1).toLowerCase();
            }

            if (event.target.selectionStart <= 
            event.target.value.indexOf('@') && event.target.selectionStart 
            <= event.target.value.lastIndexOf('@')) {
                this.setState({
                    [event.target.name]: value,
                    suggestions: [],
                 });
            }

            if (event.target.selectionStart > value.indexOf('@') && 
            event.target.selectionStart <= value.lastIndexOf('@')) {
                let string_after_cursor_position = 
                value.substr(event.target.selectionStart, value.length - 
                1).split(' ')[0];
                if (string_after_cursor_position.startsWith('@')) {
                    string_after_cursor_position = '';
                }
                const string1 = value.substr(0, 
                event.target.selectionStart);
                const string_from_at = 
                string1.slice(string1.lastIndexOf('@') + 1);
                string_after_at = string_from_at + 
                string_after_cursor_position ;
            }
            const new_suggestions = this.user_mention_list.filter(user => 
            {
                return user.name.toLowerCase().includes(string_after_at);
            });
            this.setState({
                [event.target.name]: value,
                suggestions: new_suggestions,
            });
        } else {
               this.setState({
                   [event.target.name]: value,
                   suggestions: [],
               });
        }
    };

    render = () => {
        return (
            <form onSubmit={this.handle_submit}>
                <input
                    name="text"
                    value={this.state.text}
                    onChange={this.handle_input_change}/>
                {this.state.suggestions.length > 0 &&
                    <Select
                        on_change={this.handle_select_value}
                        values={this.state.suggestions}/>}
            </form>);
     }
 }

谢谢。

1 个答案:

答案 0 :(得分:0)

查看是否适合您

enter image description here

function App() {

  const inputRef = React.useRef(null);
  const [inputValue, setInputValue] = React.useState('');
  const [userList,setUserList] = React.useState([
    {name: 'John Joe', username:'johnjoe'},
    {name: 'Jane Jannet', username:'janejannet'},
    {name: 'Jack Daniels', username:'jackdaniels'}
   ]
  );
  const [partialMention,setPartialMention] = React.useState(null);
  const [showSuggestions,setShowSuggestions] = React.useState(false);
  
  const [suggestionList,setSuggestionList] = React.useState(
    ['johnjoe','janejannet','jackdaniels']
  );
  
  function onChange(event) {
    const regexp = /@[a-zA-Z0-9]*$/;
    if (regexp.test(event.target.value)) {
      setPartialMention(event.target.value.split('@').pop());
      setShowSuggestions(true);
    }
    else {
      setShowSuggestions(false);
    }
    setInputValue(event.target.value);
  }
  
  function focusInput() {
    inputRef.current.focus();
  }

  return(
    <React.Fragment>
      <input ref={inputRef} type='text' value={inputValue} onChange={onChange}/>
      {showSuggestions && 
        <Suggestions
          inputValue={inputValue}
          suggestionList={suggestionList}
          applyMention={onChange}
          focusInput={focusInput}
          partialMention={partialMention}
        />
      }
    </React.Fragment>
  );
}

function Suggestions(props) {
  
  function selectSuggestion(username) {
    const regexp = /@[a-zA-Z0-9]*$/;
    const newValue = props.inputValue.replace(regexp,username + ' ');
    props.applyMention({target: {value: newValue}}); // THIS MIMICS AN ONCHANGE EVENT
    props.focusInput();
  }
  
 
  const suggestionItems = props.suggestionList
  .filter((item) => item.includes(props.partialMention))
  .map((item) => 
    <div className="item" onClick={()=>selectSuggestion('@' + item)}>@{item}</div>
  );
  
  return(
    <div className="container">
      {suggestionItems}
    </div>
  );
}


ReactDOM.render(<App/>, document.getElementById('root'));
.container {
  border: 1px solid silver;
  width: 150px;
}

.item {
  cursor: pointer;
}

.item:hover {
  color: blue;
}

input {
  width: 300px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>