Make Position: Fixed Behavior Like Sticky (For Vue2)

Make position: fixed behavior like sticky (for Vue2)

As I mentioned in the comments, I'd recommend using a polyfill if at all possible. They will have put a lot of effort into getting it right. However, here is a simple take on how you might do it in Vue.

I have the application handle scroll events by putting the scrollY value into a data item. My sticky-top component calculates what its fixed top position would be, and if it's > 0, it uses it. The widget is position: relative.

new Vue({
el: '#app',
data: {
scrollY: null
},
mounted() {
window.addEventListener('scroll', (event) => {
this.scrollY = Math.round(window.scrollY);
});
},
components: {
stickyTop: {
template: '<div class="a-box" :style="myStyle"></div>',
props: ['top', 'scrollY'],
data() {
return {
myStyle: {},
originalTop: 0
}
},
mounted() {
this.originalTop = this.$el.getBoundingClientRect().top;
},
watch: {
scrollY(newValue) {
const rect = this.$el.getBoundingClientRect();
const newTop = this.scrollY + +this.top - this.originalTop;

if (newTop > 0) {
this.$set(this.myStyle, 'top', `${newTop}px`);
} else {
this.$delete(this.myStyle, 'top');
}
}
}
}
}
});
#app {
height: 1200px;
}

.spacer {
height: 80px;
}

.a-box {
display: inline-block;
height: 5rem;
width: 5rem;
border: 2px solid blue;
position: relative;
}
<script src="//unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app">
<div class="spacer"></div>
<div class="a-box"></div>
<sticky-top top="20" :scroll-y="scrollY"></sticky-top>
<div class="a-box"></div>
</div>

Sticky sidebar with fixed header in Vue.js without jQuery

The short answer is to use these two lines (the first one is yours):

  const rect = this.$el.getBoundingClientRect();
const offset = rect.top + window.pageYOffset;

The longer answer of course includes the thought process to achieve this result. I ran

  console.log($(this.$el).offset + "");

On your fiddle at the relevant place to see how the offset function is implemented and got this:

function( options ) {

// Preserve chaining for setter
if ( arguments.length ) {
return options === undefined ?
this :
this.each( function( i ) {
jQuery.offset.setOffset( this, options, i );
} );
}

var rect, win,
elem = this[ 0 ];

if ( !elem ) {
return;
}

// Return zeros for disconnected and hidden (display: none) elements (gh-2310)
// Support: IE <=11+
// Running getBoundingClientRect on a
// disconnected node in IE throws an error
if ( !elem.getClientRects().length ) {
return { top: 0, left: 0 };
}

// Get document-relative position by adding viewport scroll to viewport-relative gBCR
rect = elem.getBoundingClientRect();
win = elem.ownerDocument.defaultView;
return {
top: rect.top + win.pageYOffset,
left: rect.left + win.pageXOffset
};
}

The solution is inspired from this line:

            top: rect.top + win.pageYOffset,

How to make table headers non scrollable bootstrap vue

 .table.b-table>thead>tr>th {
background-color: white;
position: sticky;
position: -webkit-sticky;
top: 0;
z-index: 2;
}

This thing worked for me use it in the app.vue it should fix all the b-tables

Nuxt/Vue/Bootstrap-vue shrink navbar on scroll

In your .vue:

<template> section:

<nav id="nav" class="navbar is-transparent is-fixed-top">

<script> section:

export default {
mounted() {
this.$nextTick(function(){
window.addEventListener("scroll", function(){
var navbar = document.getElementById("nav");
var nav_classes = navbar.classList;
if(document.documentElement.scrollTop >= 150) {
if (nav_classes.contains("shrink") === false) {
nav_classes.toggle("shrink");
}
}
else {
if (nav_classes.contains("shrink") === true) {
nav_classes.toggle("shrink");
}
}
})
})
},
}

Live Demo on codesandbox

How can I fix this jumping transition?

