Vue.js: ميزات Vue 3.4 الجديدة

آخر تحديث: 2026-08-26

يقدم إصدار Vue 3.4+ (الذي صدر في ديسمبر 2023) عدة تحسينات ثورية: defineModel تبسيط الماكرو v-model، وتفكيك الخصائص التفاعلية useTemplateRef، وواجهة برمجة التطبيقات (API) للتركيب useId، وإنشاء معرّفات فريدة. تعمل هذه الميزات على تبسيط كود template بشكل كبير وتحسين تجربة التطوير.

سيساعدك هذا الدرس على إتقان خمس ميزات جديدة أساسية ستجعل كود Vue 3 الخاص بك أكثر إيجازًا وحداثة.

1. ما ستتعلمه



2. تحدي «التزامن بين العنصر الأصلي والعنصر التابع» في أحد مكونات نموذج v

(1) المشكلة: 5 أسطر من «props» + 5 أسطر من «emit» = 10 أسطر من النص النمطي

قامت أليس بإنشاء مكون إدخال مخصص باستخدام v-model:

JS
// ❌ The "Broken" Version:v-model Required 10 Sample Code
const props = defineProps({ modelValue: String })
const emit = defineEmits(['update:modelValue'])

const internalValue = ref(props.modelValue)
watch(() => props.modelValue, (val) => {
  internalValue.value = val
})
watch(internalValue, (val) => {
  emit('update:modelValue', val)
})

10 أسطر من الكود النمطي — يجب عليك كتابة هذا لكل مكون من مكونات نموذج V.

المطور الرئيسي:

"أليس، هذا النص مطول جدًّا. يتوفر في Vue 3.4 defineModel الذي يقوم بذلك في سطر واحد."

(2) الشكل 3.4: الحل العام لماكرو defineModel

JS
// ✅ Correct Version:1 All set v-model
const modelValue = defineModel('modelValue')

// It's possible now:
// - Read: modelValue.value
// - Write: modelValue.value = 'new value' (Automatic emit)
// - watch:watch(modelValue, ...)
// - Parent Component v-model Two-way binding works as usual

10 أسطر → سطر واحد. توفر المكونات الخمسة لنموذج V 50 سطراً من التعليمات البرمجية.

(3) الإيرادات

بعد الترقية إلى defineModel:



3. شرح مفصل لماكرو defineModel

(1) الاستخدام الأساسي

VUE
<!-- Child component:CustomInput.vue -->
<template>
  <input :value="modelValue" @input="modelValue = $event.target.value">
</template>

<script setup>
// ✅ 1-line v-model
const modelValue = defineModel('modelValue')
</script>
VUE
<!-- Parent Component:Usage v-model -->
<template>
  <CustomInput v-model="searchQuery" />
  <p>Search: {{ searchQuery }}</p>
</template>

<script setup>
import { ref } from 'vue'
const searchQuery = ref('')
</script>

(2) 5 استخدامات متقدمة

JS
// 1. Default value
const modelValue = defineModel('modelValue', { default: '' })

// 2. Type Constraints(TypeScript)
const count = defineModel<number>('count', { default: 0 })

// 3. transform Convert(Conversion at the Time of Writing)
const trimmed = defineModel('text', {
  set(value) {
    return value.trim()  // Automatic trim
  }
})

// 4. getter(Conversion During Reading)
const upper = defineModel('text', {
  get(value) {
    return value.toUpperCase()  // Always uppercase
  }
})

// 5. Several v-model
const name = defineModel('name')
const email = defineModel('email')
const phone = defineModel('phone')

(3) مثال كامل

VUE
<!-- Child component:TrimInput.vue -->
<template>
  <input :value="value" @input="value = $evento.target.value">
</template>

<script setup>
const value = defineModel('value', {
  // get: Conversion During Reading
  get(val) {
    return val?.toUpperCase() || ''
  },
  // set: Conversion at the Time of Writing
  set(val) {
    return val?.trim() || ''
  },
  default: ''
})
</script>
▶ جرّب الكود
VUE
<!-- Parent Component -->
<CustomInput v-model="name" />
<!-- User Input "alice" → trim Unchanged → uppercase → "ALICE" -->


4. تفكيك الخصائص التفاعلية

(1) المشكلات التي كانت موجودة قبل إصدار Vue 3.4

JS
// ❌ Vue 3.3 and before that
const props = defineProps({ count: Number, name: String })

// Use directly in the template props.count
// JS Key Points props.count
// Deconstruction may result in a loss of response
const { count, name } = props  // count/name Convert to a regular value

(2) Vue 3.4: تفكيك المتغيرات مع الحفاظ على سرعة الاستجابة

