I am trying to display a div with the click of a button with slide effect. When something is clicked, it will toggle as shown or invisible with slide effect. I have achieved this so far by doing this.
class App extends Component {
constructor() {
super();
this.state = {
myclass: '',
}
this.divclicked = this.divclicked.bind(this);
}
divclicked() {
if (this.state.myclass === '') {
this.setState({
myclass: 'coolclass'
})
}
else {
this.setState({
myclass: '',
})
}
}
render() {
return (
<div className="App">
<div id="box" onClick={this.divclicked}>
</div>
<div id="seconddiv" className={this.state.myclass}>
<p>help help</p>
<p>help help</p>
<p>help help</p>
<p>help help</p>
<p>help help</p>
</div>
</div>
);
}
}
export default App;
And my CSS
#box {
height: 50px;
width: 50px;
background-color: red
}
#seconddiv.coolclass{
height:300px;
background: purple;
}
#seconddiv {
height: 0px;
transition: 0.5s;
overflow: hidden;
}
So here, when the red box with the id of "box" is clicked, I give the "seconddiv" a className and CSS takes care of hiding the div. The problem is that when I am giving the className coolclass, I do not want to use px but want to use percentage. So currently, it is going from 0px to 300px. But I want it to go from 0px to 100%; How do I achieve this. When I try to put the height of 100% in seconddiv, the slide animation doesn't work.
You need to set your initial height to 0%. You also need to give .App a height of 100% so that it stretches the full height of the window. In this example, I gave it a static height of 1200px, but that should be determined by the body.
class App extends React.Component {
constructor() {
super();
this.state = {
myclass: '',
}
this.divclicked = this.divclicked.bind(this);
}
divclicked() {
if (this.state.myclass === '') {
this.setState({
myclass: 'coolclass'
})
}
else {
this.setState({
myclass: '',
})
}
}
render() {
return (
<div className="App">
<div id="box" onClick={this.divclicked}>
</div>
<div id="seconddiv" className={this.state.myclass}>
<p>help help</p>
<p>help help</p>
<p>help help</p>
<p>help help</p>
<p>help help</p>
</div>
</div>
);
}
}
ReactDOM.render(<App/>,document.getElementById('root'));
#box {
height: 50px;
width: 50px;
background-color: red
}
#seconddiv.coolclass{
max-height:100%;
background: purple;
}
#seconddiv {
max-height: 0%;
transition: 0.5s;
overflow: hidden;
}
.App {
height: 100%;
}
#root {
height: 1200px;
}
<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>
You can just combine conditional rendering ( x && y ) with some scale animation
Example
const scaleAnimationIn = keyframes`
0% {
transform: scale(0, 1);
animation-timing-function: ease-out;
}
100% {
transform: scale(1, 1);
}
`
const QuestionHeaderPausedText = styled.div`
animation: ${scaleAnimationIn} 1s;
animation-delay: 7s;
animation-fill-mode: both;
`
In the return/render method just:
{isSomeConditionTrue && <QuestionHeaderPausedText>
My text
</QuestionHeaderPausedText>}
This example use Styled Components but the method (scaling) will work with any css solution.
Related
In ios9, when this two condition is true: the flexbox parent's max-height property was set and the flexbox child's flex-basic property was 0%, the the flexbox child's height go 0。
It only happen in ios9(maybe less then ios9). I have tested the system above ios9, it didnot happen. that is so wired.
my test code:
js code:
import React, {useEffect} from 'react';
import './styles.less';
export const Page: React.FC = () => {
useEffect(() => {
alert(`${document.querySelector('#containerWrapper').offsetHeight}`);
}, []);
return (
<div id='componentPageBg' className="component-page-bg">
<div id='containerWrapper' className="container-wrapper">
<div className="div-wrapper">
<div className="div1">div1</div>
</div>
<div className="div-wrapper">
<div className="div2">div2</div>
</div>
<div className="div-wrapper">
<div className="div3">div3</div>
</div>
</div>
</div>
);
};
export default Page;
css code
.component-page-bg {
display: flex;
flex-direction: column;
// max-height: 900px;
}
.container-wrapper {
flex: 0 1 0%;
}
.div-wrapper {
}
.div1 {
background-color: red;
height: 50px;
}
.div2 {
background-color: green;
height: 50px;
}
.div3 {
background-color: gray;
height: 50px;
}
my test data:
I am trying to make a slide out drawer utilizing the npm package react-transition-group. For whatever reason, I cannot seem to get the drawer to slide out from left to right on clicking the additional criteria button. If you can solve this issue without using the package, that is ok too!
Here is the code I am trying to get to work as a React component:
{/* DeveloperSearch.js */}
<CSSTransition
in={sidebarClicked}
appear
timeout={1000}
classNames="drawer"
mountOnEnter
unmountOnExit
>
<div className="DevSearch__additional-search-criteria">
Additional Search Criteria
<div className="DevSearch__additional-search-criteria-individual">
<div
style={{
fontSize: '0.8rem',
marginBottom: '5px',
fontWeight: 'bold',
}}
>
Only show people who match more than {criteriaMatch}% of all
search criteria
</div>
<input
className="form-control"
type="number"
value={criteriaMatch}
onChange={(e) => setCriteriaMatch(e.target.value)}
min={0}
max={100}
step={5}
/>
</div>
</div>
</CSSTransition>
I also have a css file that is specifically for the CSS Transition component called DeveloperSearch.css:
.drawer-exit {
width: 250px;
}
.drawer-exit.drawer-exit-active {
width: 250px;
transition: width 1000ms ease-in;
}
.drawer-exit-done {
width: 0px;
}
.drawer-enter {
width: 250px;
}
.drawer-enter.drawer-enter-active {
width: 250px;
transition: all 1000ms ease-in;
}
Unfortunately, my results are no where near what I was wanting, as the drawer does not seem to slide out at all...
I also have replicated this issue in a codesandbox that can be found by clicking here. Thanks for your help!
Here is a pure css based solution but this is a bit hacky
Markup
const Drawer = ({ transitionExit, handleExit }) => (
<div
onClick={handleExit}
className={`drawer ${transitionExit ? "exit" : ""}`}
>
<p>Home</p>
<p>About</p>
<p>Contact</p>
<p>Close Drawer</p>
</div>
);
export default function App() {
const [isOpen, setIsOpen] = useState(false);
const [transitionExit, setTransitionExit] = useState(false);
const handleExit = () => {
setTransitionExit(true);
setTimeout(() => {
setIsOpen(false);
setTransitionExit(false);
// timeout should be less than animation time otherwise state might still be true
// after animation ends and drawer appears for few milliseconds
}, 450);
};
return (
<div className="App">
<div className="wrapper">
<div className="sidebar_container">
<button onClick={() => setIsOpen(true)}>open</button>
</div>
{isOpen && (
<div className={`container ${transitionExit ? "exit" : ""}`}>
<Drawer handleExit={handleExit} transitionExit={transitionExit} />
</div>
)}
</div>
</div>
);
}
CSS
.wrapper {
height: 90vh;
max-width: 60vw;
display: grid;
grid-template-columns: 30% 70%;
overflow: hidden;
margin: 40px;
}
.sidebar_container {
width: 100px;
height: 100%;
background-color: rgb(250, 207, 213);
padding: 30px;
position: relative;
z-index: 30;
}
#keyframes containerTransitionEnter {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
#keyframes drawerTransitionEnter {
0% {
opacity: 0;
left: -10vw;
}
100% {
opacity: 1;
left: 0vw;
}
}
#keyframes containerTransitionExit {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
#keyframes drawerTransitionExit {
0% {
opacity: 1;
left: 0vw;
}
100% {
opacity: 0;
left: -10vw;
}
}
.container {
position: relative;
z-index: 10;
height: 90vh;
animation: containerTransitionEnter 0.5s;
}
.drawer {
box-sizing: border-box;
position: relative;
height: 90vh;
width: 25vw;
padding: 20px;
background-color: rgb(4, 118, 156);
border-right: 1px solid rgba(0, 0, 0, 0.3);
animation: drawerTransitionEnter 0.5s;
}
p {
margin-bottom: 10px;
color: white;
}
.container.exit {
animation: containerTransitionExit 0.5s;
}
.drawer.exit {
animation: drawerTransitionExit 0.5s;
}
Here is the link to codesandbox
Since you are using react you can use Material UI for this Here
and you can try this in your case
<Drawer
className={classes.drawer}
variant=''
anchor='left'
open={open}
classes={{
paper: classes.drawerPaper,
}}>
<div className={classes.drawerHeader}>
<IconButton onClick={handleDrawerClose}>
{theme.direction === 'ltr' ? (
<ChevronLeftIcon />
) : (
<ChevronRightIcon />
)}
</IconButton>
</div>
<Divider />
<List>
{arr.map((text, index) => (
<ListItem
button
key={text}
onClick={
text === 'Home'
? goToHome
: text === 'About'
? handleOpenAbout
: text === 'Contact'
? goToContact
: text == 'Team'
? goToMyTea,
: goToDashboard
}>
<ListItemIcon>
{text === 'Home' ? (
<HomeIcon />
) : text === 'About' ? (
<NoteAddIcon />
) : text === 'About' || text === 'Contact' ? (
<ListAltIcon />
) : text === 'Dashboard' ? (
<DashboardIcon />
) : (
<></>
)}
</ListItemIcon>
<ListItemText primary={text} />
</ListItem>
))}
</List>
</Drawer>
You should not delete div that has class="DevSearch__additional-search-criteria drawer-enter-done" from the DOM. In this case, Transition will not work. If you want to delete it, you must use css animation.
In this way, after adding div to the DOM, put animation on it to enter as a slider
In my code, I want to use the transition only when the width turns wider.
When the width decrease I don't want any animation.
can I do with CSS only? Add/remove classes is not an option for me.
function changeCss() {
document.getElementById('squareId').style.width = "300px";
}
function reset() {
document.getElementById('squareId').style.width = "100px";
}
.square {
background-color: red;
width: 100px;
height: 100px;
transition: width 1s linear;
}
<div id="squareId" class="square"></div>
<button onclick="changeCss()">increase</button>
<button onclick="reset()">decrease</button>
JSFiddle
Adjust the transition at the same time in the JS code:
window.changeCss = function() {
document.getElementById('squareId').style.transition = "width 1s linear";
document.getElementById('squareId').style.width = "300px";
}
window.reset = function() {
document.getElementById('squareId').style.transition = "none";
document.getElementById('squareId').style.width = "100px";
}
.square {
background-color: red;
width: 100px;
height: 100px;
}
<div id="squareId" class="square">
</div>
<button onclick="changeCss()">increase</button>
<button onclick="reset()">decrease</button>
I'm developing a single page application / mobile app, with Vue.JS. I want a slide effect when changing the pages, and I can do it like this:
transition name="slide"
router-view transition
transition
But I wanted the reverse effect of the slide when the user returns the page. In other words, when the user opens a new page, the page will come from the right, but when they go back, the page will come from the left.
There is a plugin for Vue router, called vue-router-transition, but it does not work. It is out of date, it only works with very old versions of Vue.
Also there is a tutorial on dynamic transitions, but only works when it is parents routes, ex: example.com/rota1/rota2/rota3, which is not my case.
I thought of the following logic in the before.each.router, set the transition class (slide-left or slide-right) depending on whether the user clicked on a go back button.
The problem is that I do not know how to apply this logic in code. I would have to pass the value of a variable that is in main.js to app.vue and I do not know how to do this.
A while ago I've used the meta object in vue-router and added a "fake" depth, because I haven't any children objects. If you use children, then go with this example: https://github.com/vuejs/vue-router/blob/dev/examples/transitions/app.js
export default () => {
return [{
meta: {
depth: 0
},
path: '/home',
component: Home
},
{
meta: {
depth: 1
},
path: '/about',
component: About
}]
}
Now you can check it by your own like this in your App.vue.
watch: {
$route(to, from) {
const toDepth = to.meta.depth || 0;
const fromDepth = from.meta.depth || 0;
this.transitionName = toDepth >= fromDepth ? 'slide-left' : 'slide-right';
}
}
I see 2 options:
Store a variable in Vuex "transitionBack" and set it to true. Change the router-link to a #click method. In the method, first save the variable and then navigate to the link. Check that variable on your beforeRouteUpdate(to, from, next) method.
Implement some logic in your beforeRouteUpdate(to, from, next) method that will check on the name of the link (e.g. if you can only go "back" from a certain page, then keep a list of all these type of pages)
Hope this helps:
new Vue({
el: '#demo',
data: {
slideTransition: 'slide-left',
showChild: false,
},
watch: {
showChild(value) {
if (value) {
this.setSlideTransition('slide-right');
} else {
this.setSlideTransition('slide-left');
}
},
},
methods: {
setSlideTransition(slideDirection) {
// Note: 300ms mentioned below is matching with css transition timing
setTimeout(() => { this.slideTransition = slideDirection; }, 300);
},
},
});
body {
margin: 0;
color: #bdbdbd;
background-color: #161616;
font-family: Helvetica neue, roboto;
}
.container {
width: 500px;
background: #161616;
}
main {
width: 60%;
height: 300px;
background-color: #333;
}
aside {
width: 40%;
background-color: #555;
}
.container, main, .parent, .child, .content {
display: flex;
align-items: center;
justify-content: center;
}
.parent {
background-color: deepskyblue;
}
.child {
background-color: deeppink;
}
.container, main, aside {
position: relative;
height: 199px;
}
.pin {
top: 0;
left: 0;
right: 0;
bottom: 0;
position: absolute;
}
.pt-50 {
padding-top: 50px;
}
/* transitions */
.fade-enter-active,
.fade-leave-active {
transition-property: opacity;
transition-duration: 0.25s;
}
.fade-enter-active {
transition-delay: 0.25s;
}
.fade-enter,
.fade-leave-active {
opacity: 0;
}
.slide-left-leave-active,
.slide-left-enter-active,
.slide-right-leave-active,
.slide-right-enter-active {
transition: 0.3s;
}
.slide-left-enter {
transform: translate(100%, 0);
}
.slide-left-leave-to {
transform: translate(-100%, 0);
}
.slide-right-enter {
transform: translate(-100%, 0);
}
.slide-right-leave-to {
transform: translate(100%, 0);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo" class="container">
<aside>
<transition name="fade">
<div class="pin parent" v-if="!showChild">
<div>
<h1>Parent</h1>
Go To Child
</div>
</div>
</transition>
<transition :name="slideTransition">
<div class="pin child" v-if="showChild">
<div>
<h1>Child</h1>
Go To Parent
</div>
</div>
</transition>
</aside>
<main>
<div>
<h1>Main</h1>
<transition name="fade">
<div v-if="showChild" class="pin content pt-50" key="child">
<h4>Child Content here</h4>
</div>
<div v-else="" class="pin content pt-50" key="parent">
<h4>Parent Content here</h4>
</div>
</transition>
</div>
</main>
</div>
In the case I have on toggle button that will bring this "mini drawer" that has some chips,
After pressing the Button
The issue in this case is that this chips just POP on the screen and I need to add some animation like this Drawer http://www.material-ui.com/#/components/drawer, I tried to add the transition and transform on CSS but It wont work
JS Part:
renderChip() {
console.log("1.30");
return this.state.listChip.map( (i, index) => (
<Chip className="chips">
{i.nome}
</Chip>
));
}
toggleList() {
this.setState({
visivel: !this.state.visivel,
});
// (this.state.visivel) ? document.getElementById("push").style.width = "0" : document.getElementById("push").style.width = "10px"};
}
render()
{
return (
<MuiThemeProvider>
<div >
<div className="anchor">
<RaisedButton
label="Label before"
labelPosition="before"
primary={true}
onClick = {this.toggleList}
/>
</div>
<div id="push" className="anchorz" style={(this.state.visivel) ? styles.wrapper : styles.closed} >
{this.renderChip()}
</div>
</div>
</MuiThemeProvider>
);
}
CSS part:
position: fixed;
display: flex;
right: 0;
bottom: 110px;
margin-right: 0;
margin-bottom: 0;
margin-left: 10px;
z-index: 900;
transition: transform 450ms cubic-bezier(0.23, 1, 0.32, 1) 0ms;*/
overflow-x: hidden;
transition: 0.5s;