Element is pushed away in list move transition when content is scrolled - vue.js

I'm trying to display a one line list of elements.
This list is browsed using the scrollbar.
Each element can be removed on click with a transtion making it go up and fade.
I came up with the following code:
new Vue({
el: '#container',
data: { blocks: [1, 2, 3, 4, 5, 6, 7] }
})
#container {
position: relative;
height: 100px;
width: 200px;
border: 1px solid black;
overflow-x: scroll;
}
.block {
position: absolute;
bottom: 0px;
height: 40px;
width: 40px;
background-color: blue;
cursor: pointer;
}
.rise-fade-leave-active,
.rise-fade-move {
transition: all 0.5s ease;
}
.rise-fade-leave-to {
transform: translateY(-40px);
opacity: 0;
}
<script src="https://unpkg.com/vue#2.6.11/dist/vue.min.js"></script>
<div id="container">
<transition-group name="rise-fade" tag="div">
<div v-for="(b, i) in blocks"
v-bind:key="b"
v-bind:style="{ left: i*50 + 'px' }"
v-on:click="blocks.splice(i, 1)"
class="block">
</div>
</transition-group>
</div>
But if I scroll to the most right and click on any visible element except the last one, the element seems to be pushed to the right during the list move transition.
Is there a way to prevent this?
I would like to have my element rising just vertically no matter the scroll value.

Related

How to give a fixed position div a z-index

I'm working on a website that has a lot of z-index values and I'm trying to make a Drag & Drop menu that you can move around but stays in the screen space at all times. But because the drag & drop menu would have a fixed position it breaks the z-index positioning (it reveals borders that it wouldn't if it was positioned absolute).
I understand that you can't position a fixed element with z-index but do you guys maybe know a workaround for it?
Here is the JS fiddle of what I have so far (I left the header in):
https://jsfiddle.net/wdeyvb7q/
HTML:
<div id="menu-container">
<div id="draggable3" class="draggable ui-widget-content">
<p>I'm a very confused box, position fixed on my container breaks the style.</p>
</div>
</div>
CSS (with #menu-container absolute):
#menu-container {
width: calc(90vw - 94px);
height: calc(100vh + 8px);
top: -4px;
position: absolute;
left: calc(5vw + 47px);
}
.draggable {
background: white;
width: 100%;
height: 90px;
float: left;
position: absolute;
z-index: 200;
border-top: 4px solid black;
border-bottom: solid black;
}
#draggable, #draggable2 {
margin-bottom:0px;
}
#draggable {
cursor: n-resize;
}
JS:
$( function() {
$( "#draggable3" ).draggable({ containment: "#menu-container", scroll: false });
} );
And here are 2 screenshots of an absolute & fixed position
I solved it! I removed both inner borders of the sidebars and added 2 divs floating left and right. By positioning those divs under the menu code in the HTML file it will stay under the menu, so I added a border on each side and that didn't break the design =)!
JSFiddle: https://jsfiddle.net/adf2gte7/
HTML:
<!-- Left And Right Inner Borders -->
<div class='left-border-menu'></div>
<div class='right-border-menu'></div>
CSS:
/* Inner Borders */
.left-border-menu {
width: calc(5vw + 47px);
height: 2000px;
background: orange;
float: left;
border-right: 4px solid black;
}
.right-border-menu {
width: calc(5vw + 47px);
height: 2000px;
background: orange;
float: right;
border-left: 4px solid black;
}

v-show or v-if div shifted the others div into the parent container

