我有一个齿轮图标,我想在激活时顺时针旋转180度(class =“ cards__cog cards__cog-active”),然后再顺时针旋转180deg以返回其停用状态(class =“ cards__cog cards__cog-inactive”)。我正在用React进行此操作,以应对单击齿轮时的状态变化。
以下方法可行,但我的问题是:
1)它会在页面加载时进行动画处理(这是有道理的,因为它具有cards__cog-inactive类,但有什么选择呢?)。
2)这很丑陋,必须有一种更简单的方法。
谢谢
.cards {
&__cog {
position: absolute;
right: 20px;
top: 20px;
width: 10vh;
cursor: pointer;
&-active {
animation: rotate180 1s ease;
animation-fill-mode: forwards;
}
&-inactive {
animation: rotate180to359to0 1s ease;
animation-fill-mode: forwards;
}
}
}
@keyframes rotate180 {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(180deg);
}
}
@keyframes rotate180to359to0 {
0% {
transform: rotate(180deg);
}
99% {
transform: rotate(359deg);
}
100% {
transform: rotate(0deg);
}
}
答案 0 :(得分:7)
您可以对其中一种动作使用过渡。但是两者都不一样,因为其中之一会倒退。
由于问题一,您不能将动画用于初始状态。
这使我们处于非活动状态,处于360度,因此它可以以正确的方式从180过渡到360,并且动画从0变为180,以便从非活动状态变为活动状态
function change () {
var elem = document.getElementById("test");
elem.classList.toggle('active');
}
.test {
width: 200px;
height: 100px;
border: solid 4px red;
margin: 20px;
transform: rotate(360deg);
transition: transform 1s;
}
.active {
animation: activate 1s;
transform: rotate(180deg);
}
@keyframes activate {
from {transform: rotate(0deg);}
to {transform: rotate(180deg);}
}
<div class="test" id="test">TEST</div>
<button onclick="change();">change</button>
答案 1 :(得分:5)
如果图标是对称的,则可以考虑2个元素并进行这样的过渡。
var e = document.querySelector('.box');
e.addEventListener('click',function() {
e.classList.toggle('active');
})
.box {
display:inline-block;
margin:20px;
transition:0s .5s;
}
.box > i {
transition:.5s;
color:red;
display:block;
}
.box.active {
transform:scaleX(-1);
}
.box.active i{
transform:rotate(180deg);
}
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css">
<div class="box">
<i class="fas fa-cog fa-7x"></i>
</div>
答案 2 :(得分:5)
您已经提到您正在使用React。考虑到这一点,您可以尝试将旋转逻辑从CSS移到组件本身。这样做,您将不需要其他类,keyframes
等。在这种情况下,仅需要transition
和transform
组合。
class Cog extends React.Component {
state = {
isActive: false,
togglesCount: 0
}
get rotationValue () {
return `${this.state.togglesCount * 180}deg`
}
get cogStyle () {
return {
transition: 'transform 1s',
transform: `rotateZ(${this.rotationValue})`
}
}
toggle = () => {
this.setState(s => ({
isActive: !s.isActive,
togglesCount: ++s.togglesCount
}))
}
render() {
return (
<button onClick={this.toggle}>
<i className="fas fa-cog fa-3x" style={this.cogStyle}/>
</button>
)
}
}
ReactDOM.render(<Cog />, document.getElementById('root'))
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css">
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root" />
对于仅css的解决方案,您可以对父元素使用transition
和rotateY(-180deg)
hack:
.icon {
display: inline-block;
}
.icon__inner {
transition: transform 1s;
}
input:checked + .icon {
transform: rotateY(-180deg);
}
input:checked + .icon .icon__inner {
transform: rotateZ(-180deg);
}
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css">
<input type='checkbox' />
<div class="icon">
<i class="icon__inner fas fa-cog fa-3x"></i>
</div>
答案 3 :(得分:2)
这是另一个答案。因为我没有齿轮,所以我使用三角形
toggle.addEventListener("click", () => {
cog.className = (cog.className == "" || cog.className == "inactive") ? "active" : "inactive"
});
#cog{
margin:0 auto;
width:108px;
outline:1px solid;
transform-origin: 54px 108px;
}
#triangle{
outline:1px solid;
border:25px solid transparent;
border-bottom:100px solid green;
width:0px;
height:1px;
position:relative;
margin:auto;
}
#triangle::before{
content:"";
width:16px;
height:16px;
background:red;
display:block;
position:absolute;
bottom:-108px;
left:-8px;
border-radius:50%;
}
@keyframes rotate1 {
100% {
transform: rotate(180deg);
}
}
@keyframes rotate2 {
0% {
transform: rotate(180deg);
}
100% {
transform: rotate(360deg);
}
}
#cog.active{animation: rotate1 1s ease;
animation-fill-mode: forwards;}
#cog.inactive{animation: rotate2 1s ease;
animation-fill-mode: forwards;}
<div id="cog" class="">
<div id="triangle"></div>
</div>
<input type="button" value="toggle-class" id="toggle" />
答案 4 :(得分:0)
由于您使用的是React,因此您可能更喜欢使用Component。继续使用<button>
和动画样式,可以将持久按钮状态与过渡状态分开,这样动画仅在单击时发生,而在重新加载时不发生。
// Image src https://upload.wikimedia.org/wikipedia/commons/thumb/9/97/Twemoji_1f61d.svg/200px-Twemoji_1f61d.svg.png
const SMILEY_PNG = 'data:image/png;base64,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';
class AnimatedIcon extends React.Component {
constructor() {
super();
this.state = {
active: false,
transitionStyle: {}
};
}
render() {
// On click set new state and add transition styling
const onclk = () => {
this.setState({
active: !this.state.active,
transitionStyle: this.state.active ? {animation: 'rotate-from-180 1s ease'} : {animation: 'rotate-to-180 1s ease'}
});
};
return (
<button onClick={onclk} className={this.state.active ? 'active' : 'inactive'}>
<img src={SMILEY_PNG} style={this.state.transitionStyle} />
ClickMe
</button>
);
}
}
ReactDOM.render( <AnimatedIcon /> , document.getElementById('root'));
button {
margin: 10px;
font-size: 20pt;
color: red;
}
button img {
padding: 10px;
vertical-align: middle;
}
.active {
color: green;
}
.active img {
transform: rotate(180deg);
}
@keyframes rotate-to-180 {
from { transform: rotate(0deg); }
to { transform: rotate(180deg); }
}
@keyframes rotate-from-180 {
from { transform: rotate(180deg); }
to { transform: rotate(360deg); }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>