Maison >interface Web >Voir.js >Comment l'API de composition Vue3 encapsule élégamment les composants tiers
Pour les composants tiers, comment étendre élégamment les fonctions tout en conservant les fonctions d'origine des composants tiers (accessoires, événements, slots, méthodes) ?
Prenons l'exemple de l'el-input d'Element Plus :
Il est très probable que vous ayez déjà joué comme ça, en encapsulant un composant MyInput et en ajoutant les accessoires, les événements, les emplacements et les méthodes à utiliser selon les vôtres besoins. Écrivez-le à nouveau :
// MyInput.vue <template> <div class="my-input"> <el-input v-model="inputVal" :clearable="clearable" @clear="clear"> <template #prefix> <slot name="prefix"></slot> </template> <template #suffix> <slot name="suffix"></slot> </template> </el-input> </div> </template> <script setup> import { computed } from 'vue' const props = defineProps({ modelValue: { type: String, default: '' }, clearable: { type: Boolean, default: false } }) const emits = defineEmits(['update:modelValue', 'clear']) const inputVal = computed({ get: () => props.modelValue, set: (val) => { emits('update:modelValue', val) } }) const clear = () => { emits('clear') } </script>
Mais après un certain temps, les exigences changent et d'autres fonctions du composant el-input doivent être ajoutées au composant MyInput. Le composant el-input a un total de 20 multi-. propriétés, 5 événements et 4 emplacements, que devons-nous faire ? Devons-nous les transmettre un par un, ce qui est non seulement fastidieux, mais également peu lisible.
Dans Vue2, nous pouvons le gérer comme ceci, cliquez ici pour voir l'encapsulation des composants tiers de Vue
Cet article est pour vous aider à transférer des connaissances et à explorer comment utiliser Vue3 CompositionAPI pour encapsuler élégamment des composants tiers~
dans Vue2
$attrs : inclut les liaisons d'attributs (à l'exception de la classe et du style) qui ne sont pas reconnues (et obtenues) comme accessoires dans la portée parent. Lorsqu'un composant ne déclare aucun accessoire, toutes les liaisons de portée parent (sauf la classe et le style) seront incluses ici, et les composants internes peuvent être transmis via v-bind="$attrs"
$listeners : inclus v- sur l'écouteur d'événement dans la portée parent (sans modificateur .native). Il peut être transmis aux composants internes via v-on="$listeners"
et dans Vue3
$attrs : contient des liaisons d'attributs et des événements dans la portée parent qui ne sont pas des accessoires de composant ou des événements personnalisés (y compris la classe , style et événements personnalisés), et les composants internes peuvent être transmis via v-bind="$attrs".
L'objet $listeners a été supprimé dans Vue 3. Les écouteurs d'événements font désormais partie de $attrs.
Dans 5101c0cdbdc49998c642c71f6b6410a8, la fonction auxiliaire useAttrs peut obtenir $attrs.
//MyInput.vue <template> <div class="my-input"> <el-input v-bind="attrs"></el-input> </div> </template> <script setup> import { useAttrs } from 'vue' const attrs = useAttrs() </script>
Bien sûr, cela ne suffit pas. En écrivant simplement ainsi, les attributs que nous lions (y compris la classe et le style) fonctionneront également sur l'élément racine (l'exemple ci-dessus est le nœud Dom avec class="my-input"). Pour éviter ce comportement par défaut, nous devons définir EnsureAttrs sur false.
Jetons un coup d'œil à l'explication de l'héritageAttrs dans le document Vue3
Par défaut, les liaisons d'attributs dans la portée parent qui ne sont pas reconnues comme des accessoires «retomberont» et seront appliquées à l'enfant en tant qu'attributs HTML ordinaires sur l'élément racine de le composant. Lors de l'écriture d'un composant qui encapsule un élément cible ou un autre composant, cela peut ne pas toujours être conforme au comportement attendu. En définissantheritAttrs sur false, ces comportements par défaut seront supprimés. Ces attributs peuvent être rendus efficaces via la propriété d'instance $attrs et peuvent être explicitement liés à des éléments non root via v-bind.
Nous pouvons donc écrire le code suivant pour gérer les accessoires et les événements des composants tiers :
// MyInput.vue <template> <div class="my-input"> <el-input v-bind="attrs"></el-input> </div> </template> <script> export default { name: 'MyInput', inheritAttrs: false } </script> <script setup> import { useAttrs } from 'vue' const attrs = useAttrs() </script>
Dans Vue3
$slots : nous pouvons l'utiliser Obtenez le slot transmis par le composant parent
$scopedSlots a été supprimé dans Vue3, et tous les slots sont exposés en tant que fonctions via $slots
La fonction auxiliaire useSlots dans 5101c0cdbdc49998c642c71f6b6410a8
Sur la base des points ci-dessus, si nous n'ajoutons pas d'emplacements supplémentaires pour le packaging des composants tiers, et que les emplacements des composants tiers sont dans le même nœud dom, nous avons également une méthode de packaging délicate ? ?? ?, obtenez le nom du slot en parcourant $slots, et ajoutez dynamiquement le slot du sous-composant :
//MyInput.vue <template> <div class="my-input"> <el-input v-bind="attrs"> <template v-for="k in Object.keys(slots)" #[k] :key="k"> <slot :name="k"></slot> </template> </el-input> </div> </template> <script> export default { name: 'MyInput', inheritAttrs: false } </script> <script setup> import { useAttrs, useSlots } from 'vue' const attrs = useAttrs() const slots = useSlots() </script>
Si les conditions ci-dessus ne sont pas remplies, nous devons ajouter manuellement les slots du tiers requis composants dans le sous-composant ~
Pour les méthodes de composants tiers, nous les implémentons via la réf. Tout d'abord, ajoutez un attribut ref="elInputRef" au composant el-input dans le composant MyInput, puis exposez elInputRef au composant parent via DefineExpose.
Sous composant : MyInput.vue
// MyInput.vue <template> <div class="my-input"> <el-input v-bind="attrs" ref="elInputRef"> <template v-for="k in Object.keys(slots)" #[k] :key="k"> <slot :name="k"></slot> </template> </el-input> </div> </template> <script> export default { name: 'MyInput', inheritAttrs: false } </script> <script setup> import { useAttrs, useSlots } from 'vue' const attrs = useAttrs() const slots = useSlots() const elInputRef = ref(null) defineExpose({ elInputRef // <script setup>的组件里的属性默认是关闭的,需通过defineExpose暴露出去才能被调用 }) </script>
Page parent : Index.vue Le code d'appel est le suivant :
// Index.vue <template> <my-input v-model='input' ref="myInput"> <template #prefix>姓名</template> </my-input> </template> <script setup> import MyInput from './components/MyInput.vue' import { ref, onMounted } from 'vue' const input = ref('') const myInput = ref(null) // 组件实例 onMounted(()=> { myInput.value.elInputRef.focus() // 初始化时调用elInputRef实例的focus方法 }) </script>
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!