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
Related
In my Nuxt.js project I installed vue2-editor package to be able to write articles with HTML. When I come to page, write something and press the button everything works correctly, but when I reload page, I get document is not defined error.
Here is the code:
<template>
<div>
<SideBar />
<div class='content'>
<h1>Write article</h1>
<client-only>
<VueEditor
v-model='articleContent'
/>
</client-only>
<div style='margin-top: 15px'><button #click='postArticle'>Post article</button></div>
</div>
</div>
</template>
<script>
import { VueEditor } from 'vue2-editor';
import SideBar from '../components/SideBar';
export default {
name: 'Articles',
components: {
SideBar,
VueEditor
},
data() {
return {
articleContent: null,
}
},
methods: {
postArticle() {
console.log(this.articleContent)
},
},
}
</script>
And the error looks like that:
Also in documentation I've found that for Nuxt.js projects vue2-editor should be added to modules, and I did it, but it still doesn't work:
modules: [
// https://go.nuxtjs.dev/axios
'#nuxtjs/axios',
'vue2-editor/nuxt'
],
You can try to load it dynamically:
<template>
<div>
<SideBar />
<div class='content'>
<h1>Write article</h1>
<client-only>
<VueEditor
v-model='articleContent'
/>
</client-only>
<div style='margin-top: 15px'><button #click='postArticle'>Post article</button></div>
</div>
</div>
</template>
<script>
import SideBar from '../components/SideBar';
export default {
name: 'Articles',
components: {
SideBar,
VueEditor: () => process.client ? (await import("vue2-editor")).VueEditor : ""
},
data() {
return {
articleContent: null,
}
},
methods: {
postArticle() {
console.log(this.articleContent)
},
},
}
</script>
Do follow the below steps the add that plugin into your Nuxt
There will be plugins folder just like pages and components, if not create one and add a js file into it vue2-editor.js.
Copy the below content inside vue2-editor.js
import Vue from "vue";
import Vue2Editor from "vue2-editor";
Vue.use(Vue2Editor);
Inside nuxt.config.js remove the 'vue2-editor/nuxt' from the modules and create a separate array called plugins as below
/*
** Plugins to load before mounting the App
*/
plugins: [{ src: "~/plugins/vue2-editor", mode: 'client' }],
Thats it you are done. Now you can start using it in any of the vue files like
<vue-editor placeholder="Write Something..." v-model="content"></vue-editor>
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)
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">
I believe this is a relatively unique problem, and as such I'm having difficulty trying to solve it.
I'm creating a file manager-like solution in Vue, and I'm looking for certain folders/files to display a unique thumbnail (in my example, showing the Creative Cloud logo if the 'Creative Cloud' folder is found). In my app I am using a component to represent each file.
The file-grid Vue file reads as such (sorry for the mess, I've been trying to integrate multiple different solutions to see what sticks):
<template>
<div id="localMain">
<div id="filesGrid">
<File :fileName="file"
:imageAddress="findImage($event)"
id="file"
v-for="file in files"
:key="file.id"></File>
</div>
</div>
</template>
<script>
import File from './LocalMain/File';
export default {
data() {
return {
creativeCloud: 'static/logos/creative-cloud.svg',
blankThumb: 'static/code.svg',
files: [
'Creative Cloud',
'Documents',
...
],
};
},
components: {
File,
},
methods: {
findImage: function findImage(e) {
/* Get the name of the file/folder, and choose a thumbnail accordingly */
const name = e.target.dataset.fileName;
let image = this.blankThumb;
if (name === 'Creative Cloud') {
image = this.creativeCloud;
} else {
image = this.blankThumb;
}
return image;
},
},
};
</script>
<style scoped>
/* styling */
</style>
The file component itself looks like this:
<template>
<div id="file">
<img :src="imageAddress" alt="Logo" id="fileImg" />
<h3 v-if="display">{{ fileName }}</h3>
</div>
</template>
<script>
export default {
data() {
return {
display: false,
};
},
props: {
fileName: String,
imageAddress: String,
},
};
</script>
<style scoped>
/* styling */
</style>
I apologise for the ambiguity in this question, but I'm quite confused.
I might be missing something, but why not just v-bind the method with the file name as the argument?
eg.
Parent template
<File :fileName="file"
:imageAddress="findImage(file)"
id="file"
v-for="file in files"
:key="file.id"></File>
Parent Javascript
findImage: function findImage(name) {
var image = this.blankThumb;
if (name === 'Creative Cloud') {
image = this.creativeCloud;
}
return image;
},