I would like to add dynamically image (check arrow) into a div which contains other div information (image + texte).
This adding means that users owned this "object" in the application. He can added or deselected this object on the fly.
The result of this action is appear or disappear arrow on the fly.
This process run perfectly in my vue.js component. But I can view appear an offset each time that arrow appears like this :
I try to use v-if or v-show vue.js directives but the result is the same.
I don't want to have a new offset appear when action to checked item is launch.
this is the HTML template :
<div id="container">
<div #click="checkedItem(key.id)" class="container-item" v-for="(key, value) in objects">
<div class="check" v-show="checked[key.id]">
<img height="35" width="35" src="../../../static/checked.png"></img>
</div>
<div class="image">
<img src="https://picsum.photos/75/75/?image=25" alt="logo"></img>
</div>
<div class="name">{{ key.name }}</div>
</div>
</div>
This is the CSS stylesheet component :
<style scoped>
#container
{
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.container-item
{
display: flex;
flex-direction: row;
margin: 30px 30px 30px 30px;
}
.container-item div.check
{
z-index: 3;
position: relative;
left: 20px;
bottom: 15px;
}
.container-item div.check > img
{
height: 35px;
width: 35px;
}
.container-item div.image
{
z-index: 2;
border: 1px solid blue;
}
.container-item div.name
{
z-index: 1;
position: relative;
top: 12px;
right: 10px;
text-align: center;
line-height: 45px;
width: 150px;
max-height: 50px;
border: 1px solid blue;
background-color: yellow;
}
</style>
And the checkedItem method component :
checkedItem: function (id)
{
let isChecked = this.checked[id] ? true : false
isChecked ? this.checked[id] = false : this.checked[id] = true
},
How can "add" DOM node HTML into HTML template component vue.js whitout create a new offset on the fly ?
As we have discussed in the comments, this is purely a CSS thing. What you want is to take div.check out from the layout flow, so that it does not influence the positioning of other elements. This can be done by adding position: absolute to its ruleset. For that to work, remember to add position: relative to its parent, too:
.container-item {
display: flex;
flex-direction: row;
margin: 30px 30px 30px 30px;
/* Allow div.check to be positioned relative to its parent */
position: relative;
}
.container-item div.check {
z-index: 3;
left: 20px;
bottom: 15px;
/* Take the check icon out of layout flow */
position: absolute;
}

Stop event listener from listing to children elements in Vue

I'm creating a modal in Vue, which I want to to be able to close whenever the user clicks outside of the inner modal container. The problem is when I add an event listener on click to the parent element all children elements also trigger that event listener when clicked.
I created a simple demo below to demonstrate my problem. If the user clicks on the black portion of the parent element the modal should close but the containing white space of the child element shouldn't be able to trigger the close function.
new Vue({
el: '#modal',
data: {
active: true,
},
methods: {
closeModal() {
this.active = false
}
}
})
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
justify-content: center;
align-items: center;
background-color: black;
}
.modal.active {
display: flex;
}
.modal-content {
width: 200px;
height: 200px;
padding: 1rem;
background-color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="modal" class="modal" :class="{active: active}" v-on:click="closeModal">
<div class="modal-content">This child element shouldn't be able to close the modal on click.</div>
</div>
You can try
v-on:click.self=...
Should only trigger if the target element is itself.
Hope that helps
I endorse kimy82's answer. Use click.self. Snippet updated.
new Vue({
el: '#modal',
data: {
active: true,
},
methods: {
closeModal(event) {
this.active = false
}
}
})
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
justify-content: center;
align-items: center;
background-color: black;
}
.modal.active {
display: flex;
}
.modal-content {
width: 200px;
height: 200px;
padding: 1rem;
background-color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="modal" class="modal" :class="{active: active}" v-on:click.self="closeModal">
<div class="modal-content">This child element shouldn't be able to close the modal on click.</div>
</div>
There are event modifiers for the click event handler
https://v2.vuejs.org/v2/guide/events.html#Event-Modifiers
<!-- modifiers can be chained -->
<a v-on:click.stop.prevent="doThat"></a>

Vue I want an image to follow the mouse

I am having trouble with a Vue component https://jsfiddle.net/shawnswebsites/fep1p02c/20/. I have a div in the component and when the user's mouse enters the div I want an image to be shown and I want the image to follow the mouse.
new Vue({
el: '#app',
data: {
showImage: false,
page: {
left : 0,
top: 0
},
},
methods: {
onMouseMove(e) {
console.log('page x: ' + this.page.left);
this.page.left = e.pageX;
this.page.top = e.pageY;
}
}
})
.container {
height: 400px;
width: 400px;
border: 1px solid #FFF;
background-color: grey;
margin: 40px;
}
.image {
position: absolute;
z-index: 1000;
overflow:hidden;
}
<script src="https://unpkg.com/vue"></script>
<div id="app">
<div class="container"
#mouseenter="showImage = true"
#mousemove.self="onMouseMove($event)"
#mouseleave="showImage = false">
</div>
<img v-show="showImage" class="image" src="http://via.placeholder.com/350x150" :style="{ left: page.left + 'px', top: page.top + 'px' }">
</div>
I use a #mouseenter to show the image and #mouseleave to hide the image. However, #mouseleave is still being called as I scroll over the div, which is causing the image to blink on and off. Can any help?
As said Oxcarga in the comment below you need to add pointer-events: none; to your image style:
.image {
position: absolute;
z-index: 1000;
overflow:hidden;
pointer-events: none;
}

waypoints refresh not working when modifying a div

I have a site made of "slides" 100% height.
<div class="slide" id="one">page1</div>
<div class="slide" id="two">page2</div>
<div class="slide" id="three">page3</div>
I use waypoints to perform some animation based on the position of the scroll, and it works fine. The context used is "window" and below an example:
$('#one').waypoint(function(direction)
{
//do something
}, { offset: '75%' });
By the way, in a slide there is a button that modifies the height of an image (it becomes very big), so after the resize the height of the container changes and also the height of the "slide", too.
I need the waypoint to refresh, in order to be raised at the same percentage calculated on the new size of the slide. I tried to do
$.waypoints('refresh');
after the resize, but it seems not working.
Below a piece of my css:
html {
height: 100%;
}
body{
text-align:center;
height:100%;
margin: 0 auto;
overflow-x: hidden;
}
.slide{
height: 100%;
margin: 0 auto;
background: white;
min-height: 700px;
min-width: 1024px;
}
#home {
height: 100%;
margin: 0 auto;
position: relative;
text-align: center;
min-height: 800px;
}
Can someone help me?