I have a transition-group containing two or more images. This is working, but now I want to preload the next image in line.
This is what I have now:
<template>
<transition-group name="fade" tag="div">
<div v-for="i in [currentIndex]" :key="i" class="absolute inset-0">
<img :src="currentImg" class="object-center object-cover w-full h-full" rel="preload" />
</div>
</transition-group>
</template>
Every time I update currentIndex, currentImg gets computed, so that works. Now I need to preload the currentIndex + 1 image. Is this possible?
If you want to preload an image, you can previously initialize an image in JavaScript, that's not mounted in the DOM:
var preloadingImg = new Image;
preloadingImg.src = "/path/to/img.jpg"; // replace string with img source of [currentIndex + 1]
// optional callback when it's loaded:
preloadingImg.onload = function(event) {
// ...
}
As long as the browser keeps the image in cache, the source link will not be requested again.
(Deleting the variable has no influence in the cache of the image.)
Related
I have a VueJS view that creates collapsed contents using Bootstrap Vue Collapse Component.
The data is dynamic and can contains hundreds of items, which is why you see in the code below it was created via a v-for loop in Vue.
<div class="inventory-detail" v-for="(partNumberGroup,index) in inventory" :key="index" >
<b-button block v-b-toggle="partNumberGroup.partNumber" v-bind:id="partNumberGroup.partNumber" variant="primary"
#click="(evt) =>{isActive = !isActive && evt.target.id == partNumberGroup.partNumber}">
<i v-bind:id="partNumberGroup.partNumber" class="float-right fa" :class="{ 'fa-plus': !isActive, 'fa-minus': isActive }"></i>
{{ partNumberGroup.partNumber }}
</b-button>
<div class="inventory-detail__card" v-for="item in partNumberGroup.items">
<b-collapse v-bind:id="partNumberGroup.partNumber" >
<b-card>
<!--Accordion/Collapse content -->
</b-card>
</b-collapse>
</div>
</div>
This works fairly well in that I can individually expand and collapse each content separately. However, the one issue I'm facing is each time I click the icon fa-minus (-) orfa-plus (+), all of them changed as per the images below.
Any tips on how I should implementing this? in my code I tried the dynamic CSS class switching but I still lack the ability to switch on specific element.
I feel like the solution to this is to somehow conditionally apply dynamic CSS class or somehow able to use the attribute 'aria-expanded'.
You can try something like this. Whenever somebody clicks on the icon, set its index as activeIndex (using the setActiveIndex method). Then you can set the class accordingly by comparing the activeIndex with current index
<i
#click="setActiveIndex(index)"
v-bind:id="partNumberGroup.partNumber"
class="float-right fa"
:class="{ 'fa-plus': !isActive(index), 'fa-minus': isActive(index) }">.
</i>
then in the script part:
...
data() {
return {
activeIndex: -1
}
},
methods: {
/* set active index on click */
setActiveIndex(index) {
this.activeIndex = index;
},
/* check if index is active or not */
isActive(index) {
return index === this.activeIndex;
}
}
This one is for Big image slider
<VueSlickCarousel v-if="changeableImages && changeableImages.length > 0"
ref="c1"
:focusOnSelect="true">
<div v-for="(image, imageIndex) in changeableImages" :key="'c1_image_' + imageIndex">
<img :src="image.imagePath">
</div>
</VueSlickCarousel>
This one is for small image slider.
<VueSlickCarousel v-if="changeableImages && changeableImages.length > 0"
ref="c2"
:asNavFor="$refs.c1"
:slidesToShow="4"
:focusOnSelect="true">
<div v-for="(image, imageIndex) in changeableImages" :key="'c1_image_' + imageIndex">
<img :src="image.imagePath">
</div>
</VueSlickCarousel>
on view methods:
imageFilterChange() {
let newChangeableImages = [];
changeableImages.$set(this, 'changeableImages', newChangeableImages);
}
My problem: when I change the changeableImages from vue methods, sometimes asNavFor doesn't work properly. I mean, small slider don't navigate proper image from big slider.
package used: "vue-slick-carousel": "^1.0.6" on "vue": "^2.6.11"
I have a DIV which holds background images, and I change them by bootstrap carousel item change by passing data-bg attribute like below:
HTML
<div class="bg-holder" data-bg="bg-1">
<div id="carousel">
<div class="carousel-item active" data-bg="bg-1">
.... some slider content
</div>
<div class="carousel-item" data-bg="bg-2">
.... some slider content
</div>
</div>
</div>
JS
const bgHolder= document.querySelector(".bg-holder");
$('#carousel').on('slide.bs.carousel', function (e) {
bgHolder.dataset.bg = e.relatedTarget.dataset.bg;
})
CSS
.bg-holder[data-bg="bg-1"] {
background-image: url(image1.jpg)
}
.bg-holder[data-bg="bg-2"] {
background-image: url(image2.jpg)
}
I set data-bg="bg-1" by default and then on every carousel change i pass the new data-bg value. it works great in all modern browsers except IE11 which do not refresh the images from css, and it keeps displaying the one i loaded by default. When I open developers tools and uncheck/check the declaration it displays the proper image. Any ideas ?
I test in IE and reproduce the issue. As a workaround, you could set the background-image as inline style of bg-holder and change it on every carousel change according to bg value. The sample code is like below:
HTML:
<div class="bg-holder" style="background-image: url(image1.jpg)">
<div id="carousel">
<div class="carousel-item active" data-bg="bg-1">
.... some slider content
</div>
<div class="carousel-item" data-bg="bg-2">
.... some slider content
</div>
</div>
</div>
JS:
$('#carousel').on('slide.bs.carousel', function (e) {
if (e.relatedTarget.dataset.bg == "bg-2") {
$(".bg-holder").css("background-image", "url(image2.jpg)");
}
else {
$(".bg-holder").css("background-image", "url(image1.jpg)");
}
})
You could also check this online demo in IE 11.
Im using bootstrap vue's pagination component to break up and display content from a v-for loop. I am slicing the array perPage. Everything seems to be working. the correct number of perPage is displayed. The correct number of rows. The only problem is that when I select a new page, the content is never updated on the screen. It shows the same data on every page.
I have console logged the sliced array depending on what page and the slice is happening and working on everyPage click, I just cant get that new array to display on screen.
<b-paggination v-model="currentPage" :total-rows="rows" :per-
page="perPage" aria-controls="my-table" </b-pagination>
<b-col v-if="!showLoad" class="mb-4" v-for="(data,index) in
listOfData" id="my-table" :key="index" cols="12>
<app-card v-bind:data="Data[index]></app-card>
</b-col>
computed: {
rows() {
return this.data.length;
}
listOfData() {
const items = this.Data
return items.slice((this.currentPage - 1) * this.perPage,
this.currentPage * this.perPage);
}
}
Update: I discovered that injecting the content from the v-for into the imported card component (app-card) was somehow stoping the content from updating from page to page. I just removed the app-card component and hard coded a card in its place.. Now for some reason the content is changing from page to page.
```
//This Works:
<div v-for="(data, index) in listOfData" :key="index">
<b-card
overlay
img-src="https://picsum.photos/900/250/?image=3"
img-alt="Card Image"
text-variant="white"
title="Image Overlay"
sub-title="Subtitle"
>
<b-card-text>
{{ data.Data }}
</b-card-text>
</b-card>
</div>
//This Doesnt Work:
<div v-for="(data, index) in listOfData" :key="index">
<app-card v-bind:Dataprop="Data"></app-card>
</div>```
So, I wanted to bind style with the height of another element that I got from getHeight function, but I kept getting an error that said window is not defined.
Can someone please give me a solution?
Here is my source code:
<template>
<div class="container">
<p class="section-title">past event</p>
<div class="columns is-multiline">
<div
class="column is-one-third is-centered past-events"
v-for="(event, index) in events.slice(0, 2)"
:key="index"
>
<EventCard :event="event" />
</div>
<div class="column is-one-third is-centered">
<div class="link-box" :style="{ height: getHeight() }">
<nuxt-link to="/past-events">
<p style="color: #ffffff; cursor: pointer" class="see-all">
Lihat List Event Lainnya
</p>
</nuxt-link>
</div>
</div>
</div>
<a class="see-all-btn"> </a>
</div>
</template>
<script>
import EventCard from "~/components/EventCard.vue";
export default {
name: "PastEvents",
components: {
EventCard
},
props: ["events"],
data() {
return {};
},
mounted() {
this.getHeight();
},
methods: {
getHeight() {
const height = window.getComputedStyle(
document.querySelector(".past-events")
).height;
console.log(height);
return height + "px";
}
}
};
</script>
Nuxt uses server-sided rendering. This means that when your code is being executed on the server, it does not have something like window. After all, it is not a browser.
The easiest way around this is by wrapping anything that should not be pre-rendered to html, with something like vue-no-ssr. This particular library renders a dummy component on the server, then actually renders the component when it gets to the browser.
Yes window doesn't exist during the mounted lifecycle hook. I assume you're trying to place something based on its position?
In that case, you might be able to utilize CSS to do it for you. You can place elements using the View Height/View Width units. Combine that with CSS calc() and you might get the solution you need.
Example:
.element {
/* make element positon relative to the window */
position: fixed;
/* set position - note vw/vh are % of window */
/* this put the top of your element -200px from the bottom of your window */
top: calc(100vh - 200px);
}
If you're doing something more complex, using Javascript's element.getBoundingClientRect() will likely provide what you need. See this answer for more info.