如何在单击时展开搜索图标并呈现我已经在代码中构建的搜索栏组件?
Posted
技术标签:
【中文标题】如何在单击时展开搜索图标并呈现我已经在代码中构建的搜索栏组件?【英文标题】:How to expand a search icon on click and render a search bar component I already built in my code? 【发布时间】:2022-01-20 07:08:47 【问题描述】:
所以基本上我拥有的是这个绿色的搜索图标,我希望能够单击它并呈现下面的搜索栏,这是我构建的一个组件。我想实现这样的目标:https://codepen.io/ahmadbassamemran/pen/rNjMXqg 但我确实很难弄清楚如何实现这一目标。样式方面,如何单击绿色图标并打开搜索栏输入组件,并通过单击搜索输入外部,搜索输入本身关闭?现在的问题是,如果我点击绿色图标,搜索栏就会出现,但是如果我点击搜索输入,搜索输入也会消失,因为我相信状态是在同一个容器上定义的。我怎样才能实现只有当我在输入之外单击并仅在输入关闭时才打开搜索栏时才会关闭输入?非常感谢您提供任何线索或提示。这是呈现绿色搜索图标的代码:
const [isExtended, setIsExtended] = useState(false); // this is for the search icon
const extendSearch = () =>
setIsExtended(!isExtended);
;
<Nav>
<h2 style= fontSize: '1.2em' >Add Time</h2>
<div style= display: 'flex'>
<SearchIconDiv onClick=extendSearch>
isExtended ? <SearchIcon /> : <SearchBar/>
</SearchIconDiv>
<div
onClick=() => setShowModal((prev) => !prev)
style=
marginLeft: '5px',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
>
<ClosingIcon />
</div>
</div>
</Nav>
我使用了样式化组件:
const Nav = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
position: fixed;
padding: 20px 40px 20px 40px;
top: 0px;
/* text-align: center; */
width: 100%;
background-color: white;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
align-items: center;
z-index: 100;
`;
const SearchIconDiv = styled.div`
margin-right: 5px;
cursor: pointer;
width: fit-content;
height: fit-content;
position: relative;
display: flex;
`;
这是搜索栏的完整组件,包括样式组件:
// react
import useState, useEffect, useRef from 'react';
// styled components
import styled from 'styled-components';
// framer motion
import motion, AnimatePresence from 'framer-motion';
// moon loader, spinner
import MoonLoader from 'react-spinners/MoonLoader';
// isOutisideClick
import useClickOutside from 'react-click-outside-hook';
// icons
import iosearch, IoClose from 'react-icons/io5';
import SearchIcon from '../../../Icons/SearchIcon';
const containerVariants =
expanded:
height: '20em',
zIndex: '200',
,
collapsed:
height: '3em',
,
;
const containerTransition = type: 'spring', damping: 22, stiffness: 150 ;
function SearchBar(props)
const [isExpanded, setExpanded] = useState(false);
const [parentRef, isClickedOutside] = useClickOutside();
const inputRef = useRef();
const [searchQuery, setSearchQuery] = useState('');
const [isLoading, setLoading] = useState(false);
const [contexts, setContexts] = useState([]);
const [noContexts, setNoContexts] = useState(false);
const isEmpty = !contexts || contexts.length === 0;
const changeHandler = (e) =>
e.preventDefault();
if (e.target.value.trim() === '') setNoContexts(false);
setSearchQuery(e.target.value);
;
const expandContainer = () =>
setExpanded(true);
;
const collapseContainer = () =>
setExpanded(false);
setSearchQuery('');
setLoading(false);
setNoContexts(false);
setContexts([]);
if (inputRef.current) inputRef.current.value = '';
;
useEffect(() =>
if (isClickedOutside) collapseContainer();
, [isClickedOutside]);
return (
<SearchBarContainer
animate=isExpanded ? 'expanded' : 'collapsed'
variants=containerVariants
transition=containerTransition
ref=parentRef
>
<SearchInputContainer>
<SearchInput
placeholder="Search for contexts"
onFocus=expandContainer
ref=inputRef
value=searchQuery
onChange=changeHandler
/>
<SearchIconDiv>
<SearchIcon />
</SearchIconDiv>
/* <AnimatePresence>
isExpanded && (
<CloseIcon
key="close-icon"
initial= opacity: 0
animate= opacity: 1
exit= opacity: 0
onClick=collapseContainer
transition= duration: 0.2
>
<IoClose />
</CloseIcon>
)
</AnimatePresence> */
</SearchInputContainer>
isExpanded && <LineSeperator />
isExpanded && (
<SearchContent>
isLoading && (
<LoadingWrapper>
<MoonLoader loading color="#000" size=20 />
</LoadingWrapper>
)
!isLoading && isEmpty && !noContexts && (
<LoadingWrapper>
<WarningMessage>Start typing to Search</WarningMessage>
</LoadingWrapper>
)
!isLoading && noContexts && (
<LoadingWrapper>
<WarningMessage>No contexts have been found</WarningMessage>
</LoadingWrapper>
)
!isLoading && !isEmpty && (
<>
/* contexts.map(( show ) => (
<TvShow
key=show.id
thumbanilSrc=show.image && show.image.medium
name=show.name
rating=show.rating && show.rating.average
/>
)) */
</>
)
</SearchContent>
)
</SearchBarContainer>
);
const SearchBarContainer = styled(motion.div)`
display: flex;
flex-direction: column;
width: 25em;
height: 3em;
background-color: #fff;
border-radius: 10px;
box-shadow: 0px 0px 11px 0px rgba(0, 0, 0, 0.1);
z-index: 200;
`;
const SearchInputContainer = styled.div`
width: 100%;
min-height: 3em;
display: flex;
align-items: center;
position: relative;
padding: 2px 15px;
`;
const SearchInput = styled.input`
width: 100%;
height: 100%;
outline: none;
border: none;
font-size: 16px;
color: #12112e;
font-weight: 500;
border-radius: 6px;
background-color: transparent;
&:focus
outline: none;
&::placeholder
opacity: 0;
&::placeholder
color: #bebebe;
transition: all 250ms ease-in-out;
`;
const SearchIconDiv = styled.span`
color: #bebebe;
font-size: 27px;
margin-right: 0px;
margin-top: 6px;
vertical-align: middle;
`;
const CloseIcon = styled(motion.span)`
color: #bebebe;
font-size: 23px;
vertical-align: middle;
transition: all 200ms ease-in-out;
cursor: pointer;
&:hover
color: #dfdfdf;
`;
const LineSeperator = styled.span`
display: flex;
min-width: 100%;
min-height: 2px;
background-color: #d8d8d878;
`;
const SearchContent = styled.div`
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
padding: 1em;
overflow-y: auto;
`;
const LoadingWrapper = styled.div`
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
`;
const WarningMessage = styled.span`
color: #a1a1a1;
font-size: 14px;
display: flex;
align-self: center;
justify-self: center;
`;
export default SearchBar;
【问题讨论】:
【参考方案1】:最简单的方法是制作 2 个单独的组件,带和不带文本输入字段,并设置一个“onClick”事件侦听器以在两者之间切换。
例子:
const [isActive, setIsActive] = useState(false);
// this is to be put into the return part
isActive? <ComponentWithInput/> : <JustTheIcon/>
而事件监听函数可能是这样的:
<JustTheIcon onClick= ()=> setIsActive(true) />
然后使用您选择的任何动画库为过渡设置动画
【讨论】:
谢谢 Mukul,我想过 - 但是当我尝试时,我遇到了问题:isExtended ?setIsExtended(!isExtended)
。我解决了这个问题,代码可以在这里看到:codesandbox.io/s/amazing-wozniak-25ht1?file=/src/App.js以上是关于如何在单击时展开搜索图标并呈现我已经在代码中构建的搜索栏组件?的主要内容,如果未能解决你的问题,请参考以下文章