VUE
<!-- Child component -->
<template>
  <p>{{ count }} - {{ name }}</p>
  <button @click="count++">+1</button>
</template>

<script setup>
// ✅ Vue 3.4:Remains responsive even after deconstruction
const { count, name } = defineProps<{
  count: number
  name: string
}>()
</script>

تظل العناصر المساعدة المُفككة تفاعلية! وهذا أحد أكبر التحسينات في Vue 3.4.

(3) 5 سيناريوهات رئيسية للتطبيق

JS
// 1. Simplify props Usage
const { count, name } = defineProps<{ count: numbervalue; name: string }>()

// 2. Deconstruction + Rename
const { count: total, name: userName } = defineProps<{ count: numbervalue; name: string }>()

// 3. Deconstruction + Default value
const { count = 0, name = 'Guest' } = defineProps<{ count?: numbervalue; name?: string }>()

// 4. In conjunction with watch(After deconstruction watch Still working)
const { count } = defineProps<{ count: numbervalue }>()
watch(count, (newVal) => console.log('count changed:', newVal))

// 5. In conjunction with computed(Stay responsive as well)
const { count } = defineProps<{ count: numbervalue }>()
const double = computed(() => count * 2)

(4) ملاحظات مهمة

JS
// ⚠️ Deconstructed props Cannot be reassigned
const { count } = defineProps<{ count: number }>()
count = 10  // ❌ Error:Assignment to constant variable

// ✅ Correct:Via emit Have the parent component modify
const emit = defineEmits(['update:count'])
const handleClick = () => emit('update:count', count + 1)


5. useId: المعرّف الفريد

(1) لماذا نحتاج إلى useId؟

أثناء عملية العرض من جانب الخادم (SSR)، قد تتسبب المعرّفات المكتوبة يدويًّا في حدوث تعارضات (استخدام عدة مثيلات للمكون نفسه باستخدام المعرّف نفسه). يقوم useId بإنشاء معرّفات فريدة عالميًّا وآمنة للاستخدام مع SSR.

JS
// ❌ Old notation:Handwritten ID,SSR There will be a conflict
const id = `input-${Math.random()}`

// ✅ Vue 3.4+:useId
import { useId } from 'vue'
const id = useId()  // 'v-0', 'v-1', ...

(2) 5 حالات استخدام رئيسية

VUE
<!-- 1. Form label Relationship -->
<template>
  <label :for="id">Username</label>
  <input :id="id" v-model="username">
</template>

<script setup>
import { useId } from 'vue'
const id = useId()
const username = ref('')
</script>

<!-- 2. ARIA Properties -->
<template>
  <button :aria-describedby="`${id}-help`">Click</button>
  <p :id="`${id}-help`">This button does X</p>
</template>

<!-- 3. Form Error Messages -->
<template>
  <input v-model="email" :aria-invalid="!!error" :aria-errormessage="`${id}-error`">
  <p v-if="error" :id="`${id}-error`">{{ error }}</p>
</template>

<!-- 4. Tooltip Relationship -->
<template>
  <button :aria-describedby="`${id}-tip`">?</button>
  <span :id="`${id}-tip`" class="tooltip">Help text</span>
</template>

<!-- 5. Modal Window -->
<template>
  <div :id="`${id}-modal`" role="dialog" aria-modal="true">
    ...
  </div>
</template>

(3) 5 مزايا رئيسية

الميزة الوصف
أمان SSR مطابقة معرّف الخادم/العميل
فريد لا يحدث تعارض بين المثيلات المتعددة في نفس الصفحة
مستقر لا يزال إعادة عرض المكونات دون تغيير
قابل للقراءة تتضمن المعرّفات البادئة v- لتسهيل التعرف عليها
خفيف الوزن 0 تبعيات (مُدمجة في Vue)


6. useTemplateRef (شرح مفصل لـ Vue 3.5+)

(1) الميزات الكاملة

VUE
<template>
  <input ref="usernameInput">
  <MyChart ref="chartComponent" :data="chartData" />
</template>

<script setup lang="ts">
import { useTemplateRef, onMounted } from 'vue'
import MyChart from './MyChart.vue'

// ✅ Vue 3.5+:One Name Does It All
const inputRef = useTemplateRef<HTMLInputElement>('usernameInput')
const chartRef = useTemplateRef<InstanceType<typeof MyChart>>('chartComponent')

// ✅ TypeScript Perfect Inference
onMounted(() => {
  inputRef.value?.focus()  // HTMLInputElement Type
  chartRef.value?.refresh()  // Component Instance Methods
})
</script>

(2) مقارنة بين Vue 3.5 و Vue 3.4

