vuejs3: how to init a ref using a prop? - vuejs3

I have this codes
<script setup>
defineProps({
position: { type: String, required: false, default: "center middle" },
});
</scritp>
I am trying adding this after defineProps
const myPosition = ref(position);
But I got
Uncaught (in promise) ReferenceError: position is not defined
What am I doing wrong, and, important, why?

To initialize a prop using the "Component" API along with <script setup>, you will want to assign the object returned by the defineProps(...) macro a name, say props and use that variable name when referring to the props in your script. So if you have a prop declared like so:
const props = defineProps({
position: { type: String, required: false, default: "center middle" },
});
You can use it in the same script like so:
const myLocation = ref(props.position);
So, a complete example could look like so:
ParentComponent.vue
<template>
<div class="main-body">
<h1>Parent Component</h1>
<div class="grid-container">
<div>
Position (in Parent):
</div>
<div>
<input v-model="msg">
</div>
</div>
<hr>
<div>
<Child :position="msg" title="Child Component 1"/>
</div>
<div>
<Child title="Child Component 2 (default position property)"/>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
const msg = ref('North West')
</script>
<style>
.main-body {
margin: 10px 20px;
}
.grid-container {
display: grid;
grid-template-columns: 1fr 2fr;
}
</style>
and then
Child.vue
<template>
<h2>
{{ title }}
</h2>
<div class="grid-container">
<div>
Position (from parent):
</div>
<div>
{{ position }}
</div>
<div>
My Position:
</div>
<div>
<input type="text" v-model="myLocation">
</div>
<div>
My Position:
</div>
<div>
{{ myLocation }}
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
const props = defineProps({
position: { type: String, required: false, default: "center middle" },
title: { type: String, required: false, default: "ChildComponent"}
});
const myLocation = ref(props.position);
</script>
<style scoped>
.grid-container {
display: grid;
grid-template-columns: 1fr 2fr;
}
</style>
Also, please check out this code in the Vue Playground
In this example, the myPosition field is initialized with the prop, but then once the application has been launched, this field is no longer dependent on the prop.

At first, you code is not fully enough. Where do you try to const myPosition = ref(position);?
If you define your props right, then there is no need to apply ref or reactive to them. They are reactive already.
Simply use now you position in the component.
Here is the sample from the Vue Tutorial Step 12 Props
<!-- ChildComp.vue -->
<script setup>
const props = defineProps({
msg: String
})
</script>
and
<ChildComp :msg="greeting" />

Related

how to add Vue props value to background-image

I'm new in VueJS and I get confused to change background image from Vue props value.
I've created simple table from 'vue3-easy-data-table'.
BaseTable.vue:
<template>
<EasyDataTable>
...
</EasyDataTable>
</template>
<script setup lang="ts">
changeImg: {
type: String,
}
})
</script>
<style>
.vue3-easy-data-table__message {
background-image: url("`${v-bind("changeImg")}`");
/* background-image: var(--image-url); */
/* background-image: url('#/assets/img/noDataMultiplierOnCity.svg'); */
}
</style>
View.vue:
<template>
<BaseTable
:changeImg= "image"
/>
</template>
<script lang="ts" setup>
const image : string = "'#/assets/img/noDataMultiplierOnCity.svg'"
</script>
I've tried solution from this link https://stackoverflow.com/questions/42872002/in-vue-js-component-how-to-use-props-in-css but no gain.
Already tried as in the comments in the code, in this case I can just style the component in style tag cause the class is from 'vue3-easy-data-table' (maybe have another way to apply style to it?)
I want to make the background image from BaseTable so it can be reused in other file.
I hope I understood you right and this example will help you
template:
<div :style="styleExample" />
script:
let styleExample = { 'width': props.examplePro }
One way to solve this is to use an inline reactive style. For example you could give your script a method that convers the prop into a style, one that holds the image and any other defining features:
<template>
<EasyDataTable :style="backgroundStyles(image)">
...
</EasyDataTable>
</template>
<script setup>
changeImg: {
type: String,
}
})
const backgroundStyles = (img) => {
return {
'background-image': `url(${img})`,
'background-size': 'cover'
}
}
</script>
code:
App.vue
<script setup>
import { ref } from 'vue'
import BaseTable from './BaseTable.vue'
import BaseTable2 from './BaseTable2.vue'
const msg = ref('Hello World!')
const imageUrl = ref("https://cdn.mos.cms.futurecdn.net/SWx64q2g3wax53Xz5H4QjS-970-80.jpg.webp");
</script>
<template>
<h1>{{ msg }}</h1>
<input v-model="msg">
<BaseTable :image="imageUrl"/>
<hr>
<BaseTable2 :image="imageUrl"/>
</template>
BaseTable.vue
<template>
<div class="bkgrnd" :style="backgroundStyles(image)">
<h2>
Base Table
</h2>
<ul v-for="index in 8" :key="index">
<li>Index: {{ index }}</li>
</ul>
</div>
</template>
<script setup>
const props = defineProps(['image'])
const backgroundStyles = (img) => {
return {
'background-image': `url(${img})`,
'background-size': 'cover'
}
}
</script>
<style scoped>
.bkgrnd {
color: white;
font-style: bold;
}
</style>
Solution using the prop in the CSS
Another way to do this can be to avoid inline styles and instead display the background image in the <style> CSS code. To do this, I would use a computed property to create a URL from the prop, something like:
const computedUrl = computed(() => {
return `url(${props.image})`;
});
Code example,
BaseTable2.vue
<template>
<div class="bkgrnd">
<h2>
Base Table 2
</h2>
<ul v-for="index in 8" :key="index">
<li>Index: {{ index }}</li>
</ul>
</div>
</template>
<script setup>
import { computed } from 'vue';
const props = defineProps(['image'])
const computedUrl = computed(() => {
return `url(${props.image})`;
});
</script>
<style scoped>
.bkgrnd {
color: white;
font-style: bold;
background-image: v-bind(computedUrl);
}
</style>
Both examples can be found at the Vue SFC Playground

