Vue.js: قواعد القوالب

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

تعد صيغة «template» في Vue امتدادًا إعلانيًا لـ HTML — فهي تضيف «التوجيهات» و«الاستيفاء» إلى HTML القياسي، مما يتيح لك عرض البيانات في DOM. تتشابه صيغة «template» بأكملها بنسبة 90% مع HTML، لذا يمكن لأي شخص على دراية بـ HTML البدء في استخدامها خلال 30 دقيقة.

تتمحور قوالب Vue حول ثلاثة عناصر أساسية: الاستيفاء (عرض البيانات) + التوجيهات (ربط الخصائص/الأحداث) + التعبيرات (تنفيذ جافا سكريبت). سيرشدك هذا الدرس إلى الطرق القياسية لاستخدام هذه العناصر الثلاثة.

1. ما ستتعلمه



2. متطلبات عرض بطاقة منتج التجارة الإلكترونية

(1) المشكلة: 30 منتجًا — هل يجب النسخ واللصق 30 مرة؟

تقوم أليس بإنشاء لوحة تحكم إدارية لموقع تجارة إلكترونية. وهي بحاجة إلى عرض 30 بطاقة منتج. نهجها الأولي هو:

HTML
<!-- Copy and paste 30 times, nightmare... -->
<div class="product-card">
  <h3>iPhone 15 Pro</h3>
  <p>Price: $999</p>
  <button>Edit</button>
</div>
<div class="product-card">
  <h3>MacBook Pro</h3>
  <p>Price: $2499</p>
  <button>Edit</button>
</div>
<!-- ... And also 28 more ... -->

عندما يقول مدير المنتج تشارلي: «غيّر تنسيق السعر ليظهر رمز العملة»:

«أليس، لا يمكنك تعديل 30 ملفًا يدويًّا. وماذا لو كان لدينا 5,000 منتج الشهر المقبل؟ نحن بحاجة إلى قالب ديناميكي.»

(2) حل القوالب في Vue: مكون واحد، 30 نقطة بيانات

VUE
<template>
  <div v-for="product in products" :key="product.id" class="product-card">
    <h3>{{ product.name }}</h3>
    <p>Price: ${{ product.price }}</p>
    <button @click="editProduct(product.id)">Edit</button>
  </div>
</template>

<script setup>
const products = ref([
  { id: 1, name: 'iPhone 15 Pro', price: 999 },
  { id: 2, name: 'MacBook Pro', price: 2499 },
  // ... 30 items, each only 1 line 1 ...
])
function editProduct(id) {
  console.log('Editing product', id)
}
</script>

5 أسطر من كود القالب × 30 منتجًا = لا حاجة إلى النسخ واللصق. وعندما تتغير أسماء المنتجات أو أسعارها، يقوم Vue بتحديث DOM تلقائيًا.

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

بعد اعتماد قوالب Vue:



3. الاستيفاء: Mustache {{ }}

(1) 4 طرق لتنفيذ الاستيفاء

الصيغة النتيجة مثال
{{ var }} عرض قيمة المتغير <p>{{ username }}</p> → أليس
{{ expr }} عرض نتيجة تعبير JS <p>{{ count + 1 }}</p> → 6
{{ fn() }} قيمة الإرجاع لنداء الدالة <p>{{ formatDate(date) }}</p> → 2 يوليو 2026
{{ obj.prop }} الوصول إلى خصائص الكائن <p>{{ user.name }}</p> → أليس

(2) الخصائص الخمس الرئيسية لعملية الاستيفاء

VUE
<template>
  <!-- 1. Automatically Responsive:Automatically updates when variables change -->
  <p>{{ message }}</p>
  
  <!-- 2. Support JS Expression(Cannot write statements)-->
  <p>{{ count * 2 + 1 }}</p>
  <p>{{ isVip ? 'VIP' : 'Regular' }}</p>
  <p>{{ items.length > 0 ? items[0].name : 'Empty' }}</p>
  
  <!-- 3. Supports ternary expressions,Arithmetic,Function Call -->
  <p>{{ new Date().getFullYear() }}</p>
  
  <!-- 4. Not supported: if/for/Variable Declaration (Use v-if/v-for instead) -->
  <!-- ❌ {{ if (x) { y } }}  // Wrong -->
  <!-- ✅ <p v-if=\"x\">y</p>     // Correct -->
  
  <!-- 5. Support for template strings -->
  <p>{{ `Hello, ${name}!` }}</p>
</template>

(3) الفرق بين الاستيفاء وـ v-text