البعد متغير ref في Vue 3.4 useTemplateRef في Vue 3.5
مرجع القالب <input ref="inputRef"> <input ref="usernameInput">
مرجع JS const inputRef = ref(null) const inputRef = useTemplateRef('usernameInput')
استدلال الأنواع يدوي ref<HTMLInputElement | null> الاستدلال التلقائي
اتساق الأسماء لا يتم الإبلاغ عن الأخطاء الإملائية المحتملة يتم الإبلاغ عن حالات عدم الاتساق
الإيجاز سطران سطر واحد


7. 5 مسارات الترقية الموصى بها

(1) وقت الترقية

إصدار Vue تاريخ الإصدار الstatus
Vue 3.0 سبتمبر 2020 إصدار قديم (يُنصح بالترقية)
Vue 3.2 أغسطس 2021 إصدار مستقر
Vue 3.3 مايو 2023 إصدار مستقر
Vue 3.4 ديسمبر 2023 موصى به حاليًا
Vue 3.5 سبتمبر 2024 أحدث إصدار مستقر

(2) قائمة الترقيات

TEXT 📖 للعرض فقط
✅ Vue 3.4:
  - defineModel Macro Replacement v-model Complex Notation
  - Responsive props Deconstruction
  - Abbreviations with the Same Name(<input :value> Replace :value="value")
  - Improvements to Error Handling
  - Template Parser Override(2x Performance)

✅ Vue 3.5:
  - useTemplateRef(Recommendations)
  - Responsive props Deconstruction and Improvement
  - useId Stable
 - Deferred teleport
  - Improved Suspense

(3) توصيات الترقية

السيناريو التوصية
مشروع جديد استخدام Vue 3.5+ مباشرةً
مشروع قديم (Vue 3.3–) الترقية إلى الإصدار 3.5، الترحيل حسب الميزة
مشروع قديم (Vue 3.0–3.2) الترقية إلى الإصدار 3.3، ثم إلى الإصدار 3.5
المشاريع الضخمة التحديثات التدريجية (تحديث Vue أولاً، ثم ترحيل v-model، وما إلى ذلك)


8. مثال كامل: تطبيق شامل باستخدام Vue 3.4+

▶ مثال: 1. 5 طرق لاستخدام defineModel

VUE
<!-- 1. Basics -->
<script setup>
const modelValue = defineModel('modelValue')
</script>

<!-- 2. Default value -->
<script setup>
const count = defineModel('count', { default: 0 })
</script>

<!-- 3. TypeScript Type -->
<script setup lang="ts">
const user = defineModel<User>('user', { default: () => ({}) })
</script>

<!-- 4. transform Convert -->
<script setup>
const trimmed = defineModel('text', {
  set(val) { return val?.trim() || '' }
})
</script>

<!-- 5. Several v-model -->
<script setup>
const username = defineModel('username')
const password = defineModel('password')
</script>
▶ جرّب الكود

▶ مثال: 2. تفكيك الخصائص التفاعلية

VUE
<template>
  <p>{{ count }} - {{ name }}</p>
  <button @click="emit('update:count', count + 1)">+1</button>
</template>

<script setup lang="ts">
// ✅ Vue 3.4+:Deconstructing Responsiveness
const { count, name } = defineProps<{
  count: number
  name: string
}>()

const emit = defineEmits<{
  'update:count': [value: number]
}>()
</script>
▶ جرّب الكود

▶ مثال: 3. حالات الاستخدام الرئيسية لـ useId 5

VUE
<template>
  <label :for="id">Email</label>
  <input :id="id" v-model="email" :aria-invalid="!!error" :aria-errormessage="`${id}-error`">
  <p v-if="error" :id="`${id}-error`" class="error">{{ error }}</p>
</template>

<script setup>
import { ref, useId } from 'vue'
const id = useId()  // v-0, v-1, ...
const email = ref('')
const error = ref('')
</script>
▶ جرّب الكود

▶ مثال: 4. استكمال الطلب باستخدام useTemplateRef

VUE
<template>
  <input ref="usernameInput" v-model="username">
  <MyChart ref="chartComponent" :data="chartData" />
</template>

<script setup lang="ts">
import { ref, useTemplateRef, onMounted } from 'vue'
import MyChart from './MyChart.vue'

const username = ref('')
const chartData = ref([1, 2, 3])

// ✅ Vue 3.5+:TypeScript Perfect Inference
const inputRef = useTemplateRef<HTMLInputElement>('usernameInput')
const chartRef = useTemplateRef<InstanceType<typeof MyChart>>('chartComponent')

onMounted(() => {
  inputRef.value?.focus()
  chartRef.value?.refresh()
})
</script>
▶ جرّب الكود

