Vue dynamic image from assets - javascript

Below is my file structure
Project
|-src
|-assets
|-images
----->|-logo.png
|-components
|-json
----->|-data.json
|-mainComp
----->|-exp.vue
Now here is my data.json code
"Experience": {
"0": {
"sectionTitle": "Awards",
"sectionContent": {
"0": {
"articleTitle": "Adobeedu",
"articleValue": "2019 Early Bird",
"articleDate": "Acheived on 2019",
"image": true,
"articleImgPath": "../../assets/images/logo.png",
"articleAlt": "AdobeEdu Early Bird Award"
}
}
}
}
and here below is the code of the exp.vue
<template>
<div>
<section class="exp__section" v-for="(data, index) in jsonTitle" :key="index">
<h5>{{data.sectionTitle}}</h5>
<article
v-for="(items, idx) in data.sectionContent"
v-bind:class="{'content__box':true, 'contains__image':(items.image === true)}"
:key="idx"
>
<h6>{{items.articleTitle}}</h6>
<div class="image__row">
<div class="image__box">
<!-- <img :src="items.articleImgPath" :alt="items.articleAlt" /> -->
</div>
<h3>{{items.articleValue}}</h3>
</div>
<p>{{items.articleDate}}</p>
</article>
</section>
</div>
</template>
<script>
import json from "#/components/json/english.json";
export default {
name: "ExperienceSection",
data() {
return {
jsonTitle: json.Experience
};
}
};
</script>
Now src does get the value: ../../assets/images/logo.png but the images don't load up. I thought maybe I am not accessing the file structure properly so I tried ./, ../, ../../../, ../../../../ but I think this may not be the problem, and I may need something to load the image after all.

It happens because Vue CLI uses Webpack to bundle the assets folder, and this bundling renames the files/path. So when binding to an asset source, the easiest way to overcome this is to use require in the template and hardcode the assets path and any subpath. For example
<img :src="require('#/assets/images/' + items.articleImgPath)" :alt="items.articleAlt">
Remove the path from the variable and only use the filename:
"articleImgPath": "logo.png",
This also keeps the JSON clean of path names.

Related

Image path to stored in Pinia not passing through to component

I'm creating a card carousel with a Spotify style thumbnail, (image as background, text on top). Content is stored in a Pinia store which I will be hooking up to Firebase eventually. I'm trying to set the image background but am getting this error
GET http://127.0.0.1:5173/%60$%7B%7Bcontent.image%7D%7D%60 404 (Not Found)
Here is my store code (condensed to the important bits)
export const useContentStore = defineStore('contentStore', {
state: () => {
return {
guides: [{
title: 'XX',
date: 'X',
description: "X",
image: './assets/images/content/thumbnail.png',
id: '1',
}]
}
}
})
Here is where I am trying to access that image path
<template>
<div class="card">
<img class="card-image" src="{{content.image}}"/>
<h1 class="title">{{content.title}}</h1>
<h2 class="subtitle"></h2>
</div>
</template>
<script setup>
/*
store
*/
import { useContentStore } from "#/stores/contentStore";
const contentStore = useContentStore();
/*
props
*/
const props = defineProps({
content: {
type: Object,
required: true,
},
});
</script>
And here is where the cards are being called
<template>
<div class="guides-container">
<h2 class="title">Guides</h2>
<div class="guides-list">
<GeneralCard
v-for="(content, index) in contentStore.guides"
:key="content.id"
:content="content"
/>
</div>
</div>
</template>
<script setup>
/*
imports
*/
import GeneralCard from "#/components/GeneralCard.vue";
/*
data
*/
const contentStore = useContentStore();
</script>
My gut instinct is that it's an issue with transferring the string through the store to the template, but I don't have any clue how to fix it. I've tried escaping the characters, using template literals on both the stored path and the image tag, played with URL() a bit, and I'm pretty sure it's not an issue with the actual path of the image (it works when I plug the path directly into the image tag)
Thanks for any help you can give!
The src attribute on the img is set improperly. It should be
<img class="card-image" :src="content.image"/>

get img src from json file using vue js 2

