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

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

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?

Vue3 Composition Api check for empty slot

First project with Vue3, trying to determine if a named slot has content supplied on a given page.
In my template I have this:
<div
:class="{ 'py-20': hasTopContent }"
>
<slot name="top-content" />
</div>
In my code I have the following:
setup (_, { slots }) {
const hasTopContent = computed((slots) => {
console.log(slots.topContent);
return slots.topContent && slots.topContent().length;
});
return {
hasTopContent
}
}
The above console.log is returning TypeError: Cannot read properties of undefined (reading 'topContent'). What have I missed? Thanks!
Michal LevΓ½ is right
var Main = {
components: {
'my-component': MyComponent,
},
data() {
return {
}
},
methods: {
}
};
const app = Vue.createApp(Main);
app.mount("#app")
<html>
<head>
<style>
.my-component {
background-color: #fafafa;
padding: 5px 20px 20px 20px;
}
</style>
</head>
<body>
<div id="app">
<h3>With top slot</h3>
<my-component class='my-component'>
<template v-slot:top>
<h4>Top Slot</h4>
</template>
</my-component>
<h3>Without top slot</h3>
<my-component class='my-component'>
</my-component>
<hr style='padding: 20px 20px 20px 20px;' />
</div>
<script src="//unpkg.com/vue#next"></script>
<script type="text/x-template" id="my-component">
<div
:class="{ 'py-20': hasTopContent }">
<slot name="top" />
hasTopContent: {{hasTopContent}}
</div>
</script>
<script type="text/javascript">
var MyComponent = {
template: '#my-component',
setup(_, { slots }) {
const hasTopContent = Vue.computed(() => {
return slots.top && slots.top().length > 0;
});
return { hasTopContent }
}
}
</script>
</body>
</html>

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',
}
}
}

In vue.js component, how to use props in css?

I'm new to vue.js. Here is my problem:
In a *.vue file like this:
<template>
<div id="a">
</div>
</template>
<script>
export default {
name: 'SquareButton',
props: ['color']
}
</script>
<style scoped>
#a {
background-color: ?
}
<style>
How can I use the props color in background-color: (where is a ? now).
Thanks.
You actually can!
You should define the CSS variables in a Computed Property, then call the computed property as a style attribute to the element that will require the CSS variable, and finally you may use the variable within the tags at the bottom of your document.
new Vue({
el: '#app',
data: function() {
return {
baseFontSize: 1,
bgHoverColor: "#00cc00",
hoverContent: "Hovering!"
}
},
computed: {
cssProps() {
return {
'--hover-font-size': (this.baseFontSize * 2) + "em",
'--bg-hover-color': this.bgHoverColor,
'--hover-content': JSON.stringify(this.hoverContent)
}
}
}
})
div {
margin: 1em;
}
div.test:hover {
background-color: var(--bg-hover-color);
font-size: var(--hover-font-size);
}
div.test:hover::after {
margin-left: 1em;
content: var(--hover-content);
}
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app" :style="cssProps">
<div>Hover text: <input type="text" v-model="hoverContent"></div>
<div>Hover color: <input type="color" v-model="bgHoverColor"></div>
<div class="test">Hover over me</div>
</div>
Or have a look here: https://codepen.io/richardtallent/pen/yvpERW/
And here: https://github.com/vuejs/vue/issues/7346
You don't. You use a computed property and there you use the prop to return the style of the div, like this:
<template>
<div id="a" :style="style" #mouseover="mouseOver()">
</div>
</template>
<script>
export default {
name: 'SquareButton',
props: ['color'],
computed: {
style () {
return 'background-color: ' + this.hovering ? this.color: 'red';
}
},
data () {
return {
hovering: false
}
},
methods: {
mouseOver () {
this.hovering = !this.hovering
}
}
}
</script>
<style scoped>
<style>
As we are in 2020 now, I suggest using this trick with a css function called var
<template>
<div id="a" :style="cssVars"></div>
</template>
<script>
export default {
props: ['color'],
computed: {
cssVars () {
return{
/* variables you want to pass to css */
'--color': this.color,
}
}
}
<script>
<style scoped>
#a{
background-color: var(--color);
}
</style>
This method is very useful because it allows you to update the passed values through css later on (for example when you apply hover event).
credit
I know we're talking vue 2 here, but in case anyone from vue 3 lands in this question (like I did), vue 3 introduced a much cleaner way to do this:
<template>
<div id="a">
</div>
</template>
<script>
export default {
name: 'SquareButton',
props: ['color']
}
</script>
<style scoped>
#a {
background-color: v-bind(color);
}
<style>
What Vue actually does behind the scenes is the same "introducing css variables through component's style process", but it sure looks much better on the eyes now.
Documentation source: https://v3.vuejs.org/api/sfc-style.html#state-driven-dynamic-css
Why not just use :style prop in this way:
<template>
<div :style="{ backgroundColor: color }">
</template>
<script>
export default {
props: {
color: {
type: String,
default: ''
}
}
}
</script>
Make sure you define css properties in camelCase style.
If you need css that can't be applied by a style attribute like pseudo classes or media queries, what I do is the following:
Create a globally available style component when initializing Vue (you need it as otherwise you run into linting issues). It creates a style tag that simply renders the content in the slot:
I would only use this if you really need both dynamic values in your css and css features that can't be applied to a style attribute.
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
Vue.component('v-style', {
render: function(createElement) {
return createElement('style', this.$slots.default)
}
})
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
Then use it at the top of your template like this and you get the full JavaScript scope of your component and the full css syntax combined:
<template>
<v-style>
#media screen and (max-width: 820px) {
.gwi-text-media-{{ this.id }} {
background-image: url({{ mobileThumb }});
}
}
</v-style>
</template>
It seems a bit hacky to me, but it does it's job and I would rather go like this in some cases than having to add additional JS for mouse-over or resize events that have a big potential to slow down your application performance.
Vue 3 added new way of binding styles, so now you can easily bind your props to css properties.
Read source:
https://learnvue.co/2021/05/how-to-use-vue-css-variables-reactive-styles-rfc/
<template>
<div>
<div class="text">hello</div>
</div>
</template>
<script>
export default {
data() {
return {
color: 'red',
}
}
}
</script>
<style>
.text {
color: v-bind(color);
}
</style>
You could utilise the CSS var(--foo-bar) function. It is also useful if you are trying to pass an asset that has its own dynamic path, like Shopify does.
This method also works for styling the :before and :after elements as they refer back to the style applied on the owner element.
Using the original post example for passing a colour:
<template>
<div
id="a"
:style="{ '--colour': color }">
</div>
</template>
<script>
export default {
name: 'SquareButton',
props: ['color']
}
</script>
<style scoped>
#a {
background-color: var(--colour);
}
</style>
Using the original post example for passing an URL:
<template>
<div
id="a"
:style="{ '--image-url': 'url(' + image + ')' }">
</div>
</template>
<script>
export default {
name: 'SquareButton',
props: ['image']
}
</script>
<style scoped>
#a {
background-url: var(--image-url);
}
</style>
Source

Resources