VUE
<template>
  <!-- Interpolation:You can add other content here -->
  <p>Welcome, {{ name }}!</p>
  
  <!-- v-text:Replace the entire element's content -->
  <p v-text="`Welcome, ${name}!`"></p>
  <!-- The above is equivalent to <p>Welcome, {{ name }}!</p> -->
</template>


4. توجيهات النص: v-text / v-html / v-once

(1) مقارنة بين الأوامر الثلاثة

الأمر الوظيفة status الاستخدام الأمان
{{ }} الاستيفاء استيفاء النص الإعداد الافتراضي ✅ الأمان
v-text تعيين خاصية textContent لعنصر ما صيغة بديلة للتقريب ✅ آمن
v-html تعيين قيمة innerHTML لعنصر ما عرض النص المنسق (يُستخدم بحذر) ⚠️ خطر XSS
v-once عرض مرة واحدة، دون تحديثات لاحقة تحسين ثابت ✅ الأمان

(2) تحذير v-html

VUE
<template>
  <!-- ✅ Safety:Content You Control -->
  <div v-html="markdownHtml"></div>
  
  <!-- ❌ Danger:User-entered HTML -->
  <div v-html="userComment"></div>
  <!-- User Input <script>alert('hacked')</script> Will be executed! -->
  
  <!-- ✅ Recommended: Use DOMPurify Cleanup -->
  <div v-html="DOMPurify.sanitize(userComment)"></div>
</template>

(3) تحسين أداء v-once

VUE
<template>
  <!-- This productId won't change → Use v-once to Reduce Reactive Overhead -->
  <span v-once>{{ productId }}</span>
  
  <!-- But this currentPrice Will change → Do not use v-once -->
  <span>{{ currentPrice }}</span>
</template>


5. ربط الخصائص: v-bind والاختصار :

(1) أساسيات v-bind

VUE
<template>
  <!-- Complete Syntax -->
  <img v-bind:src="imageUrl" v-bind:alt="imageAlt">
  
  <!-- Abbreviation(Recommendations):Remove v-bind,Only : -->
  <img :src="imageUrl" :alt="imageAlt">
  
  <!-- Dynamic property names(v-bind Special Syntax)-->
  <img :[dynamicAttr]="value">
</template>

(2) ربط الفئة والأسلوب (نقطة أساسية)

VUE
<template>
  <!-- 1. Object Syntax:Switch Based on Conditions class -->
  <div :class="{ active: isActive, 'text-danger': hasError }">
    Conditional classes
  </div>
  
  <!-- 2. Array Syntax:Apply multiple at the same time class -->
  <div :class="[activeClass, errorClass]">
    Multiple classes
  </div>
  
  <!-- 3. Trinomial Expression(Array + Object)-->
  <div :class="[isActive ? 'active' : '', { 'has-error': hasError }]">
    Mixed
  </div>
  
  <!-- 4. Nested Objects in an Array -->
  <div :class="[{ active: isActive }, errorClass]">
    Nested
  </div>
</template>

(3) أسلوب الربط

VUE
<template>
  <!-- 1. Object Syntax -->
  <div :style="{ color: activeColor, fontSize: fontSize + 'px' }">
    Styled
  </div>
  
  <!-- 2. Array Syntax(Merge multiple style Object)-->
  <div :style="[baseStyles, overridingStyles]">
    Multi styles
  </div>
  
  <!-- 3. CSS Variable(Vue 3 Recommendations)-->
  <div :style="{ '--main-color': mainColor }">
    With CSS variables
  </div>
</template>


6. ربط الأحداث: v-on والاختصار @

(1) أساسيات v-on

VUE
<template>
  <!-- Complete Syntax -->
  <button v-on:click="handleClick">Click</button>
  
  <!-- Abbreviation(Recommendations)-->
  <button @click="handleClick">Click</button>
  
  <!-- Inline Processor(Write the simple logic directly)-->
  <button @click="count++">Increment</button>
  
  <!-- Passing Parameters -->
  <button @click="handleClick('arg1', $event)">Click</button>
</template>

(2) مُعدِّلات الأحداث الشائعة (9)