▶ مثال: 5. مرجع سريع لـ 5 أخطاء شائعة

الخطأ الأعراض الحل
تفكيك defineModel لا توجد استجابة استخدم const modelValue = defineModel() مباشرةً
التعيين بعد تفكيك خصائص props خطأ استخدم emit للسماح للعنصر الأصلي بالتحديث
useId مع سلسلة نصية مبرمجة ثابتًا تعارض في SSR التبديل إلى useId()
اسم useTemplateRef غير صحيح ref.value قيمة فارغة يجب أن يتطابق الاسم
يتطلب الترقية إلى Vue 3.4+ تغييرات كثيرة جدًّا مشكلات التوافق الترحيل التدريجي

▶ مثال: 6. 5 مزايا رئيسية للترقية إلى Vue 3.4 أو أحدث

الإيرادات البيانات
تقليل حجم الكود 30–50% (تبسيط defineModel)
تحسينات في الأداء تحليل القوالب أسرع بمقدار الضعف
استدلال الأنواع دقة 100% (TypeScript)
متوافق مع SSR استخدام useId لحل تعارضات المعرّفات
تجربة المطور تحسينات كبيرة في تجربة المطور


❓ أسئلة شائعة

س هل يحل defineModel محل الصيغة الكاملة لـ v-model؟
ج نعم. defineModel('modelValue') is equivalent to the 10 lines of code in props.modelValue + emit('update:modelValue'). وهو متوافق تمامًا مع الإصدارات السابقة.
س متى سيتم دعم تفكيك الخصائص التفاعلية؟
ج في الإصدار Vue 3.4 وما بعده (ديسمبر 2023). غير مدعوم في الإصدار Vue 3.3 والإصدارات الأقدم. تظل الخصائص المفككة تفاعلية (التفاعلية العميقة هي الإعداد الافتراضي).
س هل يتغير useId مع كل عملية عرض؟
ج لا. يظل المعرّف الذي يتم إنشاؤه بواسطة useId ثابتًا طوال دورة حياة المكون (متسقًا بين SSR والعميل).
س ما الفرق بين useTemplateRef ومتغيرات ref؟
ج تم تقديم useTemplateRef في الإصدار Vue 3.5 وما بعده؛ وهو يوفر استدلالًا أقوى لأنواع TypeScript وإعادة تسمية أكثر أمانًا. أما بالنسبة للمشاريع العادية، فتكفي متغيرات ref.
س هل يمكن استخدام عملية تفكيك defineProps مع watch؟
ج نعم. تعمل const { count } = defineProps() + watch(count, ...) بشكل مثالي.
س كيف يمكنني الترقية من Vue 3.3 إلى 3.4+؟
ج npm update vue@latest. على مستوى الكود: استخدم defineModel بدلاً من بناء الجملة المعقد v-model؛ واستخدم تفكيك المتغيرات التفاعلي بدلاً من props.xxx. دون أي أعطال.
س ما هي التحسينات التي أدخلتها Vue 3.5+ على TypeScript؟
ج التفكيك التفاعلي باستخدام defineProps، والاستدلال التام على الأنواع باستخدام useTemplateRef، ودعم أكثر شمولاً لـ TypeScript فيما يتعلق بالماكرو. نوصي باستخدام <script setup lang="ts">.

📖 ملخص


📝 تمارين

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

    إعادة هيكلة مكون نموذج v باستخدام defineModel:

    • المكون الفرعي CustomInput.vue: سطر واحد من defineModel
    • المكون الأصلي: الربط ثنائي الاتجاه في نموذج v
    • يدعم القيم الافتراضية
  2. مسائل متقدمة (مستوى الصعوبة: ⭐⭐)

    إعادة كتابة المكونات باستخدام التفكيك التفاعلي في Vue 3.4+:

    • تفكيك الخصائص مثل «count» و«name» وغيرها
    • باستخدام الساعة + الحساب
    • اختبار التصميم المتجاوب
  3. مسألة التحدي (مستوى الصعوبة: ⭐⭐⭐)

    مثال على عملية ترقية كاملة إلى Vue 3.4+:

    1. استبدال بناء الجملة المعقد لنموذج V بـ defineModel في 5 مكونات
    2. تفكيك 3 مكونات باستخدام عناصر تفاعلية
    3. 5 مكونات تستخدم useId (لربط label وinput)
    4. 3 مكونات تستخدم useTemplateRef (Vue 3.5+)
    5. 5 مكونات TypeScript ذات الأنواع القوية
    6. اختبار اتساق useId في سيناريو SSR
Web-Tutorial.com

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

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

100%