I want to display array of images in production mode after upload images in public folder outside src folder. I don't want use npm run build everytime and want to display images on the fly.
I have the following architecture:
dist
- img
src
- assets
- img
public
- img
-paintings
Here I want to display my images
<v-row justify="center" class="mt-4">
<v-col
v-for="(image, idx) in downloadedImages.slice().reverse()"
:key="idx"
class="d-flex child-flex"
cols="2">
<v-card>
<v-img
:src="imageUrl(image)"
height="200px"
>
*** some code ***
</v-img>
</v-card>
</v-col>
</v-row>
with methods
methods: {
imageUrl(imgName){
return 'public/img/paintings/'+imgName)
},
getDownloadedImages() {
return axGetDownloadedImages()
.then(response => {
this.downloadedImages = response.data
})
},
}
Where downloadedImages = ['img1.jpg', 'img2.jpg', 'img3.jpg', ... , imgN.jpg]
When images uploaded I see only white <v-card> without image and page update isn't help me. But I see uploaded images after use npm run build.
I read that public folder outside src isn't compile and I can display images but this is not happening
Where I have mistake?
Related
I'm trying to make my image draggable in another application like google or another site would do. For example if I drop an image from google to a Word document, it will copy the link of it and some web applications would show the image instead; the behavior depends on the app.
But the problem is my v-img doesn't even print the link, it just does nothing.
Here is my code:
<v-card v-if="chunk.length >= i">
<template v-if="activeTab === 'Comments'">
<v-card-title class="justify-center">{{ chunk[i-1] }}</v-card-title>
</template>
<template v-else-if="activeTab === 'Images'">
<v-img
:src="getImgUrl(chunk[i-1])"
width="500"
contain
draggable="true"
/>
</template>
<v-card-actions>
<v-col>
<v-btn
color="#138ed3"
block
dark
>
Share
</v-btn>
</v-col>
<v-col>
<v-btn
color="#ffcd00"
block
dark
>
Save
</v-btn>
</v-col>
</v-card-actions>
</v-card>
As you can see I already tried the "draggable" option but it doesn't help.
Is there something I'm missing ?
The problem with v-img is that it renders the image as background (using the CSS style background-image) rather than as an IMG tag. Apparently, CSS backgrounds do not support dragging.
I cannot find one proper example of loading an image with a skeleton loader. I'm using nuxt + Vuetify and I'm trying to use a simple image with a skeleton loader.
Here is my code.
<template>
<v-skeleton-loader v-if="loading" :loading="loading" type="image">
<v-card
v-show="loaded"
class="ma-auto elevation-4"
shaped
color="darkgreen"
width="500"
flat
>
<v-img
src="/products/em-lucky-combo.jpg"
max-width="500"
#load="hasLoaded"
>
</v-img>
</v-card>
</v-skeleton-loader>
</template>
my method
<script>
export default {
methods: {
hasLoaded() {
console.log('Image finished loading')
this.loading = false
this.loaded = true
},
},
}
</script>
But as I said the method never gets called when it is inside the v-card tag or directly in the skeleton loader.
I have tried using #load, I have tried using mounted hooks like below.
<script>
export default {
mounted() {
const readyHandler = () => {
if (document.readyState === 'complete') {
console.log('Document Rendered')
this.loading = false
this.loaded = true
document.removeEventListener('readystatechange', readyHandler)
}
}
document.addEventListener('readystatechange', readyHandler)
readyHandler() // in case the component has been instantiated lately after loading
},
}
</script>
But nothing seems to work properly or elegantly. Is it just not possible? The moment the <v-img> tag is inside the skeleton loader or inside a v-card inside a skeleton loader it never gets rendered no matter what I do. One suggestion was to use a slot. I'm guessing it has something to do with slots but I do not understand how to use these.
I tried doing something like this.
<template v-slot:default>
<v-card
class="ma-auto elevation-4"
shaped
color="darkgreen"
width="500"
transition="fade-transition"
flat
>
<v-img
src="/products/em-lucky-combo.jpg"
max-width="500"
transition="fade-transition"
#load="imageLoaded"
></v-img>
</v-card>
</template>
I tried using the code below.
How to make v-skeleton loader inside v-for in Vuetify
<v-img>
<template #placeholder>
<v-sheet>
<v-skeleton-loader />
</v-sheet>
</template>
</v-img>
At the end, OP had enough of using just some dimensions and a lazy loader image. Since images were local, there was no need for a skeleton.
<template>
<v-card class="ma-auto elevation-4" flat shaped width="500">
<v-img
aspect-ratio="1"
class="grey lighten-2"
lazy-src=""
max-height="350"
max-width="500"
src="/"
transition="fade-transition"
>
<template v-slot:placeholder>
<v-row
align="center"
class="fill-height ma-0"
justify="center"
>
<v-progress-circular
color="grey lighten-5"
indeterminate
></v-progress-circular>
</v-row>
</template>
</v-img>
</v-card>
</template>
Thanks to #kissu I realised my approach was wrong and unnecessary . I ended up giving my images some set dimensions and using a lazy image loader with a placeholder slot which works just fine. As he mentioned my images are loaded locally so it wont really work in my case.
What I did in the end.
<template>
<v-card class="ma-auto elevation-4" flat shaped width="500">
<v-img
aspect-ratio="1"
class="grey lighten-2"
lazy-src=""
max-height="350"
max-width="500"
src="/"
transition="fade-transition"
>
<template v-slot:placeholder>
<v-row
align="center"
class="fill-height ma-0"
justify="center"
>
<v-progress-circular
color="grey lighten-5"
indeterminate
></v-progress-circular>
</v-row>
</template>
</v-img>
</v-card>
</template>
I am using Vuetify to create a login form for an application.
This form is similar to Google's login form which first asks for an email address then for a password on the next screen. The purpose of doing this is to look up the user's email address to see whether to perform local authentication or to redirect the user to a Single-Sign-On provider.
Here is the relevant part of the code of the login component:
<template>
<v-app id="sm-login">
<v-content>
<v-container class="fill-height" fluid>
<v-card class="mx-auto px-10 pb-9" width="450px" :loading="loading">
<v-card-title class="justify-center pt-12"><img src="../../images/logo.png"></v-card-title>
<v-card-subtitle class="text-center py-6 headline">Sign In</v-card-subtitle>
<v-card-text>
<v-form v-if="!showPassword" v-on:submit.prevent="lookupEmail">
<v-text-field v-model.trim="email" label="Email" name="email" type="email" outlined />
</v-form>
<v-form v-if="showPassword" v-on:submit.prevent="login">
<v-chip outlined class="mb-6" close #click:close="showPassword = false"><v-avatar left><v-icon>mdi-account-circle</v-icon></v-avatar> {{email}}</v-chip>
<v-text-field v-model="password" label="Password" name="password" type="password" outlined />
</v-form>
</v-card-text>
<v-card-actions>
<v-btn text>Forgot Password?</v-btn>
<v-spacer />
<v-btn color="primary" v-on:click="clickButton">Log In</v-btn>
</v-card-actions>
</v-card>
</v-container>
</v-content>
</v-app>
</template>
<script>
export default {
data() {
return {
loading: false,
email: '',
password: '',
showPassword: false,
};
},
methods: {
lookupEmail() {
this.loading = true;
// Replaced an API call with a timeout for demonstration purposes
setTimeout(() => {
this.loading = false;
this.showPassword = true;
}, 2000);
},
login() {
// DO LOGIN HERE ...
},
clickButton() {
if (this.showPassword) {
this.login();
} else {
this.lookupEmail();
}
}
}
};
</script>
The problem here is the logo in the v-card-title section. Every time the loading property is toggled on or off, the entire card jumps slightly up and then down again. I figured out that adding the logo's explicit height and width fixes the jumping, and it does, but the image still flickers every time.
Using the DevTools' Network tab, I discovered that the logo is reloaded from the server every time the loading bar appears or disappears. Needless to say, this is not the desired or expected behavior.
Why is the logo reloading every time, and what can I do about it?
This was a bug in how the <v-card> element is rendered.
Rendering the initial <v-card> creates div elements with the following classes: v-card__title, v-card__subtitle, v-card__text, and v-card__actions.
What should happen when loading is set to true is that a new div with class v-card__progress is created above the v-card__title element.
Instead, what is happening is that the title element is being modified to turn it into v-card__progress and a new div is created for the v-card__title. The new img tag in this new div is what causes the reload.
Again, when turning off loading, you would think this should just remove the v-card__progress element, but it doesn't. Instead, it removes the v-card__title element and modifies the v-card_progress to turn it into the title. Again, the new img tag here causes the reload.
I filed a bug report, which was fixed in v2.2.16.
NOTE: In general use, this is not typically noticeable in the browser. The only reason I saw it is because I had the DevTools open with "Disable Cache" checked.
It's weird, could you delete the <v-content> and try it again? just like:
<template>
<v-app id="sm-login">
<v-container class="fill-height" fluid>
...
I'm having a variety of CSS issues with Vuetify that I'm hoping someone can help me resolve. I'm using a split panel view (vue-split-panel) with Vuetify, but Vuetify doesn't seem to consistently recognize when to trigger the full-column width, as shown below. I'm able to "trigger" the full column width (for the same split panel width) by just opening and then closing the Chrome js console.
I put this into a codesandbox so that it's reproducible. In doing so, I see a new issue that the radio buttons aren't showing.
https://codesandbox.io/s/split-view-test-7mlx1
If you're able to show me how to tweak the sandbox to make the responsivity work I'd so appreciate it!
Supposed to be a radio button:
Also, an issue that I can't reproduce in the codesandbox but I'm experiencing in my app (it's a JupyterLab extension) is shown in the bottom screenshot: the select label has the border line going through it. I tried to find if there is a CSS conflict somewhere but didn't know exactly where to look.
Furthermore I also have an issue that the select menu is offset proportional to the left menu, for some reason... why does opening the left and top menus effect the position? How can I fix it? I've tried using the "attach" property and adding an id to the element itself, or creating a parent div, but neither seems to solve it.
This is ~slightly reproducible in the sandbox by making the split panel wide and clicking the multi-select, then making it narrower and clicking again. You'll see that the menu is offset when it opens.
Solutions that don't involve iFrames would be preferred, and yes, I do have my app wrapped with <v-app>, however since it's a JupyterLab extension I only have access to the main tab space (not the left or top menus) so the v-app is wrapped around the HTML element which is the main tab area, not the full screen.
I think there might be a bug in the Vuetify code somewhere around this function: https://github.com/vuetifyjs/vuetify/blob/054555a42e2ef368df2d6e168d1eec7fc06fb12c/packages/vuetify/src/components/VSelect/VSelect.ts#L456
I have resolved all the CSS issues
Refactotred the grid layout by adding the proper components and breakdowns in UI. Added a fix to radio buttons. Added the css dependencies, material icons dependencies, fonts which vuetify uses internally
Check for the working codepen here: https://codesandbox.io/s/split-view-test-47f2h
<template>
<div id="app">
<v-app>
<Split style="height: 500px;">
<SplitArea :size="25">panel left</SplitArea>
<SplitArea :size="75">
<v-container fluid grid-list-md>
<v-layout row wrap>
<v-flex class="d-flex" xs="12" sm="12" md="6" lg="4">
<v-text-field
v-model="params.c.selected"
label="C"
hint="Penalty parameter C of the error term."
persistent-hint
return-object
type="number"
outlined
></v-text-field>
</v-flex>
<v-flex class="d-flex" sm="12" md="12" lg="6">
<v-select
v-model="params.kernel.selected"
hint="Specifies the kernel type to be used in the algorithm. It must be one of ‘linear’, ‘poly’, ‘rbf’, ‘sigmoid’, ‘precomputed’ or a callable. If none is given, ‘rbf’ will be used. If a callable is given it is used to pre-compute the kernel matrix from data matrices; that matrix should be an array of shape (n_samples, n_samples)."
:items="params.kernel.items"
label="Kernel"
persistent-hint
return-object
outlined
></v-select>
</v-flex>
<v-flex class="d-flex" sm="12" md="12" lg="6">
<v-text-field
v-model="params.degree.selected"
label="Degree"
hint="Degree of the polynomial kernel function ('poly'). Ignored by all other kernels."
persistent-hint
return-object
type="number"
outlined
></v-text-field>
</v-flex>
<v-flex class="d-flex" sm="12" md="12" lg="6">
<v-text-field
v-model="params.coef0.selected"
label="Coef0"
hint="Independent term in kernel function. It is only significant in 'poly' and 'sigmoid'."
persistent-hint
type="number"
outlined
></v-text-field>
</v-flex>
<v-flex class="d-flex" sm="12" md="12" lg="6">
<v-radio-group
v-model="params.probability.selected"
hint="Independent term in kernel function. It is only significant in 'poly' and 'sigmoid'."
persistent-hint
>
<template v-slot:label>
<div style="font-size: 12px">
Probability:
boolean, optional (default=False)
</div>
<br>
</template>
<v-radio label="True" :value="true" color="black"></v-radio>
<v-radio label="False" :value="false" color="black"></v-radio>
</v-radio-group>
</v-flex>
</v-layout>
</v-container>
</SplitArea>
</Split>
</v-app>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
params: {
c: { default: 1, selected: 1 },
kernel: {
default: "rbf",
selected: "rbf",
items: ["linear", "poly", "rbf", "sigmoid", "precomputed"]
},
degree: { default: 3, selected: 3 },
coef0: { defaul: 0.0, selected: 0.0 },
probability: { default: true, selected: true }
}
};
}
};
</script>
<style>
</style>
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.)