#css #reactjs #styled-components
Вопрос:
Я работаю над Next.js проект, в котором меню открывается нажатием кнопки «бургер». Для этого я переключаю класс на кнопку, и стили для этого класса используют компоненты стиля.
Когда я нажимаю на кнопку, она меняется, как и ожидалось, но когда я добавляю переход CSS, он все еще не анимирован. Я протестировал тот же код в ванильном HTML, и он хорошо работает.
Где я ошибся?
Это мой код:
Бургер js:
<BurgerStyled
onClick={() => setIsBurgerOpen(!isBurgerOpen)}
className={BurgerOpen}
>
<span />
<span />
<span />
</BurgerStyled>
Поведение при нажатии:
const [isBurgerOpen, setIsBurgerOpen] = useState(false);
const BurgerOpen = isBurgerOpen ? "BurgerOpen" : "";
Стилизованный компонент:
const BurgerStyled = styled.div`
width: 32px;
height: 21px;
position: relative;
span {
position: absolute;
left: 0;
background-color: var(--gray);
width: 100%;
height: 3px;
transition: all 0.3s ease;
amp;:first-child {
top: 0;
}
amp;:nth-child(2) {
top: calc(50% - 3px / 2);
}
amp;:last-child {
bottom: 0;
}
}
amp;.BurgerOpen span {
amp;:first-child {
transform: rotate(45deg);
}
amp;:nth-child(2) {
width: 0;
}
amp;:last-child {
transform: rotate(-45deg);
}
}
`;
Спасибо за ваши ответы!
Комментарии:
1. Я думаю, что переход CSS работает только с
hover
селектором.
Ответ №1:
Вы можете передать свойство своему стилизованному компоненту следующим образом:
JSX:
return (
<BurgerStyled
onClick={() => setIsBurgerOpen(!isBurgerOpen)}
open={isBurgerOpen}
>
<span />
<span />
<span />
</BurgerStyled>
);
Стиль:
const BurgerStyled = styled(({ open, ...restProps }) => <div {...restProps} />)`
${({ open }) => open ? ` styles open here ` : ` styles closed here `};
`;
Что вы здесь делаете: вы передаете open
реквизит своему стилизованному компоненту, а затем передаете все остальные реквизиты в div. open
Реквизит теперь доступен в строке шаблона вашего стиля. Это предотвращает open
передачу реквизита в DOM-элемент, поскольку <div>
DOM-элемент не имеет open
свойства, поэтому передача его в DOM приведет к появлению предупреждений.
Ответ №2:
Вы можете попробовать svg
и перейти, чтобы получить желаемый результат. Проверьте мой пример кода ниже, это может вам помочь.
import { motion } from './framer-motion'; //install it with npm
const [isBurgerOpen, setIsBurgerOpen] = useState(false);
const HamburgerMenuContainer = styled.div`
display:flex;
`;
const MenuContainer = styled.div`
min-width:300px;
width:100%;
max-width:44%;
height:100%;
background-color: #fff;
box-shadow: -2px 0 2px rgba(15,15,15,0.3);
z-index:90;
position:fixed;
top:0;
right:0;
user-select:none;
padding: 1em 2.5em;
`;
const Button = styled.button`
z-index:99;
cursor:pointer;
`;
const Path = props =>{
<motion.Path fill="transparent" strokeLinecap="round" strokeWidth="3" {...props}/>
}
const transition = {duration: 0.3};
return (
<>
<HamburgerMenuContainer>
<Button onClick={() => setIsBurgerOpen(true)}>
<svg width="23" height="23" viewBox="0 0 23 23">
<Path animate={isBurgerOpen ? "open" : "closed"} initial={false} variants={{
closed: {d: "M 2 2.5 L 20 2.5",stroke:"hsl(0, 0%, 100%)"},
open: {d: "M 3 16.5 L 17 2.5",stroke:"hsl(0, 0%, 18%)"},
}}
transition={transition}
/>
<Path animate={isBurgerOpen ? "open" : "closed"} initial={false} variants={{
closed: {d: "M 2 2.5 L 20 2.5",stroke:"hsl(0, 0%, 100%)"},
open: {d: "M 3 16.5 L 17 2.5",stroke:"hsl(0, 0%, 18%)"},
}}
transition={transition}
/>
<Path animate={isBurgerOpen ? "open" : "closed"} initial={false} variants={{
closed: {d: "M 2 2.5 L 20 2.5",stroke:"hsl(0, 0%, 100%)"},
open: {d: "M 3 16.5 L 17 2.5",stroke:"hsl(0, 0%, 18%)"},
}}
transition={transition}
/>
</svg>
</Button>
</HamburgerMenuContainer>
</>
);
}
Ответ №3:
Я мог бы решить эту проблему. Мой компонент гамбургера был за пределами заголовка, вот так:
function Header() {
const Burger = () => {
// Burger component
}
return (
<Burger />
)
}
Я просто сформулировал это так, и это сработало:
function Header() {
return (
<BurgerStyled ...>
<span />
<span />
<span />
</BurgerStyled>
// Content header
)
}
Теперь анимация работает, спасибо за ваши ответы!