i use Nuxt3
I have an /components/icons
folder
Inside the /components/icons
there are many icons :
/components/icons/apps.vue
/components/icons/arrow-up.vue
/components/icons/bookmark.vue
/components/icons/home.vue
/components/icons/edit.vue
The icons are in svg format and I want to write, for example, this code for all these icons without repeating them in each file.
Example of any icon file :
<script setup lang="ts">
const props = defineProps({
size: {
type: Number,
required: false,
},
});
const svg = ref();
const size = ref(props.size);
onMounted(() => {
if (!size.value) {
size.value = parseFloat(window.getComputedStyle(svg.value).fontSize);
}
});
</script>
<template>
<svg
ref="svg"
:width="size"
:height="size"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M3.35288 9.7093C4.00437 6.92879 6.17301 4.75775 8.95043 4.10553C10.9563 3.6345 13.0437 3.6345 15.0496 4.10553C17.827 4.75775 19.9956 6.92879 20.6471 9.70931C21.1176 11.7174 21.1176 13.8072 20.6471 15.8152C19.9956 18.5957 17.827 20.7668 15.0496 21.419C13.0437 21.89 10.9563 21.89 8.95044 21.419C6.17301 20.7668 4.00437 18.5957 3.35288 15.8152C2.88237 13.8072 2.88237 11.7174 3.35288 9.7093Z"
fill="#363853"
fill-opacity="0.15"
stroke="#363853"
stroke-width="1.5" />
<path
d="M14.5 12.7622H9.5M12 15.265L12 10.2595"
stroke="#363853"
stroke-width="1.5"
stroke-linecap="round" />
</svg>
</template>
I don't want to repeat this code in every icon, Also when calling icons it is by default like this and I do not want to change the way it is used :
<IconsAdd></IconsAdd>
<IconsApps></IconsApps>
<IconsBookmark></IconsBookmark>
<IconsArrowsUp></IconsArrowsUp>
This feature is available in nuxt :
Component Names If you have a component in nested directories such as:
-| components/ ---| base/ -----| foo/ -------| Button.vue
... then the component's name will be based on its own path directory and filename, with duplicate segments being removed. Therefore, the component's name will be:
<BaseFooButton />
This always depends on the case.
extends
is optimal to extend base components with some script
logic being augmented and template
being fully replaced, as it effectively replaces render
option in this case.
Sometimes it's more effective switch to options API. This includes lifecycle hooks like mounted
, they can be stacked up, according to how extends
works.
Otherwise extends
can be used with composition API. It extended props
and other options, but doesn't affect setup
, it needs to be handled manually. Props can be explicitly specified, this can useful in some cases, e.g. for better support of prop autocompletion in IDE.
setup
can be composed but the variables that are local to base setup
cannot be replaced due to how variable scopes work in JavaScript, this needs to be taken into account. E.g.:
BaseIcon.vue
<template></template>
<script>
export default {
props: ...
setup(props) {
...
}
</script>
IconSome.vue
<template>
<svg>...
</template>
<script>
import BaseIcon from './BaseIcon.vue'
export default {
extends: BaseIcon,
props: {
...BaseIcon.props,
foo: ...
},
setup(props, ctx) {
const instance = Base.setup(props, ctx);
instance.bar = ref(2); // potentially bad
let baz = ref(3); // ok if Base.setup doesn't contain baz
return { ...instance , baz };
}
script setup
should be avoided with extends
because it's DSL and not spec-compliant JavaScript, it works in undocumented and unpredictable manner, e.g. it's known to compile to a component without render
option in production, this prevents components with templates to be extended in an expected way.