I have the following code, that prints the menu Icon but doesn't adapt to the size of the screen:
<template>
<menuIcon />
</template>
<script setup>
let menuIcon = <svg aria-hidden="true" focusable="false" data-prefix="far" data-icon="bars" class="svg-inline--fa fa-bars fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg>;
</script>
Previously you could do the following:
<script>
import menuIcon from '#assets/Icons/bars.svg';
export default {
name: "Navigation",
components: {
menuIcon,
},
};
</script>
And it worked properly; where is the best option to use script setup to use an svg image?
thanks in advance!
I'm trying to use svg image in script setup cpnfiguration.
Related
Using Vue 3.2.41 - #heroicons/vue 2.0.14 - inertiajs 1.0 - vite 4.0.0
I'm calling a Vue component using this:
<TimelineItem icon="CalendarDaysIcon" />
The component looks like this:
<template>
<component :is="icon" /> <!-- doesn't work -->
<CalendarDaysIcon /> <!-- works -->
</template>
<script setup>
import {
CalendarDaysIcon,
} from '#heroicons/vue/20/solid'
const props = defineProps(['icon'])
</script>
The HTML being rendered is like this:
<calendardaysicon></calendardaysicon> <!-- not what I want -->
<svg> ... </svg> <!-- correct but not dynamic -->
In other words, the <component :is /> is just rendering some empty <calendardaysicon> tags when I'd expect it to render the component. I can see that it has made it lowercase and have no idea how to force it back to PascalCase and I'm not even sure if that would help the situation.
I've simplified the code somewhat, but the full version would have a list of 10 different icons (all part of the Heroicons package which uses PascalCase names) which I'd like to be able to call easily from the main component.
If you are authoring your templates directly in a DOM (e.g. as the content of a native element), the template will be subject to the browser's native HTML parsing behavior. In such cases, you will need to use kebab-case and explicit closing tags for components https://vuejs.org/guide/essentials/component-basics.html#dom-template-parsing-caveats
Try: <calendar-days-icon> </calendar-days-icon>
const { createApp, createElementVNode, openBlock, createElementBlock } = Vue;
const CalendarDaysIcon = {
render(_ctx, _cache) {
return (openBlock(), createElementBlock("svg", {
xmlns: "http://www.w3.org/2000/svg",
viewBox: "0 0 20 20",
fill: "currentColor",
"aria-hidden": "true"
}, [
createElementVNode("path", { d: "M5.25 12a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H6a.75.75 0 01-.75-.75V12zM6 13.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V14a.75.75 0 00-.75-.75H6zM7.25 12a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H8a.75.75 0 01-.75-.75V12zM8 13.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V14a.75.75 0 00-.75-.75H8zM9.25 10a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H10a.75.75 0 01-.75-.75V10zM10 11.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V12a.75.75 0 00-.75-.75H10zM9.25 14a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H10a.75.75 0 01-.75-.75V14zM12 9.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V10a.75.75 0 00-.75-.75H12zM11.25 12a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H12a.75.75 0 01-.75-.75V12zM12 13.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V14a.75.75 0 00-.75-.75H12zM13.25 10a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H14a.75.75 0 01-.75-.75V10zM14 11.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V12a.75.75 0 00-.75-.75H14z" }),
createElementVNode("path", {
"fill-rule": "evenodd",
d: "M5.75 2a.75.75 0 01.75.75V4h7V2.75a.75.75 0 011.5 0V4h.25A2.75 2.75 0 0118 6.75v8.5A2.75 2.75 0 0115.25 18H4.75A2.75 2.75 0 012 15.25v-8.5A2.75 2.75 0 014.75 4H5V2.75A.75.75 0 015.75 2zm-1 5.5c-.69 0-1.25.56-1.25 1.25v6.5c0 .69.56 1.25 1.25 1.25h10.5c.69 0 1.25-.56 1.25-1.25v-6.5c0-.69-.56-1.25-1.25-1.25H4.75z",
"clip-rule": "evenodd"
})
]))
}
}
const TimeLineItem = {
props: ['icon'],
components: {
CalendarDaysIcon
},
template: '<component :is="icon" class="icon"/>'
}
const App = {
components: {
TimeLineItem
}
}
const app = createApp(App)
app.mount('#app')
.icon {
width: 36px;
height: 36px;
}
<div id="app">
<time-line-item icon="CalendarDaysIcon"></time-line-item>
</div>
<script src="https://unpkg.com/vue#3/dist/vue.global.prod.js"></script>
Using <component :is="icon" /> is only using a string containing CalendarDaysIcon
Instead, in the main component, pass the actual component reference like this:
<template>
<TimelineItem :icon="CalendarDaysIcon" />
</template>
<script setup>
import {
CalendarDaysIcon,
} from '#heroicons/vue/20/solid'
const props = defineProps(['icon'])
</script>
Then, in the TimelineItem component, there is no need to reference any icons:
<template>
<component :is="icon" /> <!-- now works -->
</template>
<script setup>
const props = defineProps(['icon'])
</script>
Thanks to #Robert Boes on the Inertia Discord server for the guidance.
use Vue3-carousel
there is an object of 15 elements. how to make a carousel of 5 elements correctly?
I use this template
<template>
<Carousel :autoplay="2000" :wrap-around="true">
<Slide v-for="slide in 10" :key="slide">
<<div class="carousel__item">{{ slide }} here I want to output an object with 5 elements</div>
</Slide>
</Carousel>
</template>
<script>
import { define Component } from 'vue'
import { Carousel, Slide } from 'vue3-carousel';
import 'vue3-carousel/dist/carousel.css';
export default define Component({
name: 'Autoplay',
components: {
Carousel,
Slide,
},
});
</script>
I've started working with Vue.js version 3 and making a simple signup form. I need to implement a password strength meter for my password field but seems there isn't any compatible such component with Vue.js 3 version.
I've found few good components for password strength meter to use with Vue.js but they all seems to have compatibility with Vue.js 2.
I've tried
https://awesomeopensource.com/project/skegel13/vue-password
its working good in DEMO but not compatible with my Vue.js 3.
I'm stuck here. Any help/suggestions ?
Are you looking for a visual component or something that actually computes password strength?
zxcvbn is fairly well-known as a strength calculator - it outputs a score from 0-4 for how strong a password is. You could then roll a simple Vue component that outputs a different value depending on that score.
Below example uses Tailwind CSS classes for styling the visual meter. I wrote this in the browser and haven't tested the Vue but it's fairly simple and you should be able to get the idea.
<!-- PasswordStrengthMeter.vue -->
<template>
<div>
<div class="w-full h-4 flex">
<div :class="style"></div>
<div class="flex-1"></div>
</div>
<div>{{ strength }}</div>
</div>
</template>
<script>
props: {
score: {
required: true,
default: 0,
}
},
computed: {
strength() {
return [
'Very Weak', // 0
'Weak', // 1
'Moderate', // 2
'Strong', // 3
'Very Strong' // 4
][this.score];
},
style() {
return [
'w-1 bg-red-500', // 0
'w-1/4 bg-yellow-500', // 1
'w-1/2 bg-yellow-300', // 2
'w-3/4 bg-green-500', // 3
'w-full bg-blue-500' // 4
][this.score];
},
},
</script>
Here's what it might look like.
This one works nicely with Vue3.
https://github.com/miladd3/vue-simple-password-meter/tree/next
Sample code from the repository:
<template>
<div id="app">
<label>Password</label>
<input type="password" v-model="password" />
<password-meter :password="password" />
</div>
</template>
<script>
import { defineComponent, ref } from 'vue';
import PasswordMeter from 'vue-simple-password-meter';
export default defineComponent({
components: {
PasswordMeter,
},
setup() {
const password = ref('');
return {
password,
};
},
});
</script>
I'm passing a string containing a sequence of elements as a prop, which I try to render using :v-html="prop":
<template>
<svg
version="1.1"
baseProfile="full"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 26 26"
:class="sizeClass"
:height="size"
:width="size"
>
<g :v-html="sequence" />
</svg>
</template>
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
name: "Avatar",
props: {
sizeClass: String,
size: String,
sequence: String,
},
});
</script>
However inspecting the result on dev tools, the html is not rendered, but appears only in the v-html attribute :
What am I missing ?
directives are bound by default they don't need binding sign : or v-bind::
<g v-html="sequence" />
I have a component called legend that should embed SVG elements inside a template that places the actual SVG tags:
<svg xmlns="http://www.w3.org/2000/svg" class="pie-chart" :width="outerwidth" :height="outerheight">
<legend ref="legend" :series="series" :position="positionLegend" :options="{}" ></legend>
</svg>
But the legend component does not get rendered the output is:
<div id="graphbox">
<svg xmlns="http://www.w3.org/2000/svg" width="1691" height="14" class="pie-chart">
<legend series="[object Object],[object Object],[object Object]" position="[object Object]" options="[object Object]"></legend>
</svg>
</div>
Does vue not parse within SVG tags?
Components inside <svg> should work fine but you'll need to rename legend to something else. legend is a standard HTML element name so Vue will get confused.
Also make sure that you've registered the component correctly, either locally or globally. Usually Vue will warn you if you've forgotten to register a component but in this case it won't because legend is a standard HTML element.
Here's a complete example, similar to the one in the question:
const myLegend = {
template: `<circle r="10" cx="20" cy="20" :fill="color" />`,
props: ['color']
}
new Vue({
el: '#graphbox',
components: {
myLegend
},
data () {
return {
outerheight: 50,
outerwidth: 50,
color: '#ff0000'
}
}
})
<script src="https://unpkg.com/vue#2.6.11/dist/vue.js"></script>
<div id="graphbox">
<svg :width="outerwidth" :height="outerheight">
<my-legend :color="color"></my-legend>
</svg>
</div>