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
Why Do I Need "Height: Auto" for Responsive Images
Bootstrap 4 Horizontal Scroller Div
CSS3 Background-Size - How to Guarantee Coverage
Ie7 and "Inherit": Ignoring Entire Rule
Setting The Scrollbar Color in Safari for Lion (Os X 10.7)
Slide Flickering with CSS Transitions
Twitter Bootstrap Grid Vertical Align Bottom
Google Chrome: Diagonal CSS Line-Through
CSS Takes Effect After Page Has Rendered
CSS: Overflow-Y: Scroll; Overflow-X: Visible
Adding CSS Styling to React Native Webview
How to Get Another Element Value in Less
How to Include a CSS Stylesheet in Orchard Module
What Is Defferent Between Bootstrap.CSS and Bootstrap.Min.CSS
Error While Configuring CSS Modules with Webpack