Can't display image in vue - javascript

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)

Related

Vue3 with Vite only accepts kebab case tags while Vue3 cli accepts Pascal case tags for custom components

I have a project using Vue3 with Vite (on Laravel) which have a Wiki.vue page which loads a "MyContent.vue" component.
//On MyContent.vue:
<template>
<div>content component</div>
</template>
<script>
export default {
name: "MyContent",
};
</script>
//On Wiki.vue:
<template>
<MyContent />
</template>
<script>
import MyContent from "./wiki/components/MyContent.vue";
export default {
components: { MyContent },
};
</script>
//On vite.config.js
import { defineConfig } from "vite";
import laravel from "laravel-vite-plugin";
import vue from "#vitejs/plugin-vue";
export default defineConfig({
plugins: [
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => ["MyContent"].includes(tag),
},
},
}),
laravel(["resources/css/app.css", "resources/js/app.js"]),
],
});
On Wiki.vue If I dont change the tag from MyContent to my-content the component won't load at all.
I tried to start a new Vue3 Cli project and I notice that the HelloWorld tag is able to remain Pascal case and load properly which I really wonder what makes the difference.
Thanks in advance!
You've configured a compiler option to treat any elements whose name matches "MyContent" as custom elements, which prevents them from being parsed as Vue components:
// vite.config.js
export default defineConfig({
plugins: [
vue({
template: {
compilerOptions: { 👇
isCustomElement: (tag) => ["MyContent"].includes(tag),
},
},
}),
],
});
Wiki.vue's template tries to use a Vue component named "MyContent", which is ignored per the config above. HelloWorld.vue is unaffected by this because the config above only looks for "MyContent".
Solution
You should either remove the isCustomElement config, or rename MyContent.vue. It doesn't sound like you're actually using custom elements, so I think the former is the best solution.

How to create a Nuxt 3 Plugin from Vue 3 Plugin? (vue3-markdown-it)

I am new to Nuxt, and am attempting to turn the Vue plugin vue3-markdown-it into a Nuxt 3 plugin, but am receiving the following error:
[Vue warn]: Failed to resolve component: Markdown If this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement.
What am I doing incorrectly?
Nuxt 3 Plugin Documentation
// md-plugin.client.ts
import Markdown from 'vue3-markdown-it'
export default defineNuxtPlugin(nuxtApp => {
nuxtApp.vueApp.use(Markdown)
})
// index.vue
<template>
<main>
<ClientOnly>
<Markdown :source="content" />
</ClientOnly>
</main>
</template>
<script lang="ts" setup>
const { find } = useStrapi4()
const {
data: {
attributes: { content },
},
} = await find('homepage')
</script>
I had a similar problem on different plugin. I solved the problem by using component instead of plugin.
Create a new file under the components folder (Markdown.vue).
Add Markdown codes in this file:
<template>
<Markdown :source="content" />
</template>
<script lang="ts" setup>
import { defineProps } from "vue";
import Markdown from 'vue3-markdown-it';
defineProps({
content: { type: any }
});
</script>
You can customize this code.
Delete plugin file (md-plugin.client.ts)
Now <Markdown :source="content" /> will see our generated Markdown component. It worked me.

VueEditor document is not defined Nuxt.js

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>

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

How do I import an svg in Vue 3?

I tried following:
https://github.com/visualfanatic/vue-svg-loader/tree/master
but there's a version conflict with vue-template-compiler since that's used in Vue 2.
I tried:
https://github.com/visualfanatic/vue-svg-loader
but I'm missing a specific vue dependency.
I noticed there's a caveat with using typescript and you need to declare the type definition file. However, I still get "Cannot find module '../../assets/myLogo.svg' or its corresponding type declarations."
Here's what I added:
vue.config.js
module.exports = {
chainWebpack: (config) =>
{
const svgRule = config.module.rule('svg');
svgRule.uses.clear();
svgRule
.use('vue-loader-v16')
.loader('vue-loader-v16')
.end()
.use('vue-svg-loader')
.loader('vue-svg-loader');
},
configureWebpack: process.env.NODE_ENV === 'production' ? {} : {
devtool: 'source-map'
},
publicPath: process.env.NODE_ENV === 'production' ?
'/PersonalWebsite/' : '/'
}
shims-svg.d.ts
declare module '*.svg' {
const content: any;
export default content;
}
MyComponent.vue
<template>
<div>
<MyLogo />
</div>
</template>
<script lang="ts">
import * as MyLogo from "../../assets/myLogo.svg";
export default defineComponent({
name: "MyComponent",
components: {
MyLogo
},
props: {
},
setup(props)
{
return {
props
};
}
});
</script>
Actually SVGs are supported right out of the box with Vue CLI. It uses file-loader internally. You can confirm it by running the following command on the terminal:
vue inspect --rules
If "svg" is listed (it should be), then all you've got to do is:
<template>
<div>
<img :src="myLogoSrc" alt="my-logo" />
</div>
</template>
<script lang="ts">
// Please just use `#` to refer to the root "src" directory of the project
import myLogoSrc from "#/assets/myLogo.svg";
export default defineComponent({
name: "MyComponent",
setup() {
return {
myLogoSrc
};
}
});
</script>
So there's no need for any third party library—that is if your sheer purpose is only to display SVGs.
And of course, to satisfy the TypeScript compiler on the type declaration:
declare module '*.svg' {
// It's really a string, precisely a resolved path pointing to the image file
const filePath: string;
export default filePath;
}
Can't say for sure, since I haven't tried with ts, but as posted here
this should work.
declare module '*.svg' {
import type { DefineComponent } from 'vue';
const component: DefineComponent;
export default component;
}
I see you're using:
import * as MyLogo from "../../assets/myLogo.svg";
I believe that should be:
import MyLogo from "../../assets/myLogo.svg";
vue-svg-loader is not compatible with vue 3. To import svg and use it as a component, simply wrap the contents of the file in 'template'
In component:
<template>
<div class="title">
<span>Lorem ipsum</span>
<Icon />
</div>
</template>
<script>
import Icon from '~/common/icons/icon.svg';
export default {
name: 'PageTitle',
components: { Icon },
};
</script>
Webpack:
{
test: /\.svg$/,
use: ['vue-loader', path.resolve(__dirname, 'scripts/svg-to-vue.js')],
}
scripts/svg-to-vue.js:
module.exports = function (source) {
return `<template>\n${source}\n</template>`;
};
Example from fresh installed vue.js 3.2:
<img alt="Vue logo" class="logo" src="#/assets/logo.svg" width="125" height="125"/>

Categories