Vue.js: Refs و DOM
آخر تحديث: 2026-10-20
تتيح لك مراجع القوالب الوصول مباشرةً إلى عناصر DOM أو مثيلات المكونات الفرعية — على سبيل المثال، استدعاء input.focus() أو الوصول إلى أساليب المكونات. وقد أدخلت Vue 3.5 واجهة برمجة تطبيقات التركيب useTemplateRef الأكثر قوة، والتي تعمل بالاقتران مع استدلال الأنواع في TypeScript.
تُعد «Template Refs» «الملاذ الأخير» — توصي Vue باستخدام «refs» و«reactive» و«props» و«emit» لحل معظم المشكلات؛ ولا ينبغي استخدام «Template Refs» إلا عندما تحتاج إلى التعامل مباشرةً مع DOM أو مثيل مكون.
1. ما ستتعلمه
ref="el"أساسيات الإشارات إلى القوالبuseTemplateRef(موصى به لـ Vue 3.5+)- الوصول إلى عناصر DOM (التركيز، والتمرير إلى منطقة العرض، وما إلى ذلك)
- الوصول إلى مثيل مكون فرعي (باستخدام الطريقة
defineExpose) $refsصيغة بديلة باستخدام واجهة برمجة التطبيقات (API) للتركيب- مصفوفات المرجع في
v-for - 5 حالات استخدام رئيسية و4 أنماط غير مرغوب فيها
2. معضلة «التركيز التلقائي» في نموذج تسجيل الدخول
(1) المشكلة: كيف يمكن أن يحصل حقل الإدخال على التركيز تلقائيًّا عند فتح النافذة المنبثقة؟
قامت أليس بإنشاء نافذة منبثقة لتسجيل الدخول من المفترض أن تركز تلقائيًا على حقل إدخال اسم المستخدم:
// ❌ The "Broken" Version:Directly querySelector
onMounted(() => {
const input = document.querySelector('.username-input')
input.focus() // ❌ Does not meet the requirements Vue Philosophy
})
فلسفة Vue: تجنب التلاعب المباشر بـ DOM. استخدم «Template Refs» بدلاً من ذلك.
مدير المنتج تشارلي:
"أليس، عندما يُفتح النافذة المنبثقة، يجب أن يتم تحديد حقل اسم المستخدم تلقائيًّا حتى يتمكن المستخدمون من البدء في الكتابة على الفور."
(2) عرض حل «مراجع القوالب»
(3) الإيرادات
بعد استخدام «Template Refs»:
- سهولة قراءة الكود: اذكر بوضوح «أريد الإشارة إلى هذا العنصر»
- يتوافق مع فلسفة Vue: لا يتعامل مباشرةً مع DOM
- أمان الأنواع: يستنتج TypeScript أنواع العناصر
- دورة الحياة الصحيحة: الوصول في
onMountedأوnextTick
3. الاستخدام الأساسي لـ ref
(1) مرجع السلسلة (بأسلوب Vue 2، تم إهماله)
// ❌ Not recommended:String ref
export default {
mounted() {
this.$refs.input.focus()
}
}
(2) المتغير ref (موصى به في Vue 3)
(3) 5 عمليات أساسية
// 1. Visit DOM Element
inputRef.value // <input> Element
// 2. Call DOM API
inputRef.value.focus()
inputRef.value.blur()
inputRef.value.select()
inputRef.value.scrollIntoView()
// 3. Read/Edit DOM Properties
inputRef.value.value // input value
inputRef.value.disabled // disabled Properties
inputRef.value.style.color = 'red' // Edit Style
// 4. Monitoring DOM Events (Not recommended, use @event)
inputRef.value.addEventListener('focus', handler)
// 5. Accessing a Child Component Instance(For more details, see 17.4)
childRef.value.someMethod()
▶ مثال: التركيز التلقائي على نموذج تسجيل الدخول
▶ جرّب الكودالإخراج:
عند تحميل الصفحة يحصل حقل Username على التركيز تلقائيًا والمؤشر بداخله
بعد تعبئة الحقلين والضغط على Login تُطبع في وحدة التحكم: Login: alice 123456
▶ مثال: التمرير التلقائي إلى أسفل الصفحة
▶ جرّب الكودالإخراج:
القائمة فارغة وموضع التمرير في أعلى الحاوية
بعد إرسال رسالة: تُضاف الفقرة إلى القائمة ثم ينتقل scrollTop إلى scrollHeight فيظهر آخر عنصر
4. useTemplateRef (موصى به لـ Vue 3.5 وما فوق)
(1) لماذا نحتاج إلى useTemplateRef؟
يتطلب المتغير ref في <script setup> اسمين (القالب ref والمتغير)، مما قد يؤدي بسهولة إلى حدوث تناقضات. أما useTemplateRef فيعالج هذه المشكلة باستخدام اسم واحد، كما أن استدلال الأنواع في TypeScript أكثر قوة.
(2) 5 مزايا رئيسية
| الميزة | الوصف |
|---|---|
| استدلال النوع | يتعرف TypeScript عليه تلقائيًا على أنه عنصر HTMLInputElement |
| إعادة التسمية الآمنة | قم بتغيير الاسم في مكان واحد؛ وسيقوم IDE بمزامنته |
| تجنب عدم تطابق الأسماء | تحدث الأخطاء عندما لا تتطابق مراجع القوالب وأسماء المتغيرات |
| إعداد مبسط | لا يلزم وجود const inputRef = ref(null) |
| أدوات التطوير المحسّنة | دعم Vue DevTools 5.x |
(3) مقارنة شاملة
<!-- Old notation:Variable ref -->
<template>
<input ref="usernameInput">
</template>
<script setup>
import { ref, onMounted } from 'vue'
const inputRef = ref(null) // The name may not match the template.
onMounted(() => inputRef.value.focus())
</script>
<!-- New Writing Style:useTemplateRef(Vue 3.5+ Recommendations)-->
<template>
<input ref="usernameInput">
</template>
<script setup>
import { useTemplateRef, onMounted } from 'vue'
const inputRef = useTemplateRef('usernameInput') // One Name Does It All
onMounted(() => inputRef.value.focus())
</script>
▶ مثال: استنتاج النوع لـ useTemplateRef
<template>
<input ref="usernameInput" type="text">
<MyChart ref="chartComponent" :data="chartData" />
</template>
<script setup lang="ts">
import { ref, useTemplateRef, onMounted } from 'vue'
import MyChart from './MyChart.vue'
// ✅ TypeScript Inference:HTMLInputElement | null
const usernameInput = useTemplateRef<HTMLInputElement>('usernameInput')
// ✅ TypeScript Inference:InstanceType<typeof MyChart> | null
const chartComponent = useTemplateRef<InstanceType<typeof MyChart>>('chartComponent')
onMounted(() => {
// usernameInput.value Automatic is HTMLInputElement
usernameInput.value?.focus()
// chartComponent.value "Auto" is a component instance
chartComponent.value?.refresh()
})
</script>
الإخراج:
بعد mount يحصل حقل الإدخال على التركيز ويُستدعى refresh() على مكوّن المخطط
النوع: usernameInput هو HTMLInputElement أو null، وchartComponent هو مثيل MyChart أو null
لا حاجة إلى تحويل نوع يدوي كما في ref(null)
5. الوصول إلى مثيل مكون تابع
(1) defineExpose: طريقة Expose
(2) الوصول إلى المكون الأصلي
<template>
<MyInput ref="myInputRef" v-model="searchQuery" />
<button @click="focusInput">Focus Input</button>
</template>
<script setup>
import { ref } from 'vue'
import MyInput from './MyInput.vue'
const searchQuery = ref('')
const myInputRef = ref(null)
function focusInput() {
myInputRef.value.focus() // Calling Methods Exposed by Child Components
myInputRef.value.select() // You can also use chained calls
}
</script>
(3) 5 حالات استخدام رئيسية
| السيناريو | تم الكشف عنه بواسطة المكون الفرعي | تم استدعاؤه بواسطة المكون الرئيسي |
|---|---|---|
| تسليط الضوء على النموذج | focus() |
inputRef.focus() |
| مسح النموذج | clear() |
formRef.clear() |
| إعادة تحميل البيانات | reload() |
tableRef.reload() |
| فتح نافذة منبثقة | open() |
modalRef.open() |
| إرسال النموذج | submit() |
formRef.submit() |
6. الarray ref في v-for
(1) الاستخدام الأساسي
(2) المرجع الديناميكي (v-for مع عدد ديناميكي)
(3) 5 نقاط أساسية يجب أخذها في الاعتبار
| نقاط يجب ملاحظتها | الوصف |
|---|---|
| ترتيب الarray | يتطابق مع ترتيب البيانات في v-for |
| تفاعلي | تتطلب التغييرات التي تطرأ على الarray «ref» تعيين «watch» |
| العرض الشرطي | قد لا يتم تحديث المراجع بعد v-if |
| عدد المتغيرات الديناميكية | استخدام مرجع كائن أو مرجع دالة |
| الأداء | قد يؤدي وجود عدد كبير من المراجع (100+) إلى إبطاء عملية العرض |
7. تمرين شامل: استدعاء دالة المكوّن التابع عبر defineExpose
▶ مثال: استدعاء المكون الأصلي لطريقة المكون التابع
<!-- Child component:FormValidator.vue -->
<template>
<form>
<input v-model="email" placeholder="Email">
<input v-model="password" type="password" placeholder="Password">
</form>
</template>
<script setup>
import { ref } from 'vue'
const email = ref('')
const password = ref('')
const emailRef = ref(null)
const passwordRef = ref(null)
defineExpose({
validate: () => {
if (!email.value) {
emailRef.value.focus()
return false
}
if (!password.value || password.value.length < 6) {
passwordRef.value.focus()
return false
}
return true
},
reset: () => {
email.value = ''
password.value = ''
}
})
</script>
<!-- Parent Component:LoginPage.vue -->
<template>
<FormValidator ref="formRef" />
<button @click="submit">Submit</button>
</template>
<script setup>
import { ref } from 'vue'
import FormValidator from './FormValidator.vue'
const formRef = ref(null)
function submit() {
if (formRef.value.validate()) {
console.log('Valid!')
} else {
console.log('Invalid!')
}
}
</script>
الإخراج:
الضغط على Submit والحقول فارغة → ينتقل التركيز إلى حقل Email ويُطبع Invalid!
بعد إدخال بريد صحيح وكلمة مرور من 6 أحرف أو أكثر → يُطبع Valid!
(1) 📊 5. مرجع سريع لـ 5 أخطاء شائعة
| الخطأ | الأعراض | الحل |
|---|---|---|
| خطأ إملائي في اسم القالب | قيمة المرجع فارغة | تأكد من تطابق أسماء المراجع |
الوصول في المستوى الأعلى setup |
ref.value قيمة فارغة |
استخدم onMounted |
| الوصول داخل نافذة منبثقة | لا يعمل | استخدم nextTick أو طرق DOM مشابهة |
| الوصول إلى الarray المرجعية في v-for | عدم توافق الفهرس | استخدم :key للحفاظ على الترتيب |
| مرجع مشترك بين المكونات | غير محدد | المكونات الفرعية تستخدم defineExpose |
(2) 📊 6. مقارنة بين أنواع المراجع الخمسة الرئيسية
| النوع | مثال | ينطبق على |
|---|---|---|
| عنصر DOM | ref="inputRef" → HTMLInputElement |
الوصول إلى input/div |
| مثيل المكون | ref="childRef" → مثيل المكون |
أساليب مكون النغمة |
| array v-for | ref="itemRefs" → array |
الوصول إلى عناصر القائمة |
| مرجع وظيفي | :ref="el => ..." → عنصر واحد |
العدد الديناميكي |
| مرجع سلسلة | ref="name" → this.$refs |
نمط العرض 2 (غير موصى به) |
❓ أسئلة شائعة
useTemplateRef مطلوب في Vue 3.5+؟ref. يُفضل استخدام استدلال الأنواع في TypeScript.useRef (React)؟useRef في React مرجعًا قابلًا للتعديل، بينما يُرجع «template ref» في Vue كائن مرجع. يحتوي useTemplateRef في Vue 3.5+ على واجهة برمجة تطبيقات (API) أقرب إلى useRef في React.v-for؟v-for. كما يتم تحديثها عند تبديل status v-if. يمكنك استخدام watch على array المرجع للاستجابة للتغييرات.useTemplateRef<HTMLInputElement>('usernameInput'). أو ref<HTMLInputElement | null>(null).📖 ملخص
- تُستخدم «مراجع القوالب» للوصول مباشرةً إلى عناصر DOM أو مثيلات المكونات الفرعية
- 3 طرق لكتابتها: مرجع متغير (Vue 3) / useTemplateRef (Vue 3.5+؛ موصى به) / مرجع سلسلة (نمط Vue 2؛ غير موصى به)
- 5 عمليات أساسية: التركيز / التمرير / التحديد / تغيير الخصائص / ضبط المكونات
defineExposeيسمح للمكون الفرعي بإتاحة طرق للمكون الأصلي- في
v-for، يتم تجميعrefتلقائيًا في array - 5 سيناريوهات رئيسية: التركيز التلقائي / التمرير إلى أسفل الصفحة / طريقة تحديد الدرجة اللونية / التكامل مع تطبيقات خارجية / قياس حجم العنصر
- 4 أنماط خاطئة: الأخطاء الإملائية / الوصول إلى المستوى الأعلى / النوافذ المنبثقة التي لا تستخدم
nextTick/ التداخل بين المكوناتref
📝 تمارين
-
أسئلة أساسية (مستوى الصعوبة: ⭐)
تنفيذ نموذج بسيط للتركيز التلقائي:
- حقل إدخال واحد + زر واحد
- يتم تحديد حقل الإدخال تلقائيًا بعد تحميل الصفحة
- عند النقر على الزر، يتغير نص الزر إلى «تم الإرسال» ويتم تعطيل الزر
-
مسائل متقدمة (مستوى الصعوبة: ⭐⭐)
تنفيذ مربع دردشة يتحرك تلقائيًا إلى أسفل الصفحة:
- قائمة الرسائل (عنصر div الحاوي)
- حقل الإدخال + زر «إرسال»
- بعد إرسال الرسالة، تُضاف إلى القائمة ويتم تمريرها تلقائيًا إلى أسفل القائمة
- استخدم
v-forلعرض الرسائل، وarrayrefلإدارة DOM
-
مسألة التحدي (مستوى الصعوبة: ⭐⭐⭐)
تنفيذ نظام متكامل لـ «المكونات الأبوية والفرعية + Template Refs»:
- المكون الفرعي FormValidator: يوفر طريقتي validate() و reset()
- المكون الأصلي LoginPage: يستدعي الأسلوب
validateلإجراء عملية التحقق من الصحة؛ ويعرض رسالة خطأ في status فشل عملية التحقق من الصحة - 5 حقول إدخال (اسم المستخدم/البريد الإلكتروني/كلمة المرور/رقم الهاتف/اختبار كابتشا)
- useTemplateRef (Vue 3.5+) + الكتابة القوية في TypeScript
- ضبط التركيز تلقائيًا على حقل الإدخال الأول عند فتح النافذة المنبثقة
- عند حدوث خطأ، ركز على حقل الخطأ الأول