Unable to see my images when using Parcel - npm

I am trying to lazy load images using Javascript and when I run a server using parcel I can only see the images when the tag is assigned a src. But when I assign a data-src to the tag to implement the lazy loading, the images on the parcel server never show up. My JavaScript code is correct, I think there is a problem with parcel, anyone know how to fix this?
Here is my html and JS code:
<div class="photo__container photo__container--one">
<img
data-src="portrait/1-vertical.jpeg"
alt="image"
class="fade-in-img img-vertical-lazy"
/>
<img
data-src="portrait/2-vertical.jpeg"
alt="image"
class="fade-in-img img-vertical-lazy"
/>
<img
data-src="portrait/3-vertical.jpeg"
alt="image"
class="fade-in-img img-vertical-lazy"
/>
</div>
JS code:
//lazy-loading
const lazyImages = document.querySelectorAll('.img-vertical-lazy');
const appearLazy = {
threshold: 0.1
};
const lazyLoading = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (!entry.isIntersecting) return;
entry.target.src = entry.target.getAttribute('data-src');
lazyLoading.unobserve(entry.target);
});
}, appearLazy);
JS code:
lazyImages.forEach(image => lazyLoading.observe(image));

Related

Trying to load an image inside a assets/img folder in a v-for, but the images does not load

I'm trying to load the images in the assets/img folder in my vue3 project using a v-for inside a div, but they are not loading, just display my alt.
So, I have a vue component what will display a title and a paragraph and also a image. The images are in the assets/img folder, I'm getting the path of the image with a store that I created. When I try to just put the path of the image like this: src="../assets/img/img2.jpg" the images renders.
Here is 1 of my state in the store.js:
content: [
{
headline: 'Teste',
paragraph: 'this is a paragraph',
img: '#/assets/img/img.jpg'
},]
Here is my template using the v-for:
<template>
<div>
<div
class="slider"
v-for="item, i in content"
:key='i'
>
<h1>{{item.headline}}</h1>
<p>{{item.paragraph}}</p>
<img
:src="item.img"
alt="test"
/>
</div>
</div>
</template>
My setup:
setup () {
const store = useStore()
const content = store.getters.getContent
return { content }
}
I tryed to use :src="require(item.img)" but i got a webpack error by doing this:
Uncaught Error: Cannot find module '#/assets/img/img.jpg' webpackEmptyContext components sync:2
Also tryed to point the folder of the images in the src, :src="#/assets/img + item.img", but it didn't work.
I met this question before.
Maybe the following code could help you.
// create a function in util.js
export const getSrc = ( name ) => {
const path = `/src/assets/img/${name}`
const modules = import.meta.globEager('/src/assets/img/*.jpg')
return modules[path].default
}
// use getSrc in someItem.vue
import { getSrc } from '#/util/util.js'
content: [
{
headline: 'Teste',
paragraph: 'this is a paragraph',
img: getSrc('img.jpg')
}
]

How to place image address in array and use that array index in source VUE JS?

