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 أو مثيل مكون.

التوجيهات ذات صلة:v-for v-if

1. ما ستتعلمه


2. معضلة «التركيز التلقائي» في نموذج تسجيل الدخول

(1) المشكلة: كيف يمكن أن يحصل حقل الإدخال على التركيز تلقائيًّا عند فتح النافذة المنبثقة؟

قامت أليس بإنشاء نافذة منبثقة لتسجيل الدخول من المفترض أن تركز تلقائيًا على حقل إدخال اسم المستخدم:

JS
// ❌ 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»:


3. الاستخدام الأساسي لـ ref

(1) مرجع السلسلة (بأسلوب Vue 2، تم إهماله)

JS
// ❌ Not recommended:String ref
export default {
  mounted() {
    this.$refs.input.focus()
  }
}

(2) المتغير ref (موصى به في Vue 3)

(3) 5 عمليات أساسية

JS
// 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()

▶ مثال: التركيز التلقائي على نموذج تسجيل الدخول

▶ جرّب الكود

الإخراج:

TEXT
عند تحميل الصفحة يحصل حقل Username على التركيز تلقائيًا والمؤشر بداخله
بعد تعبئة الحقلين والضغط على Login تُطبع في وحدة التحكم: Login: alice 123456

▶ مثال: التمرير التلقائي إلى أسفل الصفحة

▶ جرّب الكود

الإخراج:

TEXT
القائمة فارغة وموضع التمرير في أعلى الحاوية
بعد إرسال رسالة: تُضاف الفقرة إلى القائمة ثم ينتقل 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) مقارنة شاملة

VUE
<!-- 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

VUE
<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>
▶ جرّب الكود

الإخراج:

TEXT
بعد mount يحصل حقل الإدخال على التركيز ويُستدعى refresh() على مكوّن المخطط
النوع: usernameInput هو HTMLInputElement أو null، وchartComponent هو مثيل MyChart أو null
لا حاجة إلى تحويل نوع يدوي كما في ref(null)

5. الوصول إلى مثيل مكون تابع

(1) defineExpose: طريقة Expose

(2) الوصول إلى المكون الأصلي

VUE
<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

▶ مثال: استدعاء المكون الأصلي لطريقة المكون التابع

VUE
<!-- 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>
▶ جرّب الكود

الإخراج:

TEXT
الضغط على 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 (غير موصى به)

التوجيهات ذات صلة:v-for v-if

❓ أسئلة شائعة

س متى ينبغي استخدام «Template Refs»؟
ج في أربع حالات: (1) التعامل مع DOM (التركيز/التمرير/اللوحة القماشية)؛ (2) استدعاء أساليب المكونات؛ (3) دمج مكتبات الجهات الخارجية (ECharts/Mapbox)؛ (4) قياس أبعاد العناصر. أما في الحالات الأخرى، فاستخدم «refs» أو «reactive» أو «props».
س هل useTemplateRef مطلوب في Vue 3.5+؟
ج نعم. فهو مدعوم فقط في Vue 3.5+. في Vue 3.4 والإصدارات الأقدم، استخدم المتغير ref. يُفضل استخدام استدلال الأنواع في TypeScript.
س ما الفرق بين «Template Refs» وuseRef (React)؟
ج تُرجع useRef في React مرجعًا قابلًا للتعديل، بينما يُرجع «template ref» في Vue كائن مرجع. يحتوي useTemplateRef في Vue 3.5+ على واجهة برمجة تطبيقات (API) أقرب إلى useRef في React.
س ما هي الطرق التي يجب أن يُتيحها المكون الفرعي؟
ج لا تُتيح سوى الطرق التي يحتاجها المكون الأصلي فعليًّا (مثل focus و clear و validate). لا تُتيح الطرق الداخلية الأخرى (مبدأ التغليف).
س متى يتم تحديث array المرجع في v-for؟
ج يتم تحديثها في كل مرة يتم فيها إعادة عرض v-for. كما يتم تحديثها عند تبديل status v-if. يمكنك استخدام watch على array المرجع للاستجابة للتغييرات.
س هل تتعارض مرجعيات القوالب مع وظائف provide/inject؟
ج لا، لا تتعارض. تُستخدم مرجعيات القوالب لـ«الوصول من العنصر الأصلي إلى العنصر الفرعي»، بينما تُستخدم وظائف provide/inject لـ«مشاركة البيانات عبر المستويات». ويمكن استخدامهما معًا.
س كيف يمكنني إضافة نوع إلى مرجع في TypeScript؟
ج استخدم useTemplateRef<HTMLInputElement>('usernameInput'). أو ref<HTMLInputElement | null>(null).

📖 ملخص


📝 تمارين

  1. أسئلة أساسية (مستوى الصعوبة: ⭐)

    تنفيذ نموذج بسيط للتركيز التلقائي:

    • حقل إدخال واحد + زر واحد
    • يتم تحديد حقل الإدخال تلقائيًا بعد تحميل الصفحة
    • عند النقر على الزر، يتغير نص الزر إلى «تم الإرسال» ويتم تعطيل الزر
  2. مسائل متقدمة (مستوى الصعوبة: ⭐⭐)

    تنفيذ مربع دردشة يتحرك تلقائيًا إلى أسفل الصفحة:

    • قائمة الرسائل (عنصر div الحاوي)
    • حقل الإدخال + زر «إرسال»
    • بعد إرسال الرسالة، تُضاف إلى القائمة ويتم تمريرها تلقائيًا إلى أسفل القائمة
    • استخدم v-for لعرض الرسائل، وarray ref لإدارة DOM
  3. مسألة التحدي (مستوى الصعوبة: ⭐⭐⭐)

    تنفيذ نظام متكامل لـ «المكونات الأبوية والفرعية + Template Refs»:

    1. المكون الفرعي FormValidator: يوفر طريقتي validate() و reset()
    2. المكون الأصلي LoginPage: يستدعي الأسلوب validate لإجراء عملية التحقق من الصحة؛ ويعرض رسالة خطأ في status فشل عملية التحقق من الصحة
    3. 5 حقول إدخال (اسم المستخدم/البريد الإلكتروني/كلمة المرور/رقم الهاتف/اختبار كابتشا)
    4. useTemplateRef (Vue 3.5+) + الكتابة القوية في TypeScript
    5. ضبط التركيز تلقائيًا على حقل الإدخال الأول عند فتح النافذة المنبثقة
    6. عند حدوث خطأ، ركز على حقل الخطأ الأول
Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%