VUE
<template>
  <!-- 1. .stop:Prevent Bubbling(e.stopPropagation())-->
  <button @click.stop="handleClick">Stop propagation</button>
  
  <!-- 2. .prevent:Prevent the default behavior(e.preventDefault())-->
  <form @submit.prevent="handleSubmit">Submit</form>
  
  <!-- 3. .once:Triggered only once -->
  <button @click.once="handleClick">Click once</button>
  
  <!-- 4. .self:Only event.target This is triggered only if it is the current element -->
  <div @click.self="handleClick">Self only</div>
  
  <!-- 5. .capture:Using the Capture Phase -->
  <div @click.capture="handleClick">Capture</div>
  
  <!-- 6. .passive:Do not prevent the default behavior(Performance Optimization)-->
  <div @scroll.passive="onScroll">Passive scroll</div>
  
  <!-- 7. Keyboard Modifiers -->
  <input @keyup.enter="submit">     <!-- Enter Key -->
  <input @keyup.esc="cancel">       <!-- Esc Key -->
  <input @keyup.tab="nextField">    <!-- Tab Key -->
  <input @keyup.delete="deleteItem"> <!-- Delete Key -->
  
  <!-- 8. Mouse Modifiers -->
  <button @click.left="leftClick">Left</button>
  <button @click.right.prevent="rightClick">No right click</button>
  <button @click.middle="middleClick">Middle</button>
  
  <!-- 9. System Modifiers(Key combinations)-->
  <button @click.ctrl="save">Ctrl + Click</button>
  <button @click.ctrl.exact="save">Accurate Ctrl(You cannot add other keys)</button>
</template>

(3) سلاسل المُعدِّلات

VUE
<template>
  <!-- Combinations of Multiple Modifiers(Execute in order)-->
  <button @click.stop.prevent="handle">Stop + Prevent</button>
  
  <!-- is effectively equivalent to -->
  <button @click="(e) => { e.stopPropagation(); e.preventDefault(); handle(); }">
    Manual
  </button>
</template>


7. قيود التعبير (لا يُسمح بإبداء الآراء)

(1) تعبيرات القوالب مقابل جمل جافا سكريبت

VUE
<template>
  <!-- ✅ Sure.(Expression,Has a return value)-->
  <p>{{ count + 1 }}</p>
  <p>{{ isVip ? 'VIP' : 'Regular' }}</p>
  <p>{{ items.filter(i => i.active).length }}</p>
  
  <!-- ❌ That won't work.(Statement,No return value)-->
  <!-- <p>{{ const x = 1 }}</p>      // Wrong: Variable Declaration -->
  <!-- <p>{{ if (x) { y } }}</p>     // Wrong: if Statement -->
  <!-- <p>{{ for (i of arr) {} }}</p> // Wrong: for Loop -->
  
  <!-- ✅ Switch to v-if / v-for Instructions -->
  <p v-if="x">y</p>
  <div v-for="i in arr" :key="i.id">{{ i.name }}</div>
</template>

(2) التعبيرات مقابل الخصائص المحسوبة

السيناريو استخدام التعبيرات استخدام الخصائص المحسوبة
العمليات الحسابية البسيطة (1–2 علامات حسابية)
منطق معقد (متعدد الخطوات، حلقات)
التخزين المؤقت مطلوب
المعلمات المطلوبة ❌ (استخدم طريقة بدلاً من ذلك)
VUE
<template>
  <!-- Simple:Expression -->
  <p>{{ price * quantity }}</p>
  
  <!-- Complex:Computed Properties(computed)-->
  <p>{{ totalWithTax }}</p>
</template>


8. توجيهات Edge: v-pre / v-cloak

(1) v-pre: تخطي عملية الترجمة

VUE
<template>
  <!-- Skip compiling this element,{{ }} Display as is -->
  <span v-pre>{{ this is literal, not interpolated }}</span>
</template>

السيناريو: توضيح بناء جملة قوالب Vue نفسها (مثل الدروس التعليمية ومواقع الوثائق).

(2) v-cloak: إخفاء قبل التحويل البرمجي

VUE
<template>
  <!-- v-cloak Make elements invisible until compilation is complete -->
  <p v-cloak>{{ message }}</p>
</template>

<style>
[v-cloak] { display: none; }
</style>

السيناريو: منع المستخدمين من رؤية {{ message }} تومض قبل التجميع.



9. مثال كامل: بطاقات المنتجات الديناميكية

▶ مثال: 1. بطاقة المنتج الأساسية

VUE
<template>
  <div class="product-card">
    <h3>{{ product.name }}</h3>
    <p class="price">${{ product.price }}</p>
    <span :class="['badge', stockStatusClass]">
      {{ stockStatusText }}
    </span>
    <button :disabled="product.stock === 0" @click="addToCart">
      Add to Cart
    </button>
  </div>
</template>

<script setup>
import { computed } from 'vue'