I’m new into vue js and I’m facing a little issue. I’m sure that its a minor issue as I’m new into it can’t able to solve it by myself. Any suggestion or solution will be acknowledge.
Thing is I want to store image address (images that will be in assets directory) in an array & then I want to pass those address as a source to img tag. for instance following is the code:
<div class="text-h2" v-for="img in imgs" :key="img">
<img src="{{img}}" alt="">
</div>
where the image source will be saved in src array:
export default {
name: 'Home',
data: () => ({
imgs: ['./assets/img1.png','./assts/img2.png' ],
}),
ANY HINT WILL BE REALLY APPRECIATED
You can create method:
methods() {
getImage(imagePath) {
return require(imagePath);
}
}
Then in template call that method:
<img :src="getImage(img)" alt="">
With :src you bind image source to img from array imgs.

How to load an External SVG into Vue as an Object

I need to load an SVG file into a Vue template. It must be loaded in such a way that I can access the internal classes with js and css, so presumably I'm looking for an <object> tag and not an <img> tag.
The SVG is located on an external server, not a part of my project. Vue-Svg-Loader works just fine if I have the svg as part of my project, but doesn't seem to work when the SVG isn't available until runtime.
I've tried the following
<template>
<div ref="floorplan" id="floorplan-frame">
<object
type="image/svg+xml"
id="floorplan"
:data="svgPath"
></object>
</div>
</template>
<script>
export default {
data() {
return {
svgPath: 'http://test-mc4/floorplan.svg',
};
},
};
</script>
Unfortunately it doesn't work. If I replace the <object> tag with <img :src="svgPath" /> it does show the SVG, but as a static image where the internal css classes are not available. It does show me that my path is correct and the file is actually available, but it doesn't explain why the object tag is just empty when I use it.
I've searched extensively and I can figure out how to load it as an Object if it's internal, or how to load it External as long as it's an image. I just can't seem to figure out how to do both.
In order to access the elements within an <object>, you'd need to wait until it was loaded (load event) and then access the child SVG document by its contentDocument property.
Unfortunately, this won't work in your case because the SVG files are coming from a different origin. The same-origin policy will block access to the contentDocument. Here is an example, which also fails (logs null) because a data: URL is a different origin:
const svgPath = 'data:image/svg+xml;charset=utf-8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+DQo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDIwIDIwIj4NCiAgICA8Y2lyY2xlIGN4PSIxMCIgY3k9IjEwIiByPSIxMCIgZmlsbD0icmVkIi8+DQo8L3N2Zz4=';
const app = new Vue({
el: '#app',
data: {
svgPath,
},
methods: {
svgLoaded() {
setTimeout(() => {
console.log(this.$refs.object.contentDocument);
}, 1000);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<object
ref="object"
:data="svgPath"
width="100"
height="100"
v-on:load="svgLoaded"
></object>
</div>
The only way to load an SVG from a different origin and then access its internal structure with your JS and CSS would be to fetch it and then load it into your component as v-html. Note that this opens significant XSS vulnerabilities; you should be wary of this option and only use it with external servers you trust. In any case, here's a working example:
const svgPath = 'data:image/svg+xml;charset=utf-8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+DQo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDIwIDIwIj4NCiAgICA8Y2lyY2xlIGN4PSIxMCIgY3k9IjEwIiByPSIxMCIgZmlsbD0icmVkIi8+DQo8L3N2Zz4=';
const app = new Vue({
el: '#app',
data: {
svgData: '',
},
async mounted() {
const svgResponse = await fetch(svgPath);
this.svgData = await svgResponse.text();
await Vue.nextTick();
// SVG is present in the DOM at this point
const svg = this.$refs.drawing.firstElementChild;
console.log(svg.outerHTML);
// DOM manipulations can be performed
const circle = svg.querySelector('circle');
circle.setAttribute('fill', 'blue');
circle.setAttribute('r', '6');
}
});
.drawing {
width: 100px;
height: 100px;
}
/* SVG can be styled as part of the main document */
.drawing circle {
stroke: cyan;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div
class="drawing"
ref="drawing"
v-html="svgData"
></div>
</div>

Replace image with placeholder on src change

I have an image with a bound src value
<img :src="image.url">
When image.url gets updated, the old image stays in place until the new image is loaded. This can look a little weird as the new image lags behind the text details on change.
How can I replace the image with a loading indicator when the src property changes with vue.js?
I could add DOM manipulation with the code that triggers the change and that works, but I'd rather do it properly with vue bindings.
This should get you on the right track:
Have an imageLoading attribute in your data() function.
Set your :src as follows: <img :src="imageLoading ? ./myPlaceholder.png : image.url" />
$watch your image.url to set the loading image whenever it changes:
watch: {
'image.url': function() {
this.imageLoading = true;
}
Add an #load handler to your img tag to set imageLoading to false when the image loads: <img :src="imageLoading ? ./myPlaceholder.png : image.url" #load="imageLoading = false" />
Note on the #load handler - shamelessly stolen from this question, which does link to an example.
This is a basic image placeholder component that uses slots to display any placeholder content
<template>
<div class="image">
<img :src="src" #load="ready = true" v-show="ready">
<slot v-if="!ready" />
</div>
</template>
<script>
export default {
props: ['src'],
data: () => ({
ready: false
}),
watch: {
src () { this.ready = false }
}
}
</script>
to use it
<image-placeholder src="IMAGE_URL">
<b>PLACEHOLDER CONTENT HERE</b>
<p>Can be anything</p>
<img src="ANOTHER_IMAGE_URL" />
</image-placeholder>

Vue fallback to asset images

I have a bunch of entities I want to display on a page in a Vue 3 application. Each entity should have an image URL. If an entity does not have such a URL, I want to display a default image that's stored in /src/assets/images/default.png
So I've created a computed property that returns the image URL, either entity.url or the URL above.
Unfortunately, this doesn't work, instead of getting the default image I'm getting no image, and the Vue dev webserver returns index.html. This is because Vue's handling of static assets doesn't work when the static asset URL is returned in runtime.
The image is shown properly if I hard-code the URL #/assets/images/default.png, but not if I return this as a string (dropping the # makes no difference).
How can I make Vue handle static assets that are referenced dynamically?
I'd use v-if/v-else to show the appropriate image based on whether entity.url exists ..
<img v-if="entity.url" :src="entity.url" />
<img v-else src="#/assets/images/default.png" />
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
imageData:{ imgUrl:'https://upload.wikimedia.org/wikipedia/commons/thumb/f/f9/Wiktionary_small.svg/350px-Wiktionary_small.svg.png',
}
},
methods: {
getUrlData(data) {
if (data && data.imgUrl) {
return data.imgUrl
}
else {
return "#/assets/images/default.png"
}
}
}
})
<div id="app">
<p>{{ message }}</p>
<img :src="getUrlData(imageData)">
</div>
Try this should work in your case! and let me know if you are getting any errors
In Vue 3, you can put an #error event on the image, so if the URL returns a 404, you can execute arbitrary logic:
<script setup>
import { ref } from 'vue';
const isProfileImageBroken = ref(false);
const handleBrokenImage = () => {
console.log('image broke');
isProfileImageBroken.value = true;
};
</script>
<template>
<i v-if="!auth.user.image || isProfileImageBroken" class="icon-user icon-lg"></i>
<img
v-if="auth.user.image && !isProfileImageBroken"
:src="auth.user.image"
class="w-6 h-6 rounded-full object-cover"
#error="handleBrokenImage"
>
</template>