I finally got it fixed by wrapping the <h1> element inside a <template> tag and do the loop on it instead of doing it directly from the <transition> tag. Notice that I also added mode="out-in" in the <transition> tag, otherwise it still jumps.

<transition name="fade" mode="out-in">
<template v-for="(slide, i) in slides">
<h1 class="punchline" :key="slide" v-if="current == i">
{{ slide }}
</h1>
</template>
</transition>

The reason of the jumps is because when I inspect the element, the new content is mounted while the old element was still there so it just rendered below the old one before it got completely removed. Not sure why is this happen but probably because <transition> is not meant to be looped.

<transition-group> like this:

<transition-group name="fade" mode="out-in">
<h1
class="punchline"
v-for="(slide, i) in slides"
:key="slide"
v-show="current == i">
{{ slide }}
</h1>
</transition-group>

also won't work with this condition since it produces the same behavior. (or perhaps i'm using it wrong? please let me know)

Vue2: prop does not get bound

Why it doesn't work

Actually, the answer is pretty trivial: you don't put any props on your arrowToSection component. While in your body you have an element confusingly named <arrowToSection>, arrowToSection component is not mounted on it - at least not directly. You create arrowToSection component inside the anonymous Vue instance created in component.js, here: template: '<arrowToSection/>'. And you pass no props to it.

How to fix it

To fix it, you need to pass the prop here:

let arrowToSection = vdsm.arrowToSection
new Vue({
el: '#arrowToSection',
template: '<arrowToSection :offsetSelector="'.navbar'" />',
components: { arrowToSection }
})

Next, you may ask "why not add a prop to this anonymous element, and use the value set in body HTML instead". For which the answer is, props are the way of passing values between Vue components. Outside HTML is not a Vue component and you can't pass props from there. The attributes you put on #arrowToSection element are just normal attributes (and the whole element gets replaced and arguments lost, btw).

Later note: This example in documentation shows attributes being apparently read from the HTML element. It seems somewhat contradictory with my experiment. It's possible that passing props would work if you use full v-bind:prop="..." notation instead of :prop="..." shorthand.

Alternative solutions with propsData

If you really want to use props, you could use propsData:

let arrowToSection = vdsm.arrowToSection
new Vue({
el: '#arrowToSection',
props: ['offsetSelector'],
propsData: {
offsetSelector: '.navbar',
},
template: '<arrowToSection :offsetSelector="offsetSelector" />',
components: { arrowToSection }
})

As you see, this is really contrived and doesn't make sense. However, you don't really need the intermediate component, so, at least in practice, you can use propsData this way:

let arrowToSection = vdsm.arrowToSection
new Vue(Object.assign({}, arrowToSection, {
el: '#arrowToSection',
propsData: {
offsetSelector: '.navbar',
},
}))

Disclaimer: I'm not sure using components this way is officially supported. Probably not. But it works.

Prevent on click on parent when clicking button inside div

Have a look at Event Modifiers in the Vue.js v3 docs (v2 docs here), v-on:click.stop will stop that click from propagating or "bubbling" up to the parent element.

Can the right column be fixed in the bootstrap-vue table?

It's possible by overriding bootstrap's CSS with some of our own. First make sure the last column has the stickyColumn: true option plus whatever other options you want to give it:

...
'i',
'j',
'k',
{ key: "l", stickyColumn: true, isRowHeader: true, variant: "primary" },

This will ensure it has a classname we can easily select on. Apply styling that gives the last sticky column in the table an attribute of right: 0:

<style>
.b-table-sticky-column:last-child {
right: 0;
}
</style>

codesandbox example

Can you force Vue.js to reload/re-render?

Try this magic spell:

vm.$forceUpdate();
//or in file components
this.$forceUpdate();

No need to create any hanging vars :)

Update: I found this solution when I only started working with VueJS. However further exploration proved this approach as a crutch. As far as I recall, in a while I got rid of it simply putting all the properties that failed to refresh automatically (mostly nested ones) into computed properties.

More info here: https://v2.vuejs.org/v2/guide/computed.html



Related Topics



Leave a reply



Submit