Advanced Vue 3 Component Encapsulation: v-model, Slot Passing, and Ref Access

This article demonstrates how to create a reusable Vue 3 component with Vite and Element‑Plus, covering two‑way data binding via v‑model, slot forwarding using the h function, and exposing child component refs through a Proxy, complete with code examples and explanations.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Advanced Vue 3 Component Encapsulation: v-model, Slot Passing, and Ref Access

The tutorial shows how to set up a Vue 3 project with Vite and Element‑Plus, then create a reusable component that supports two‑way data binding, slot transmission, and child ref access.

Two‑way data binding is illustrated using the standard v-model="xxxx" syntax and the newer defineModel() helper, which simplifies model handling in custom components.

Passing slots to child components is achieved by creating a WrapInput.vue component that iterates over $slots and renders them, and by using the component element with is="h(ElInput, $attrs, $slots)" to forward slots via the h function. Example usage in app.vue demonstrates #prepend and #append slots.

<script setup lang="ts">
import { ref } from "vue";
import WrapInput from "./components/WrapInput.vue";
const inputText = ref('');
</script>

<template>
  <WrapInput v-model="inputText">
    <template #prepend>Http://</template>
    <template #append>.com</template>
  </WrapInput>
</template>

Accessing child component refs is first shown with a manual getRef method, then refined using a Proxy to expose all properties of the underlying input element. The updated WrapInput.vue defines a ref and uses defineExpose(new Proxy(...)) to forward method calls.

<script setup lang="ts">
import { h, ref } from "vue";
import { ElInput } from "element-plus";
const model = defineModel();
const inputRef = ref();
defineExpose(new Proxy({}, {
  get(_target, prop) { return inputRef.value?.[prop]; },
  has(_target, prop) { return prop in inputRef.value; }
}));
</script>

<template>
  <component is="h(ElInput, $attrs, $slots)" v-model="model" ref="inputRef"></component>
</template>

The parent App.vue uses the component, updates slot content dynamically, and calls the exposed focus method via a ref, demonstrating full interaction between parent and child.

<script setup lang="ts">
import { ref } from "vue";
import WrapInput from "./components/WrapInput.vue";
const inputText = ref('');
const prependSlotText = ref('Http://');
const appendSlotText = ref('.com');
function updateSlotInfo() {
  prependSlotText.value = 'https://';
  appendSlotText.value = `${new Date().getTime()}`;
}
const wrapInputRef = ref();
function setWrapInputFocus() { wrapInputRef.value?.focus(); }
</script>

<template>
  <WrapInput v-model="inputText" ref="wrapInputRef">
    <template #prepend>{{ prependSlotText }}</template>
    <template #append>{{ appendSlotText }}</template>
  </WrapInput>
  <div style="margin: 20px 0;">{{inputText}}</div>
  <el-button type="primary" @click="updateSlotInfo">Update Slots</el-button>
  <el-button type="primary" @click="setWrapInputFocus">Set Input Focus</el-button>
</template>

In summary, the article demonstrates practical techniques for encapsulating Vue 3 components, handling v-model, forwarding slots via the h function, and exposing child refs using a Proxy, providing a solid foundation for building reusable UI components.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

ComponentVue__slots__V-Model
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.