Vue.3 does not render Vuetify components when using at tag attribute in transition-group

I want to animate some cards using gsap for the following components in Vue.js 3.
<script setup lang="ts">
import gsap from 'gsap'
import { useTranslate } from '#/#core/composable/useTranslate'
import TimeLineItem from './TimeLineItem.vue'
interface ITimeLine {
icon: string
title: string
description: string
color: string
}
const timeLines = ref<ITimeLine[]>([
{
title: 'PadvishInstall',
description: 'timeline-welcome',
icon: 'material-symbols:looks-one-outline',
color: 'warning',
},
{
title: 'InsertingToken',
description: 'timeline-step1',
icon: 'ic:outline-looks-two',
color: 'error',
},
{
title: 'ContactInfo',
description: 'timeline-step2',
icon: 'ph:number-square-three-bold',
color: 'info',
},
])
const { translate } = useTranslate()
/**
* Functions
*/
const beforeEnter = (el: Element) => {
const he = el as HTMLElement
he.style.opacity = '0'
he.style.transform = 'translateX(100px)'
}
const enter = (el: Element, done: () => void) => {
const he = el as HTMLElement
gsap.to(el, {
opacity: 1,
x: 0,
duration: 0.8,
onComplete: done,
delay: Number((el as HTMLElement).dataset.index) * 0.5,
})
}
</script>
<template>
<VCard class="text-center" variant="text" title="card title">
<VCardText>
<transition-group
align="start"
justify="center"
truncate-line="both"
:density="$vuetify.display.smAndDown ? 'compact' : 'default'"
appears
#before-enter="beforeEnter"
#enter="enter"
tag="v-timeline"
>
<TimeLineItem
v-for="(item, index) in timeLines"
:key="index"
:data-index="index"
:title="translate(item.title)"
:description="translate(item.description)"
:icon="item.icon"
:color="item.color"
/>
</transition-group>
</VCardText>
</VCard>
</template>
TimeLineItem component :
<script setup lang="ts">
interface Props {
icon: string
title: string
description: string
color: string
}
const props = defineProps<Props>()
</script>
<template>
<VTimelineItem size="x-small" fill-dot>
<template #icon>
<div class="v-timeline-avatar-wrapper rounded-circle">
<VAvatar size="small">
<VIcon size="100" :icon="icon" :color="color" />
</VAvatar>
</div>
</template>
<VCard>
<VCardText>
<!-- 👉 Header -->
<div class="d-flex justify-space-between">
<h6 class="text-base font-weight-semibold mb-1 me-3">
{{ title }}
</h6>
</div>
<!-- 👉 Content -->
<p class="mb-1">
{{ description }}
</p>
</VCardText>
</VCard>
</VTimelineItem>
</template>
<style lang="scss" scoped>
.v-timeline-avatar-wrapper {
background-color: rgb(var(--v-theme-background));
}
</style>
For animating each element of v-timeline, I used transition-group and set the value of tag to v-timeline. But, when using transition-group, the Vue does not recognize the 'v-timeline' is a vuetify component and must render a component!.
This is a limitation of transition-group or can be considered as a bug in Vue.3?

