I'm trying to dynamically upload images into a vuetify carousel component from a folder I've added to the project path called 'Main'.
My component looks like:
<template>
<v-carousel>
<v-carousel-item v-for="(item,i) in items" :key="i" :src="item.src"></v-carousel-item>
</v-carousel>
</template>
<script>
function getImagePaths() {
// var images = require.context('../../main/img/', false, /\.png$/)
var images = require.context("../../main/", false, /\.png$/);
// var images = require.context('/main/', false, /\.png$/)
console.log("images", images);
return images;
}
export default {
methods: {
imgUrl: getImagePaths()
}
};
I'm getting the:
NuxtServerError: Cannot find module 'undefined'
(screenshot above) How can I fix this?
EDIT: if I change the Script tag to:
<script>
// function getImagePaths() {
// // Load locally as a function.
// const fs = require("fs-extra");
// var requireContext = require("require-context");
// // var images = require.context('../../main/img/', false, /\.png$/)
// var images = require.context("../../main/", false, /\.png$/);
// // var images = require.context('/main/', false, /\.png$/)
// console.log("images", images);
// return images;
// }
// export default {
// methods: {
// imgUrl: getImagePaths()
// }
// };
export default {
data () {
return {
items: [
{
src: 'https://cdn.vuetifyjs.com/images/carousel/squirrel.jpg'
},
{
src: 'https://cdn.vuetifyjs.com/images/carousel/sky.jpg'
},
{
src: 'https://cdn.vuetifyjs.com/images/carousel/bird.jpg'
},
{
src: 'https://cdn.vuetifyjs.com/images/carousel/planet.jpg'
}
]
}
}
}
</script>
It works as expected.
Related
This is my first question so I'll try to explain the problem as much as I can.
I'm working on a Vue3 project, where I have a component that receives props, these props are treated as proxys in Vue (reactivity purposes).
The problem comes when reading the data. The proxy's target seems to have data, but when console.log() the object.property, shows undefined:
console.log(this.slideResults)
console.log(JSON.parse(JSON.stringify(this.slideResults)))
My component:
export default defineComponent({
props: {
takenImage: HTMLImageElement,
slideResults: Object, // slideResults = {[opencvResults], [possibleDuplicatedImages]}
},
components: { Swiper, Slide, SwiperSlide },
computed: {
getImages() {
// console.log the prop -> target = Object{canvasResults: canvas, possibleDuplicatedImages: }
console.log(this.slideResults);
const slideResults = JSON.parse(JSON.stringify(this.slideResults));
console.log(slideResults);
console.log(slideResults.canvasResults);
console.log(slideResults.possibleDuplicatedImages);
// To destructure props and don't lose reactivity we need to convert them into ref
// const { slideResults } = toRaw(this.slideResults);
// console.log(slideResults);
// const { canvasResults, possibleDuplicatedImages } = toRaw(
// this.slideResults
// );
// console.log(canvasResults[0]);
// console.log(this.takenImage);
// // In order to pass to a slide the images as: Array<Object> where [{imageFile, canvas}]
// /**
// * #type {Array<{ image: HTMLCanvasElement[], opencvResult: File[] }>}
// */
const images = [];
// for (let i = 0; i < canvasResults.length; i++) {
// images.push({
// image: possibleDuplicatedImages[i],
// opencvResult: canvasResults[i],
// });
// }
// console.log(images);
return images;
},
},
});
I have also tried with this, where the logs return the same as above:
export default defineComponent({
props: {
takenImage: HTMLImageElement,
slideResults: Object, // slideResults = {[opencvResults], [possibleDuplicatedImages]}
},
components: { Swiper, Slide, SwiperSlide },
setup(props) {
/**
* Returns the images to use in the slides
*/
const getImages = () => {
// To destructure props and don't lose reactivity we need to convert them into ref
const { slideResults } = toRefs(props);
const { canvasResults, possibleDuplicatedImages } = toRaw(
slideResults.value
);
console.log(canvasResults);
console.log(possibleDuplicatedImages);
console.log(props.takenImage);
// In order to pass to a slide the images as: Array<Object> where [{imageFile, canvas}]
/**
* #type {Array<{ image: HTMLCanvasElement[], opencvResult: File[] }>}
*/
const images = [];
for (let i = 0; i < canvasResults.length; i++) {
images.push({
image: possibleDuplicatedImages[i],
opencvResult: canvasResults[i],
});
}
console.log(images);
return images;
};
return {
modules: [Autoplay, Keyboard, Pagination, Zoom, Navigation],
getImages,
};
},
});
I'm using a Popup style UI component in a Nuxt.js base project. This is used by many pages and routes, so I declared and initiated as global component plugin when the app starts, like below:
// nuxt.config.js
plugins: [
{ src: '~/plugins/popup/index.js', mode: 'client' },
],
// plugins/toast/index.js
import Vue from 'vue';
import PopupComponent from './Popup.vue';
const PopupConstructor = Vue.extend(PopupComponent);
export default () => {
Vue.use({
install: () => {
let _popup = new PopupConstructor();
window.popup = Vue.prototype.popup = {
appear: _popup.appear,
disappear: _popup.disappear
};
_popup.vm = _popup.$mount();
_popup.dom = _popup.vm.$el;
document.body.appendChild(_popup.dom);
}
});
};
// Popup.vue
// some edit applied for the sake of simplicity
<template>
<div
class="popup"
:class="{
'--error': error,
'--visible': visible
}"
ref="popup"
>
<div class="content" ref="content">
<div class="title">{{title}}</div>
<div class="text">{{detail}}</div>
</div>
</div>
</template>
import gsap from 'gsap';
export default {
data: function () {
return {
visible: false,
title: '',
detail: '',
timer: 3000,
timeout: null,
animationTimeout: null,
};
},
created() {
},
mounted() {
this.$_appear = null;
this.$_disappear = null;
},
beforeDestroy() {
this.$_appear.kill();
this.$_appear = null;
this.$_disappear.kill();
this.$_disappear = null;
},
appear({ title, detail }) {
if (this.visible) {
this.clearTimeout();
}
this.visible = true;
this.$_appear.kill();
this.$_disappear.kill();
this.title = title;
this.detail = detail;
this.$_showAni = gsap.to(this.$refs.popup, 0.5, {
css: {
top: '100px',
opacity: 1
},
onComplete: () => {
this.$_appear = null;
}
});
this.timeout = window.setTimeout(() => {
this.disappear();
}, this.timer);
},
disappear() {
this.clearTimeout();
this.$_disappear.kill();
this.$_disappear = gsap.to(this.$refs.popup, 0.5, {
css: {
top: '100px',
opacity: 0
},
onComplete: () => {
this.$_disappear = null;
this.visible = false;
}
});
},
clearTimeout() {
if (this.timeout) {
window.clearTimeout(this.timeout);
this.timeout = null;
}
}
}
As you see, by this code the Popup vue component's methods(appear, disappear) will be accessible through window.popup, and the component itself will be created, mounted, attached on document.
This works just fine, but the problem is it seems this leads to memory leak. As I profile the memory allocation timeline using Chrome devtool, from some point of time memory allocated with window causes retained(dangling?; could be GC-ed but left due to reference using?) memory.
Is the usage of plugin like above okay? If not, to get the same utility while preventing memory leak, which part should be corrected?
EDIT:
I added the simple version implementation code for Popup which uses GSAP library for an animation. It uses the animation for appear and disappear sequentially.
In a Vue.js application, I have fetched a product based on provided route id.
Product object in an array has pictures.
I want to create a copy of reactive data "mosaicImagesList" that is reflected once the product is fetched, and it should have following structure:
[
{
"url": "https://via.placeholder.com/650x250",
"isWide": true,
"isTall": false
},
{
"url": "https://via.placeholder.com/350x150",
"isWide": true,
"isTall": false
}
]
It shows an output in console.log, but it shows an empty list of array in the rendered page.
Here is my code:
export default {
name: 'products.show',
data () {
return {
slide: 0
}
},
computed: {
product () {
return this.$store.state.product
},
images () {
const items = this.product.picture || []
const result = []
items.forEach(image => {
const img = new Image()
img.addEventListener('load', function () {
const isWide = img.width > img.height
const isTall = img.height > img.width
result.push({ url: image, isWide, isTall })
})
img.src = image
})
console.log(result) // <--- THIS WORKS IN THE CONSOLE LOG DEV TOOL
return result
}
},
methods: {
async fetchProduct () {
await this.$store.dispatch('products/getById', this.$route.params.id)
}
},
async created () {
await this.fetchProduct()
}
}
Here is the HTML section:
<div class="image-mosaic">
<div
v-for="(image, index) in images"
:key="index"
:style="`background-image: url('${image.url}')`"
class="card" />
</div>
The for..in-loop iterates over the enumerable properties of an Object.
As images is an Array the solution might be to use a for..of-loop.
i'm learning vue and i have small problem.
I've created code, which receive some informations from webserwer (via socket) and this code works fine.
But i would like to do very simple thing - display info as variable in HTML and i have problem with it.
My code is:
export default {
components: {
BCard,
BButton,
},
data() {
return {
connection: null,
json: {
cmd: 'start',
width: 1024,
height: 800,
url: 'https://www.google.com',
token: '',
service_id: 1,
thumbnail_width: 100,
thumbnail_height: 100,
},
}
},
created() {
console.log('Starting Connection to WebSocket')
this.connection = new WebSocket('ws://127.0.0.1:8080/')
// this.connection = new WebSocket('ws://echo.websocket.org')
this.connection.onopen = function (event) {
console.log(event)
console.log('Success')
}
this.connection.onmessage = webSocketOnMSG
},
methods: {
sendMessage(message) {
console.log(this.connection)
console.log(message)
console.log(JSON.stringify(message))
const dat = this.connection.send(JSON.stringify(message))
console.log('TT', dat)
},
drawItem() {
const img = document.createElement('img')
const canvas = document.getElementById('canvasId')
img.src = 'http://image...'
img.onload = function (a) {
const h = a.target.height
const w = a.target.width
const c = canvas.getContext('2d')
canvas.width = w
canvas.height = h
c.drawImage(img, 0, 0)
document.getElementById('draw-image-test').appendChild(canvas)
}
},
webSocketOnMSG(msg) {
console.log(msg)
},
},
}
and i would like to add code like this:
data: {
xposition: 'xpos',
yposition: 'ypos'
}
but when i'm adding it to created earlier data() i have error, so this doesn't work:
data() {
xposition: 'xpos',
yposition: 'ypos',
return {...}
}
where should i add code to replace variables {{xposition}} and {{yposition}} in HMTL?
You must put your new variables inside your returned object in the data function, alongside your 'json' variable. You need to declare them first as empty values, and then add the proper values in your API call callback
data() {
return {
xposition: '',
yposition: '',
...
}
}
webSocketOnMSG(msg) {
// this will change your component's xposition property
this.xposition = msg.propertyYouWantToAccess
},
I am trying to get select the list of files(path) from directory and display it on the DOM,but in order to display data i have to first assign in vuejs data object.
mainRenderer
ipcMain.on("channel1", (e, args) => {
const files = getFileFromUserSelection();
e.reply("channel1", files); // sending to channel1 in app.vue
});
const getFileFromUserSelection = () => {
const files = dialog.showOpenDialog({
properties: ["multiSelections"]
});
if (!files) return;
return files;
};
App.Vue
<template>
<div>
<p v-for="file in files">{{file}}</p>
</div>
</template>
<script>
import { ipcRenderer } from "electron";
//this gets files from the main process
ipcRenderer.on("channel1", (e, files) => {
console.log(files); // i want this file into data:function()
});
export default {
data: function() {
return {
files: []
};
},
methods: {
clicked: function() {
ipcRenderer.send("channel1", "open dialog to getFiles from user");
}
}
};
</script>
You can use the beforeCreate hook on the Vuecomponent in order to hydrate the data property:
export default {
data: function() {
return {
files: []
};
},
beforeCreate() {
ipcRenderer.on("channel1", (e, files) => {
this.files = files
});
},
methods: {
clicked: function() {
ipcRenderer.send("channel1", "open dialog to getFiles from user");
}
}
};
Note that, of course, you cannot interact directly with the files array until you know it's been hydrated, so a computed getter here may be of some use to you, or just use files.length.