I'm trying to get img src attribute from a json file but the images are not shown and the alternate texts are.
I'm sure that the images are found in the directory src/assets and thier names are right.
this is the component:
<template>
<div>
<div class="project" :title="title" :image="image" :desc="desc">
<div class="p-title">{{title}}</div>
<div class="p-image">
<img :src="image" :alt="title">
</div>
<div class="p-desc">{{desc}}</div>
</div>
</div>
</template>
<script>
export default {
name: 'AllProjects',
props: ["title","image","desc"]
}
</script>
And the view:
<template>
<div class="projects">
<AllProjects
v-for="project in projects"
:key="project.id"
:title="project.title"
:image="`#/assets/${project.image}`"
:desc="project.desc"
/>
</div>
</template>
<script>
import AllProjects from "#/components/AllProjects.vue";
import JsonProjects from "#/projects.json";
export default {
name: "Projects",
components: {
AllProjects,
},
data: function () {
return {
projects: JsonProjects,
};
},
};
</script>
And the projects.json file:
[
{
"id":0,
"title":"Blog Website",
"image":"blog.png",
"desc":"Description Of The Project"
},
{
"id":1,
"title":"Social Media Website",
"image":"social-media.png",
"desc":"Description Of The Project"
},
{
"id":2,
"title":"Online Courses Website",
"image":"online-courses.png",
"desc":"Description Of The Project"
}
]
So where is my mistake?
The issue is in your image path - replace the '#' with the full path to your image, as it can not be resolved correctly:
:img = "`src/assets/${project.image}`"
The '#' char is a 'resolve alliance' used with webpack - from the webpack doc:
Create aliases to import or require certain modules more easily
You can try to bind your path to the dom like so: {{#/assets/}}
and see it is not resolved to 'src', as it meant for modules importing and not to use inside the template.
You can find more details about the 'resolve alliance' in another issue

Can't display image in vue

I use this component SideMenu for displaying other SideMenuButton components, but the image isn't displayed
SideMenu:
<template>
<div id = "side-menu">
ciao
<SideMenuButton imgPath="../assets/lens.png"/>
</div>
</template>
<script>
import SideMenuButton from './SideMenuButton.vue'
export default {
name: "SideMenu",
components:{
SideMenuButton
}
}
</script>
SideMenuButton:
<template>
<div>
<img v-bind:src="imgPath">
</div>
</template>
<script>
export default {
name: "SideMenuButton",
props:{
imgPath: String,
}
}
</script>
U need to use assets resources like this
<img src="#/assets/lens.png"/>
Pass the image as props and use in the child the require for the img
SideMenu:
<template>
<div id = "side-menu">
ciao
<SideMenuButton image="lens.png"/>
</div>
</template>
SideMenuButton:
<template>
<div>
<img :src="require(`#/assets/${image}`)">
</div>
</template>
<script>
export default {
name: "SideMenuButton",
props:{
image: String,
}
}
</script>
The problem with this approach is, that vue uses webpack under the hood to bundle required resources (images aswell) into the dist/ directory. (simply put)
That happens at buildtime.
But the image path is a variable, so it can change at runtime. Webpack cannot determine the image anymore.
<template>
<div id="side-menu">
ciao
<SideMenuButton imgPath="imgPath"/>
</div>
</template>
<script>
import SideMenuButton from './SideMenuButton.vue'
export default {
name: 'SideMenu',
components: {
SideMenuButton
},
computed: {
imgPath () {
// webpack will replace the given path to import() with the actual "production" image path
return import('../assets/lens.png')
}
}
}
</script>
It is possible that you have to import() all images once somewhere in your app, so that webpack can include them at build time.
If you want to read any further into this topic:
vue guide on relative path imports
file-loader (prior to webpack version 5)
raw-loader (prior to webpack version 5)
url-loader (prior to webpack version 5)
asset modules (since webpack version 5)

v-on:click="{{item.klik}}" using VUE [duplicate]

My Vue.js component is like this:
<template>
<div>
<div class="panel-group" v-for="item in list">
...
<div class="panel-body">
<a role="button" data-toggle="collapse" href="#purchase-{{ item.id }}" class="pull-right" aria-expanded="false" aria-controls="collapseOne">
Show
</a>
</div>
<div id="purchase-{{ item.id }}" class="table-responsive panel-collapse collapse" role="tabpanel">
...
</div>
</div>
</div>
</template>
<script>
export default {
...
computed: {
list: function() {
return this.$store.state.transaction.list
},
...
}
}
</script>
When executed, there exists an error like this:
Vue template syntax error:
id="purchase-{{ item.id }}": Interpolation inside attributes has
been removed. Use v-bind or the colon shorthand instead.
How can I solve it?
Use JavaScript code inside v-bind (or shortcut ":"):
:href="'#purchase-' + item.id"
and
:id="'purchase-' + item.id"
Or if using ES6 or later:
:id="`purchase-${item.id}`"
Use v-bind or shortcut syntax ':' to bind the attribute.
Example:
<input v-bind:placeholder="title">
<input :placeholder="title">
Just use
:src="`img/profile/${item.photo}`"
If you're pulling data from an array of objects, you need to include require('assets/path/image.jpeg') in your object like I did below.
Working example:
people: [
{
name: "Name",
description: "Your Description.",
closeup: require("../assets/something/absolute-black/image.jpeg"),
},
Using require(objectName.propName.urlPath) in the v-img element did not work for me.
<v-img :src="require(people.closeup.urlPath)"></v-img>
The easiest way is too require the file address:
<img v-bind:src="require('../image-address/' + image_name)" />
The complete example below shows ../assets/logo.png:
<template>
<img v-bind:src="require('../assets/' + img)" />
</template>
<script>
export default {
name: "component_name",
data: function() {
return {
img: "logo.png"
};
}
};
</script>
The most elegant solution is save images outside Webpack. By default, Webpack compress images in Base64, so if you save images in your assets folder, that doesn't work because Webpack will compress images in base64, and that isn’t a reactive variable.
To solve your problem, you need to save your images in your public path. Usually the public path is in "public" folder or "statics".
Finally, you can do this:
data(){
return {
image: 1,
publicPath: process.env.BASE_URL
}
}
And your HTML you can do this:
<img :src="publicPath+'../statics/img/p'+image+'.png'" alt="HANGOUT PHOTO">
When to use the public folder
You need a file with a specific name in the build output
File depends on a reactive variable that can change in execution time
You have images and need to dynamically reference their paths
Some library may be incompatible with Webpack and you have no other option but to include it as a <script> tag.
More information: "HTML and Static Assets" in Vue.js documentation

Static image src in Vue.js template

My Vue component contains some images. I want to do lazy-loading later, so I need to set the src of the images to a small image, first.
<template>
<div v-for="item in portfolioItems">
<a href="#{{ item.id }}">
<img
data-original="{{ item.img }}"
v-bind:src="/static/img/clear.gif"
class="lazy" alt="">
</a>
</div>
</template>
Gives me a bunch of errors, like:
[Vue warn]: Invalid expression. Generated function
body: /scope.static/scope.img/scope.clear.gif vue.common.js:1014[Vue
[Vue warn]: Error when evaluating expression "/static/img/clear.gif":
TypeError: Cannot read property 'call' of undefined (found in
component: )
webpack.config.js:
module.exports = {
// ...
build: {
assetsPublicPath: '/',
assetsSubDirectory: 'static'
}
}
This solution is for Vue-2 users:
In vue-2 if you don't like to keep your files in static folder (relevant info), or
In vue-2 & vue-cli-3 if you don't like to keep your files in public folder (static folder is renamed to public):
The simple solution is :)
<img src="#/assets/img/clear.gif" /> // just do this:
<img :src="require(`#/assets/img/clear.gif`)" // or do this:
<img :src="require(`#/assets/img/${imgURL}`)" // if pulling from: data() {return {imgURL: 'clear.gif'}}
If you like to keep your static images in static/assets/img or public/assets/img folder, then just do:
<img src="./assets/img/clear.gif" />
<img src="/assets/img/clear.gif" /> // in some case without dot ./
If you want to bind a string to the src attribute, you should wrap it on single quotes:
<img v-bind:src="'/static/img/clear.gif'">
<!-- or shorthand -->
<img :src="'/static/img/clear.gif'">
IMO you do not need to bind a string, you could use the simple way:
<img src="/static/img/clear.gif">
Check an example about the image preload here: http://codepen.io/pespantelis/pen/RWVZxL
This is how i solve it.:
items: [
{ title: 'Dashboard', icon: require('#/assets/icons/sidebar/dashboard.svg') },
{ title: 'Projects', icon: require('#/assets/icons/sidebar/projects.svg') },
{ title: 'Clients', icon: require('#/assets/icons/sidebar/clients.svg') },
],
And on the template part:
<img :src="item.icon" />
See it in action here
#Pantelis answer somehow steered me to a solution for a similar misunderstanding. A message board project I'm working on needs to show an optional image. I was having fits trying to get the src=imagefile to concatenate a fixed path and variable filename string until I saw the quirky use of "''" quotes :-)
<template id="symp-tmpl">
<div>
<div v-for="item in items" style="clear: both;">
<div v-if="(item.imagefile !== '[none]')">
<img v-bind:src="'/storage/userimages/' + item.imagefile">
</div>
sub: <span>#{{ item.subject }}</span>
<span v-if="(login == item.author)">[edit]</span>
<br>#{{ item.author }}
<br>msg: <span>#{{ item.message }}</span>
</div>
</div>
</template>
declare new variable that the value contain the path of image
const imgLink = require('../../assets/your-image.png')
then call the variable
export default {
name: 'onepage',
data(){
return{
img: imgLink,
}
}
}
bind that on html, this the example:
<img v-bind:src="img" alt="" class="logo">
hope it will help
You need use just simple code
<img alt="img" src="../assets/index.png" />
Do not forgot atribut alt in balise img
I had a similar issue with Vue where I tried to display several images by importing data from a configuration json file and then iterating over the data using v-for.
Even when I put require('../../assets/' + filename) right in the json, the images would never show. I eventually realized that Vue was interpreting my data value as a string, rather than a function. Good thing that javascript supports functions as a return type. So I made this function:
getImagePath(filename: string) {
return require('../../assets/' + filename);
}
I then just called that function from my v-for loop simply passing in the filenames from my config:
<v-list-item :key="place.id" v-for="place in placesOfPower">
<v-list-item-content class="justify-end">
<v-img :src="getImagePath(place.image)"
position="top center"
height="90"
width="30vw"/>
</v-list-item-content>
<v-list-item-content>
I found this thread on my search for a solution to show an image when it exists. I want to show a list of database entries that contain a type property. Each type should have a fitting png file in my vue assets folder. The whole list would break if a new type would be added without adding the image beforehand.
I found "Catch an error on requiring module in node.js" on stack overflow. The answer by Peter Lyons led me to my solution:
<template>
<v-data-table :items="items">
<template v-slot:item.type="{ item }">
<v-img
v-if="typeImageSource(item.type)"
:src="typeImageSource(item.type)"
/>
<template v-else>
{{ item.type }}
</template>
</template>
</v-data-table>
</template>
<script>
export default {
data () {
return {
// In reality this gets filled from a db:
items: [
{ id: 1, type: 'abc' },
{ id: 2, type: 'abcd' },
{ id: 3, type: 'efg' },
]
}
},
methods: {
typeImageSource: function (type) {
let src = ''
try {
src = require(`#/assets/types/${('' + type).toLowerCase()}.png`)
} catch (error) {
console.warn(`Image for type ${type} could not be found! Please add "${('' + type).toLowerCase()}.png" to the folder "#/assets/types/".\n\n`, error)
return null
}
return src
},
},
}
</script>
If you are using nuxt
use <img :src="'_nuxt/path_to_your_local_image'" />
if you are using vue
first use static src import : <img src="path_to_your_local_image" />
then inspect image element to see what src is rendered to the browser
then replace it with a dynamic src

Categories