#javascript #reactjs #antd
Вопрос:
Я пытаюсь реализовать раскрывающуюся функциональность с использованием компонентов ANTD, таких как:
- Если в поле ввода есть какой-то текст, должно отображаться выпадающее меню.
- Когда я нажимаю за пределами раскрывающегося списка, раскрывающийся список должен закрыться.
- Когда я нажимаю на раскрывающееся меню, раскрывающееся меню не должно закрываться.
- Если в поле ввода нет текста, раскрывающийся список не должен открываться.
- Раскрывающийся список не должен закрываться при нажатии на поле ввода, если там есть какой-то текст.
Я не могу выполнить 5-е требование. Всякий раз, когда я нажимаю на поле ввода, раскрывающийся список открывается и закрывается, как показано здесь:
Этого не должно произойти.
Пример рабочего кода:
state = {
visible: false,
searchInput: null
};
handleVisibleChange = flag => {
if (!this.isDefined(this.state.searchInput)) {
this.removeDropdown();
} else {
this.setState({ visible: flag });
}
};
removeDropdown = () => {
this.setState({ visible: false });
};
showDropdown = () => {
this.setState({ visible: true });
};
checkInput = value => {
if (this.isDefined(value)) {
this.setState({ searchInput: value });
this.showDropdown();
} else {
this.setState({ searchInput: null });
this.removeDropdown();
}
};
render() {
const menu = (
<Menu>
<Menu.Item key="1">Clicking me will not close the menu.</Menu.Item>
<Menu.Item key="2">Clicking me will not close the menu also.</Menu.Item>
<Menu.Item key="3">Clicking me will not close the menu.</Menu.Item>
</Menu>
);
return (
<Dropdown
overlay={menu}
trigger={['click']}
onVisibleChange={this.handleVisibleChange}
visible={this.state.visible}
>
<Search
value={this.state.searchInput}
onInput={e => this.checkInput(e.target.value)}
/>
</Dropdown>
);
}
Полный код: https://stackblitz.com/edit/react-srz4ml?file=index.js
Я пробовал использовать onBlur()
и onFocus()
методы вместо onVisibleChange()
, но это нарушает 3-е требование.
Может кто-нибудь, пожалуйста, помочь мне в этом?
Спасибо.
Ответ №1:
Я немного поэкспериментировал с этим, и, похоже, не существует супер простого способа сделать это, но я смог заставить его работать с некоторым уродливым управлением государством. https://stackblitz.com/edit/react-srz4ml-p6faxs?file=index.js Надеюсь, вы сможете придумать более чистое решение.
state = {
searchInput: null,
isVisable: false,
clickedPrevState: false
};
render() {
const getNewState = (prevState, event, value) => {
console.log(prevState, event, value);
let newState = { ...prevState, clickedPrevState: false };
switch (event) {
case 'input':
newState.isVisable = value ? true : false;
newState.searchInput = value;
break;
case 'clicked':
if (prevState.searchInput) {
newState.isVisable = true;
newState.clickedPrevState = true; // used by next getNewState to determine if it was a click on input
} else newState.isVisable = false;
break;
case 'change':
if (prevState.searchInput amp;amp; (value || prevState.clickedPrevState)) {
newState.isVisable = true;
} else newState.isVisable = false;
break;
default:
newState.isVisable = false;
}
return newState;
};
const menu = (
<Menu>
<Menu.Item key="1">Clicking me will not close the menu.</Menu.Item>
<Menu.Item key="2">Clicking me will not close the menu also.</Menu.Item>
<Menu.Item key="3">Clicking me will not close the menu.</Menu.Item>
</Menu>
);
return (
<Dropdown
overlay={menu}
trigger={['click']}
visible={this.state.isVisable}
onVisibleChange={flag =>
this.setState(prevstate => {
return getNewState(prevstate, 'change', flag);
})
}
onClick={e =>
this.setState(prevstate => {
return getNewState(prevstate, 'clicked');
})
}
>
<Search
value={this.state.searchInput}
onInput={e =>
this.setState(prevstate => {
return getNewState(prevstate, 'input', e.target.value);
})
}
/>
</Dropdown>
);
}
Комментарии:
1. Я попробовал ту же логику в своем проекте, но сначала
onVisibleChange
запускается, а затемonClick
событие (в данной песочнице кода порядок меняется на противоположный). Поэтому, когда я сначала нажимаю на поле поиска, событие изменения устанавливается в значениеclickedPrevState
false, а затем событие щелчка устанавливает состояние в значение true. Поэтому, если я нажму снаружиclickedPrevState
, на данный момент это все еще верно, и выпадающий список не исчезнет. Если я нажму еще раз, он закроется. Есть ли возможность изменить порядок срабатыванияonClick
иonVisisbleChange
событий?2. Интересно, что это было бы наоборот. Это могут быть разные версии antd. Вам придется изменить логику, если это так. Просто глядя на это без тестирования, я думаю, что это должно сработать, просто удалив всю логику с помощью clickedPrevState. Когда я тестирую его, события, похоже, являются частью одного и того же цикла рендеринга, поэтому должны работать, не вызывая мерцания меню.