const props = defineProps({
  product: { type: Object, required: true }
})

const stockStatusClass = computed(() => {
  if (props.product.stock === 0) return 'out-of-stock'
  if (props.product.stock < 10) return 'low-stock'
  return 'in-stock'
})

const stockStatusText = computed(() => {
  if (props.product.stock === 0) return 'Out of Stock'
  if (props.product.stock < 10) return `Only ${props.product.stock} left`
  return 'In Stock'
})

function addToCart() {
  console.log('Added', props.product.name)
}
</script>
▶ جرّب الكود

▶ مثال: 2. طرق مختلفة لكتابة عملية الاستيفاء

VUE
<template>
  <!-- Variable Interpolation -->
  <p>{{ username }}</p>
  
  <!-- Expression Interpolation -->
  <p>{{ count * 2 + 1 }}</p>
  
  <!-- Trinomial Expression -->
  <p v-if="score >= 60">Passed</p>
  <p v-else>Failed</p>
  
  <!-- Function Call -->
  <p>{{ formatDate(new Date()) }}</p>
  
  <!-- Object Access -->
  <p>{{ user.profile.name }}</p>
</template>
▶ جرّب الكود

▶ مثال: 3. 5 طرق لاستخدام v-bind

VUE
<template>
  <!-- 1. Basic Binding -->
  <img :src="imageUrl">
  
  <!-- 2. Dynamic property names -->
  <img :[attrName]="value">
  
  <!-- 3. Object Syntax(class)-->
  <div :class="{ active: isActive }">A</div>
  
  <!-- 4. Array Syntax(class)-->
  <div :class="[activeClass, errorClass]">B</div>
  
  <!-- 5. String Concatenation(href)-->
  <a :href="`/users/${userId}`">Profile</a>
</template>
▶ جرّب الكود

▶ مثال: 4. 5 طرق لكتابة v-on

VUE
<template>
  <!-- 1. Just a click -->
  <button @click="handleClick">Click</button>
  
  <!-- 2. Inline Statements -->
  <button @click="count++">+</button>
  
  <!-- 3. Passing Parameters + event Object -->
  <button @click="handleDelete(item.id, $event)">Delete</button>
  
  <!-- 4. Modifier Chain -->
  <button @click.stop.prevent="handle">Save</button>
  
  <!-- 5. Keyboard shortcuts -->
  <input @keyup.ctrl.enter="submit">
</template>
▶ جرّب الكود

▶ مثال: 5. القوالب مقابل HTML — مرجع سريع

العنصر صيغة HTML صيغة Vue الوصف
نص ثابت <p>Hello</p> <p>{{ msg }}</p> تحويل إلى نص ديناميكي
خاصية ثابتة <img src="x.jpg"> <img :src="url"> التغيير إلى ديناميكي
فئة ثابتة <div class="box"> <div :class="cls"> التغيير إلى ديناميكية
النمط الثابت <div style="color: red"> <div :style="sty"> التبديل إلى النمط الديناميكي
حدث النقر <button onclick="fn()"> <button @click="fn"> تعديل Vue
العرض الشرطي لا شيء <div v-if="ok"> خاص بـ Vue
عرض القائمة لا شيء <div v-for="i in list"> خاص بـ Vue

▶ مثال: 6. 5 أخطاء شائعة

الخطأ الأعراض الحل
احذف .value اكتب {{ count }} في القالب، وcount.value في ملف JS يقوم القالب بفك التعبئة تلقائيًا؛ أما ملف JS فيحتاج إلى .value
كتابة if/for في {{ }} أخطاء الترجمة استخدام توجيهات v-if / v-for
v-html XSS مدخلات المستخدم <script> التنفيذ التنظيف باستخدام DOMPurify
لم تتلقَ الدالة المضمنة $event يتعذر الوصول إلى كائن الحدث @click="fn($event)" قم بتمريره صراحةً
ترتيب المُعدِّلات غير صحيح فشل في منع انتقال التأثير .stop يسبق .prevent (حسب الحاجة)


❓ أسئلة شائعة

