How to pass the src attribute of the img tag to the child component through the parent component in vue - vue.js

I have a parent component and a child component, and I want to pass a src attribute to the child component via defineProps to make it display the image.
Below is my parent component code:
<script setup>
import item from "./item.vue";
const items=[
{
id:0,
img:'../assets/2.png',
name:'秘塔写作猫',
des:'码文章必备工具'
},
{
id:1,
img:'../assets/2.png',
name:'AdblockPlus广告拦截',
des:'最流行的广告拦截拓展程序'
},
{
id:2,
img:'../assets/3.png',
name:'Tampermonkey油猴脚本',
des:'码文章必备工具'
},
{
id:3,
img:'../assets/4.png',
name:'蔚蓝主页',
des:'个性化简洁风格浏览器主页'
},
{
id:4,
img:'../assets/5.png',
name:'ABCD PDF',
des:'完全免费在线PDF压缩转换工具'
},
{
id:5,
img:'../assets/6.png',
name:'ASO谷歌商店工具',
des:'洞悉竞品下载、评论等核心数据'
},
]
</script>
<template>
<div id="ain">
<div id="head">
<h4>站长推荐</h4>
<a>查看全部</a>
</div>
<div id="body">
<item v-for="item in items" :key="item.id" :img="item.img" :name="item.name" :des="item.des">
</item>
</div>
</div>
</template>
Below is my subcomponent code:
<script setup>
defineProps(['img','name','des'])
</script>
<template>
<div id="item">
<div>
<img src="img">
<p>{{name}}</p>
<p id="detail">{{des}}</p>
</div>
</div>
</template>
This error is displayed in the console:GET http://127.0.0.1:5173/assets/2.png 404 (Not Found)
I think it's a problem with passing parameters, but I don't know how to modify it, thank you all.

There are two solutions
1.You can use an absolute path
2.Put your image in the public path under the root directory

It looks like you are using Vite and there are a few options to reference images:
Use import statements for images to obtain the image URL
import imgUrl from './assets/img.png'
document.getElementById('hero-img').src = imgUrl
Place images inside public folder and reference using /. For example if all images are contained inside public/img then the URL would be /img.
Try new URL(url, import.meta.url) although this does not work with SSR
Number 2) is probably the easiest if these images won't be updated.
Reference:
https://vitejs.dev/guide/assets.html

Related

Vue: Hand Over An Object To A Component For It To Use

In my app I have a list component which I use inside another component. Currently, it looks something like this:
<script setup>
const seed = [
{
key: value,
anotherKey: anotherValue,
},
// and so on...
];
</script>
<template>
<ul>
<li v-for="element in seed" :key="element.key" :anotherKey="element.anotherKey">
</ul>
</template>
My question is: Is it possible to somehow "hand over" an object inside the parent component which uses this list component instead of getting the object from within the list component's script tag?
You can use provide in your parent component to pass an object to your child components.
ParentComponent.vue (Untested code)
<script setup>
const seed = [
{
key: value,
anotherKey: anotherValue,
},
// and so on...
];
provide('seed', seed)
</script>
ChildComponent.vue
<script setup>
const seed = inject('seed')
</script>
<template>
<ul>
<li v-for="element in seed" :key="element.key" :anotherKey="element.anotherKey">
</ul>
</template>
You can read about provide in compositions.
https://vuejs.org/api/composition-api-dependency-injection.html

Accessing element within a component

I'm trying to access the root element a component with this.$children.$el, however, I'm getting undefined in the console. I can see the $el property on the object when I console.log(this.$children), so I'm not quite sure where I'm going wrong, any help would be greatly appreciated.
<template>
<div>
<Project
v-for="project in projects"
:key="project.sys.id"
:title="project.fields.title"
:images="project.fields.images"
/>
</div>
</template>
<script>
import Project from '~/components/Project'
export default {
mounted() {
const projects = this.$children.$el
},
components: {
Project
}
}
</script>
As stated in the vue.js documentation this.$children returns an array of children components. You could see your child component by printing this.$children[0] and its root element by priting this.$children[0].$el.
If you have many children components and want to target a specific one, you can tag your component with a ref attribute like below :
<template>
<div>
<Project
v-for="project in projects"
:key="project.sys.id"
:title="project.fields.title"
:images="project.fields.images"
ref="project"
/>
</div>
</template>
<script>
import Project from '~/components/Project'
export default {
mounted() {
console.log(this.$refs.project)
},
components: {
Project
}
}
</script>

How can you pass props into a modal dialog in vuejs?