How to use <i18n-t> in Web component?

I'm creating a Vue web component using i18n
And I wanna put a span tag with color in
here is my code demo.
I wanna know how to import
<!-- custom-element.ce.vue -->
<script setup>
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const locale = ref('en')
defineProps({
locale: String,
})
</script>
<template>
<div classs="custom-ele-wrap">
<i18n-t keypath="title" tag="span">
<template #text>
<span :class="['locale-text', locale']"> {{ localeText }} </span>
</template>
</i18n-t>
</div>
</template>
<style scoped>
.locale-text.en {
color: blue;
}
.local-text.zh-TW {
color: red;
}
</style>
// <!-- i18n json -->
{
"en": {
"title": "{text} language",
},
"zh-TW": {
"title": "這是{text}語言",
}
}
but it shows
enter image description here

How to obtain data in child component in Vue.js 3?

I have a Date component that contains a calendar and time. I can select a date and time from this. I have another component called DatePopup that shows a calendar and time as a popup. This component contains OK and Cancel buttons. If a user selects OK, I want to get the date reactive variable in child component, i.e., Date.
How can I achieve this structure so that I can obtain the data from parent component?
Note that I use Quasar.
Date.vue
<template>
<div class="q-pa-md q-gutter-sm">
<q-badge color="yellow-illerarasi-film-teskilati" text-color="black">
Deadline: {{ date.full }}
</q-badge>
</div>
<div class="q-gutter-md row items-start">
<q-date v-model="date.full" mask="YYYY-MM-DD HH:mm" color="yellow-illerarasi-film-teskilati" text-color="black"/>
<q-time v-model="date.full" mask="YYYY-MM-DD HH:mm" color="yellow-illerarasi-film-teskilati" text-color="black"/>
</div>
<p> {{ date }}</p>
</template>
<script>
import {reactive} from "vue";
export default {
name: "Date",
setup() {
let date = reactive({
full: "2022-01-01 00:00",
})
return {
date,
}
}
}
</script>
<style scoped>
</style>
DatePopup.vue
<template>
<div class="q-pa-md q-gutter-sm">
<q-dialog v-model="show">
<q-card style="width: 700px; max-width: 80vw;">
<q-card-section>
<div class="text-h6">Choose a Deadline</div>
</q-card-section>
<q-card-section class="q-pt-none">
<Date/>
</q-card-section>
<q-card-actions align="right">
<q-btn flat label="Cancel" color="primary" text-color="black" v-close-popup/>
<q-btn label="OK" color="yellow-illerarasi-film-teskilati" text-color="black" v-close-popup/>
</q-card-actions>
</q-card>
</q-dialog>
</div>
</template>
<script>
import Date from "./Date.vue";
import {reactive} from "vue";
export default {
name: "DatePopup",
components: {Date},
props: {
showPopup: {
type: Boolean,
default: true
}
},
setup(props) {
return reactive({
show: true
})
}
}
</script>
<style scoped>
</style>

How to change component css with props with Nuxt Js Vue js

I'm new to Nuxt and Vue, thanks for being indulgent ;).
I have a "Subtitle" component that I use in another "Main" component (names are for the example).
How can I change the css of the "subtitle" component from the "Main" component ?
Here "Subtitle" component :
<template>
<div>
<h1 :class="data">{{ title }}</h1>
</div>
</template>
<script>
export default {
name: 'subtitle',
props: {
title: String,
}
}
</script>
And here my "Main" component :
<template>
<div class="container">
<Subtitle :title="title""></Subtitle>
</div>
</template>
I searched with the props etc.... But now I've been on it for a while and I'm blocking.
Thanks for your help!
You can do it using the combination of props and computed
Subtitle Component
<template>
<div>
<h1 :style="getStyle">{{ title }}</h1>
</div>
</template>
<script>
export default {
name: 'subtitle',
props: {
stylings: Object,
},
computed: {
getStyle() {
return this.stylings;
}
}
}
</script>
Main Component
<template>
<div class="container">
<Subtitle :stylings="customStyle"></Subtitle>
</div>
</template>
export default {
name: 'subtitle',
data() {
return {
customStyle: {
'font-weight': 'Bold',
}
}
}

Resources