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
Related
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"/>
In my NuxtJS project I have a component that recieves an image path as a prop. I tried passing it directly to :src="imageAddress" but it neither resolve nor throws an error. Then I tried to use this path inside require() to resolve it properly. But I get this Nuxt error: Cannot find module '~/assets/icons/crown.png'. The path is correct and I tested that by placing an img element directly in index.vue. Do you have any idea why this happens?
This is how my code is structured:
pages/index.vue
<template>
<ChildComponent image-address="~/assets/icons/crown.png" />
</template>
___________________________________________________________________
components/ChildComponent.vue
<template>
<img v-if="imageAddress.length" :src="require(imageAddress)">
</template>
<script>
export default {
name: 'ChildComponent',
props: {
imageAddress: {
type: String,
required: true,
default: ''
}
}
}
</script>
You can try to make method in ChildComponent:
getUrl (img) {
return require(`~/assets/icons/${img}.png`);
}
then in template:
<img :src="getUrl(imageAddress)" alt="" />
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.
I am attempting to render a list of components. All the data properties are displaying correctly except the img src url.
the files/folders are :
CryptContent.vue - contains the v-for
the component to render
assets/ - contains the images
The CryptContent.vue contain:
<template>
<OwnedCardContent
v-for="card in allCards"
:id="card.id"
:name="card.name"
:cost="card.cost"
:cset="card.cset"
:edition_total="card.edition_total"
:level="card.card_level"
:unlock_czxp="card.unlock_czxp"
:buy_czxp="card.buy_czxp"
:transfer_czxp="card.transfer_czxp"
:sacrifice_czxp="card.sacrifice_czxp"
:url="card.graphic"
:card_class="card.bg"
></OwnedCardContent>
</template>
<script>
allcards : [
{id:0, name: 'Jim Zombie',graphic: './assets/jim.svg', cost: 300, cset: 'We like to party set', edition_total: ' of 100',unlock_czxp : '1,300,300',card_level: 80, buy_czxp: '1,800',transfer_czxp: '100', sacrifice_czxp: '2,300',bg: 'card-bg card-bg-6'},
]
</script>`
OwnedCardContent.vue contains:
<template>
<div id="1" :class="card_class">
<img class="card-img" :src="url" />
<span class="card-edition">#1{{edition_total}}</span>
<div class="card-item-name text-center">{{name}}<br>{{cset}}</div>
<div class="card-czxp text-left">{{unlock_czxp}}</div>
<div class="card-level">{{level}}</div>
</div>
</div>
</template>
<script>
export default {
name: 'OwnedCardContent',
props: ['id','name','url','edition_total','cset','unlock_czxp','level','cost','buy_czxp','transfer_czxp','sacrifice_czxp','card_class'],
data () {
return {
}
}
}
</script>
The image won't render. When I inspect the code, the correct value from allCards graphic gets injected into the page..
when I remove :src and put just src="./assets/jim.svg" it works.
so I assume it's how webpack prepares it maybe ? I dont know enough about it :(
any help would be super helpful, thanks !
With webpack images are considered as modules so you should import or require them like :
allcards : [ {id:0, name: 'Jim Zombie',graphic: require('./assets/jim.svg'), ....]
or
import img from './assets/jim.svg';
export default{
...
data(){
return {
allcards : [ {id:0, name: 'Jim Zombie',graphic: img, ....],
...
}
}
...
}
Could you try use method for src
getImgUrl(path) {
var images = require.context('../assets/', false, /\.png$/)
return images('./' + path + ".png")
}
<div class="col-lg-2" v-for="pic in pics">
<img :src="getImgUrl(pic)" v-bind:alt="pic">
</div>
You can try this
<img v-attr="src:imgUrl">
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