In a Vuejs app, I have a modal dialog box pop up when user clicks a button. I need to pass a prop into this modal component. Normally, I have no trouble passing props to child components. Why is this case different? I'd rather not store any data in the store if avoidable. When the modal opens the prop collaboratorSelected is an empty String, i.e. it does not register the new prop value the parent is passing, but instead keeps the initial value set when the parent component mounts. This prop needs to be responsive.
Parent component...
<template>
<div>
<div v-for="collaborator in collaborators">
Edit
</div>
<EditShare #editedShare="editedShare" :collaboratorSelected="collaboratorToEdit" ref="modal" ></EditShare>
</div>
</template>
<script>
import axios from "axios";
import store from "../store.js";
import EditShare from "#/components/EditShare";
import $ from "jquery";
export default {
name: "Share",
data() {
return {
collaboratorToEdit: "",
collaborators: ["1", "2", "3"]
};
},
components: {
EditShare
},
methods: {
showEditShare(collaborator) {
this.collaboratorToEdit = collaborator;
let element = $('#editShare');
$(element).modal('show');
}
}
</script>
Child modal component...
<template>
<form #submit.prevent="handleSubmit">
<div class="modal" tabindex="-1" role="dialog" id="editShare">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<div class="modal-title card-title-bigger">Add Share</div>
{{collaboratorSelected}}
</div>
</div>
</div>
</div>
</form>
</template>
<script>
import axios from "axios";
import store from "../store.js";
import $ from "jquery";
export default {
name: "EditShare",
props: {
collaboratorSelected: String
},
</script>
I believe that given that you're using jQuery, the jQuery code is executing before the property value is propagated to the child component.
Try wrapping the jQuery code in a $nextTick method and see if that works. Something like this:
this.collaboratorToEdit = collaborator;
this.$nextTick(function(){
let element = $('#editShare');
$(element).modal('show');
});
I did some experiments in this pen and I was able to see how the code in the function doesn't wait for the property value to propagate (as you have it) and how it waits for it when using $nextTick.
Let me know if it works.

render a Vue slot in a layout from component

I'm having problems with a named slot. This seems like it should work. In the code below I'm trying to use a named slot "sidebar". I would expect my sidebar slot content to show up between the Sidebar starts and Sidebar ends text but nothing shows up in that slot. Everything renders in the main slot.
Here's my code.
route...
{
path: "/test",
name: "test",
meta: {
layout: "test-layout"
},
component: () =>
import("#/pages/Test.vue")
},
and App.vue template...
<template>
<div id="app">
<component :is="layout">
<router-view />
</component>
</div>
</template>
and test-layout...
<template>
<div>
<div>
<h1>Sidebar starts</h1>
<slot name="sidebar"/>
<h1>Sidebar ends</h1>
</div>
<div class="container">
<h1>Content starts</h1>
<slot/>
<h1>Content ends</h1>
</div>
</div>
</template>
and page Test.vue...
<template>
<test-layout>
<span slot="sidebar">sidebar slot content {{forecast.todaySummary}}</span>
<div>main slot content {{forecast.currentSummary}}</div>
</test-layout>
</template>
<script>
import api from "#/js/web-services";
export default {
data() {
return {
forecast: null
};
},
created() {
api.getDailyForecast().then(response => {
this.forecast = response.data;
});
}
};
</script>
and the import in my main.js
import TestLayout from "./layouts/test-layout.vue";
Vue.component('test-layout', TestLayout);
Why isn't my sidebar slot working?
UPDATE
If I get rid of the two lines in main.js and add
import TestLayout from "#/layouts/test-layout.vue";
and
export default {
components: { TestLayout },
data() {...
to Test.vue then it works.
In your router file you are using layout: "test-layout" this means what ever comes in your vue component will be rendered in base test-layout.
There are two ways as far as I know to render the layouts.
Do not define layout in router file and on parent component define named slots like this<slot #header></slot><slot #body></slot> then every slot will be rendered within this (test-layout) layout, and then in your each component extend like this <test-layout><template header>Header content</template><template body>Body content</template></test-layout>.
Defining layout in router file like you did, you can not further use in slots in that layout, you can just import other components e.g <template><Component1><Component2> </template>

Vue js loading js file in mounted() hook

I have the following Vue component:
<template>
<div id="wrapper">
<div class="main-container">
<Header />
<router-view/>
<Footer/>
</div>
</div>
</template>
<script>
import './assets/js/popper.min.js';
// other imports
// ....
export default {
name: 'App',
components : {
Header,
Footer
},
mounted(){
// this is syntax error
import './assets/js/otherjsfile.js'
}
}
</script>
As is clear from the code snippet, I want to have the otherjsfile.js loaded in mounted() hook. That script file has certain IIFEs which expects the html of the web page to be fully loaded.
So how do I invoke that js file in a lifecycle hook?
This is the pattern I use. The example is importing a js file which contains an IIFY, which instantiates an object on window.
The only problem with this would occur if you want to use SSR, in which case you need Vue's <ClientOnly> component, see Browser API Access Restrictions
mounted() {
import('../public/myLibrary.js').then(m => {
// use my library here or call a method that uses it
});
},
Note it also works with npm installed libraries, with the same path conventions i.e non-relative path indicates the library is under node_modules.
I'm a little unsure of what your asking. But if you are just trying to include an external js file in your page, you can just use the script tag in your template and not have to put anything in your mounted function, like this:
<template>
<div id="wrapper">
<div class="main-container">
<Header />
<router-view/>
<Footer/>
</div>
<script src="./assets/js/otherjsfile.js"></script>
</div>
</template>
<script>
import './assets/js/popper.min.js';
// other imports
// ....
export default {
name: 'App',
components : {
Header,
Footer
},
}
</script>
Does this solve your issue?