Open IgorHalfeld opened 5 years ago
Acho que é interessante a gente enxergar que antes de ser um componente Vue, o SFC é um módulo JavaScript e tem acesso a todas as ferramentas de granularização/modularização e composição dele. Isso inclui exportar outros valores, funções e partes do componente que podem compor os componentes que o utilizam.
E tenho uma sugestão para não extrapolar o uso dessa técnica. Usem apenas em Composable Components, que são componentes interdependentes e com um mesmo escopo e dependência de UI.
Seguem snippets do uso dessa técnica nos meus componentes FieldContainer
e FieldText
.
FieldContainer
<template>
<fieldset class="field-container">
<label v-if="label" class="label" :for="id">{{ label }}</label>
<slot />
</fieldset>
</template>
<script>
import generateID from '@/helpers/generateID';
export const FieldContainerProps = {
id: {
type: String,
default: generateID,
},
label: String,
};
export default {
name: 'FieldContainer',
props: FieldContainerProps,
};
</script>
FieldText
<template>
<field-container v-bind="{ id, label }" class="field-text">
<input
v-bind="{ id, type, value }"
class="field"
@input="$emit('input', $event.target.value)"
/>
</field-container>
</template>
<script>
import FieldContainer, {
FieldContainerProps,
} from '@/components/Field/FieldContainer';
export const FieldTextTypes = ['text', 'number', 'password'];
export default {
name: 'FieldText',
components: { FieldContainer },
props: {
...FieldWrapperProps,
type: {
type: String,
default: 'text',
validator: FieldTextTypes.includes.bind(FieldTextTypes),
},
value: {
type: [Number, String],
required: true,
},
},
};
</script>
Dei uma modificada para usar mixins e improvisei um componente funcional. Ainda é possível automatizar a geração de outros componentes baseado em tipos de input suportados. Dada a simplicidade dos outros componentes, até seria possível usar 100% de render function, ampliando as possibilidades de customização.
<template>
<fieldset class="field-container" :class="'field-container-' + id">
<label v-if="label" class="label" :for="id">{{ label }}</label>
<slot />
</fieldset>
</template>
<script>
import generateID from '@/helpers/generateID';
export const FieldContainerProps = {
id: {
type: String,
default: generateID,
},
label: String,
};
export default {
name: 'FieldContainer',
props: FieldContainerProps,
};
</script>
import FieldContainer, {
FieldContainerProps,
} from './FieldContainer';
const FieldMixin = {
components: {
FieldContainer
},
props: {
...FieldContainerProps
}
}
export default FieldMixin
<template>
<field-container v-bind="{ id, label }" class="field-text">
<input
v-bind="{ id, type, value }"
class="field-input"
:class="'field-input-' + type"
v-on="$listeners"
/>
</field-container>
</template>
<script>
import FieldMixin from './FieldMixin';
export const FieldTextTypes = ['text', 'number', 'password'];
export default {
name: 'FieldText',
mixins: [FieldMixin],
props: {
type: {
type: String,
default: 'text',
validator: FieldTextTypes.includes.bind(FieldTextTypes),
},
value: {
type: [Number, String],
required: true,
},
},
}
</script>
import { FieldContainerProps } from './FieldContainer'
import FieldText from './FieldText'
export default {
functional: true,
props: {
...FieldContainerProps,
value: {
type: [Number, String],
required: true,
},
},
render (h, { data, props }) {
return h(FieldText, {
...data,
props: {
...props,
type: 'password'
}
})
}
}
Toppen! Eu renomearia o h
para createElement
só pra melhorar a legibilidade :D
O @VitorLuizC abriu uma thread falando sobre compor seus componentes usando trechos de outros componentes, já que um componente no Vue é basicamente um objeto, segue o exemplo
Greetings.vue
Header.vue
E então, nessa mesma thread o @vinicius73 comentou do uso de
mixins
eentends
que também é uma alternativa quando falamos de composição.