Reputation: 734
I have built a VueJS component and am using it multiple times on the same page. The components work independently of each other perfectly, however there's a method in the component to get it's offsetWidth and apply this (with a prefix) to the component as a class (eg width-800).
When there is only one of the component on a page, it works fine.
When there is more than one, only the last occurrence applies the class. It does calculate the class correctly with the correct width, but just doesn't apply it to the others on the page.
<template>
<div id="app-medialib" v-bind:class="[this.breakpoint]">
<p>{{ this.breakpoint }}</p>
this.breakpoint
is a data property which holds the class name.
mounted: function(){
var self = this;
this.calculateBreakpoint();
window.onresize = function(event) {
self.calculateBreakpoint();
};
}
and the breakpoint method:
calculateBreakpoint: function(){
var mediaLibraryWidth = null;
var elems = document.getElementsByClassName('header medialib');
for( var i=0; i<elems.length; i++ ){
if( elems[i].offsetParent !== null ){
console.log('elems[i]', elems[i]);
mediaLibraryWidth = elems[i].offsetWidth;
break;
}
}
console.log('calculateBreakpoint', mediaLibraryWidth);
if( mediaLibraryWidth > 956 ) {
this.breakpoint = 'md';
} else if( mediaLibraryWidth < 957 && mediaLibraryWidth > 700 ){
this.breakpoint = 'sm';
} else {
this.breakpoint = 'xs';
}
console.log('calculateBreakpoint', this.breakpoint);
},
Any help is much appreciated on this. Been scratching my head for a while now.
Thanks.
Upvotes: 1
Views: 3285
Reputation: 4892
Apply the v-bind:class
outside of the template like this
Vue.component("foo", {
template: "<div>{{item}}</div>",
props: ["item"]
});
var app = new Vue({
el: "#app",
data: {
background: "blue",
items: ["a", "b", "c", "d"]
},
mounted: function() {
var self = this;
this.calculateBreakpoint();
window.onresize = function(event) {
self.calculateBreakpoint();
};
},
methods: {
calculateBreakpoint: function() {
var mediaLibraryWidth = null;
var elems = document.getElementsByClassName("app");
for (var i = 0; i < elems.length; i++) {
if (elems[i].offsetParent !== null) {
console.log("elems[i]", elems[i]);
mediaLibraryWidth = elems[i].offsetWidth;
break;
}
}
console.log("calculateBreakpoint", mediaLibraryWidth);
if (mediaLibraryWidth > 956) {
this.background = "red";
} else if (mediaLibraryWidth < 957 && mediaLibraryWidth > 700) {
this.background = "blue";
} else {
this.background = "green";
}
console.log("calculateBreakpoint", this.breakpoint);
}
}
});
.red {
background: red;
}
.blue {
background: blue;
}
.green {
background: green;
}
.widget {
margin: 10px;
padding: 20px;
width: 200px;
font-weight: bold;
font-size: 16px;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.min.js"></script>
<div id="app" class="app">
<foo v-for="item in items" :class="[background]" class="widget" :item="item">
</div>
https://codepen.io/anon/pen/RVLrmG
Upvotes: 0
Reputation: 1362
When you do window.onresize and bind a function to it, the previous bindings get overridden, so when you have multiple components in your app, their mounted function is called which overrides the window.onresize. That is the reason why only the last components class is being changed.
Try the following in your console.
window.onresize = function (e) {
console.log('a')
}
window.onresize = function (e) {
console.log('b')
}
Only 'b' gets logged when you resize.
Checkout : What is the best practice to not to override other bound functions to window.onresize?
In your case using jquery to bind functions on window.onresize will be a better approach.
Try:
$(window).resize(function() {
console.log('a')
})
$(window).resize(function() {
console.log('b')
})
It will log both 'a' and 'b' when you resize.
So change your window.onresize to:
$(window).resize(function() {
self.calculateBreakpoint();
})
Or as per Daniel Beck's suggestion, if you want to avoid using jquery, use:
window.addEventListener('resize', self.calculateBreakpoint )
Upvotes: 3