س ما الفرق بين {{ }} و v-text؟
ج لهما نفس التأثير — فكلاهما يضبطان خاصية textContent للعنصر. الفرق هو أن {{ }} يمكن استخدامه جنبًا إلى جنب مع النص الثابت (<p>Hi, {{ name }}</p>)، بينما يجب أن يشغل v-text العنصر بأكمله (<p v-text="msg"></p>). نوصي باستخدام {{ }} لمزيد من المرونة.
س هل v-html آمن؟
ج لا، إنه غير آمن. يقوم v-html بتحليل السلاسل على أنها HTML، مما يسمح للمستخدمين الضارين بإدخال <script> لمهاجمة موقعك. ما لم تكن تثق بنسبة 100% في مصدر البيانات (مثل أداة عرض Markdown قمت بكتابتها بنفسك)، استخدم {{ }} للتقريب أو قم بتنقية البيانات أولاً باستخدام DOMPurify.sanitize().
س ما هو ترتيب تنفيذ سلسلة مُعدِّلات v-on؟
ج من اليسار إلى اليمين. على سبيل المثال، يستدعي @click.stop.prevent أولاً stopPropagation()، ثم preventDefault().
س هل يمكن اختصار v-bind؟ وهل يمكن اختصار v-on أيضًا؟
ج اختصار v-bind هو : (بدون v-bind)، واختصار v-on هو @ (موصى به). كلا الاختصارين هما ترميزات رسمية مدعومة منذ الإصدار Vue 2، وتدعمهما ميزة تمييز الصيغة في بيئة تطوير المتكاملة (IDE) وميزة الإكمال التلقائي.
س هل يمكنني استخدام عبارات if/else في القوالب؟
ج لا. يجب أن تُرجع تعبيرات القوالب قيمةً، وعبارات if وfor هي عبارات برمجية وليست تعبيرات. استخدم التوجيهات v-if وv-else-if وv-else لتنفيذ العرض الشرطي.
س كيف يمكن التبديل ديناميكيًا بين فئات متعددة باستخدام v-bind؟
ج استخدم صيغة الكائن :class="{ active: isActive, 'text-danger': hasError }". أو صيغة الarray :class="[activeClass, errorClass]". يمكنك المزج بين الصيغتين: :class="[isActive && 'active', { 'error': hasError }]".
س كيف يمكنني استجابة اختصار لوحة المفاتيح Ctrl+S؟
ج استخدم مُعدِّل النظام @keyup.ctrl.s="save" أو @keydown.ctrl.s.prevent="save" (أضف .prevent لمنع ظهور مربع حوار الحفظ الافتراضي للمتصفح). يدعم Vue 3 أيضًا المُعدِّل الدقيق .exact؛ على سبيل المثال، يتطلب @click.ctrl.exact الضغط على مفتاح Ctrl فقط — ولا يُسمح بالضغط على أي مفاتيح أخرى.

📖 ملخص


📝 تمارين

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

    اكتب مكونًا في Vue 3 يعرض بطاقة مستخدم تحتوي على:

    • اسم المستخدم (الاستيفاء)
    • صورة الملف الشخصي (v-bind)
    • زر «متابعة» (v-on)
    • status الاتصال/عدم الاتصال (زر تبديل ديناميكي)

    البيانات المستخدمة: كائن المستخدم { name: 'Alice', avatar: 'alice.jpg', online: true }

  2. مسائل متقدمة (مستوى الصعوبة: ⭐⭐)

    قم بتطبيق قائمة مهام بسيطة:

    • حقل الإدخال (لا يُستخدم نموذج v في الوقت الحالي؛ يتم محاكاته باستخدام v-bind:value + @input)
    • زر «إضافة» (@click + تعبير)
    • عرض القوائم (v-for؛ سنتناول هذا الموضوع في الدرس التالي)
    • يحتوي كل عنصر على زر حذف (@click + تمرير المعلمات)

    البيانات: const todos = ref(['Learn Vue', 'Build app', 'Deploy'])

  3. مسألة التحدي (مستوى الصعوبة: ⭐⭐⭐)

    اكتب مكونًا كاملاً لبطاقة تفاصيل المنتج يدعم ما يلي:

    1. 5 شارات لstatus المنتج (متوفر/غير متوفر/طلب مسبق/معروض للبيع/تم إيقاف إنتاجه)
    2. تتوافق 5 حالات مع ألوان فئات مختلفة (يتم ربطها بشكل جماعي باستخدام صيغة الكائنات)
    3. أزرار زيادة/تقليل الكمية (النقر عليها يؤدي إلى الزيادة/التقليل)
    4. تعطيل زر «إضافة إلى سلة التسوق» عندما تكون الكمية أكبر من أو تساوي الكمية المتوفرة في المخزون (:يتم تعطيله ديناميكيًا)
    5. ما لا يقل عن 3 مُعدِّلات للأحداث (@click.stop، @submit.prevent، إلخ)
Web-Tutorial.com

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

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

100%