Vue.js: العرض الشرطي والقوائم

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

يُعد العرض الشرطي (v-if / v-show) وعرض القوائم (v-for) أكثر التوجيهات استخدامًا في قوالب Vue. يتحكم الأول في ما إذا كان العنصر سيُعرض أم لا، بينما يتحكم الثاني في عدد العناصر التي يتم عرضها. ويمكن لهذين التوجيهين معًا التعامل مع 90% من سيناريوهات واجهة المستخدم.

يُعد فهم الاختلافات الخمسة الرئيسية بين v-if وv-for، بالإضافة إلى الاستخدام الصحيح لـ :key، أمرًا ضروريًا لتطوير تطبيقات Vue عالية الأداء.

1. ما ستتعلمه

العرض المشروط



2. كابوس البرمجة: «عبارات if المتداخلة» في لوحة المعلومات

(1) المشكلة: 5 علامات v-if متداخلة — كابوس في عملية تصحيح الأخطاء

خرج كود لوحة التحكم الخاصة بأليس عن السيطرة:

VUE
<!-- ❌ The "Broken" Version:v-if Nested Hell -->
<template>
 <div v-if="user">
 <div v-if="user.isAdmin">
 <div v-if="orders.length > 0">
 <div v-if="!isLoading">
 <div v-if="!hasError">
 <!-- Content is finally displayed -->
 <p>Orders: {{ orders.length }}</p>
 </div>
 <div v-else>Error: {{ errorMsg }}</div>
 </div>
 <div v-else>Loading...</div>
 </div>
 <div v-else>No orders</div>
 </div>
 <div v-else>Not admin</div>
 </div>
 <div v-else>Please login</div>
</template>

مراجعة الكود من تشارلي:

"أليس، هذا غير قابل للقراءة. هناك 5 مستويات من التداخل في عبارات v-if. ماذا لو أضفنا شرطين آخرين؟ نحن بحاجة إلى نمط أكثر بساطة."

(2) حل Vue: التسوية باستخدام v-if + الخصائص المحسوبة

VUE
<template>
 <div v-if="!user">Please login</div>
 
 <div v-else-if="!user.isAdmin">Not admin</div>
 
 <div v-else-if="isLoading">Loading...</div>
 
 <div v-else-if="hasError">Error: {{ errorMsg }}</div>
 
 <div v-else-if="orders.length === 0">No orders</div>
 
 <div v-else>
 <p>Orders: {{ orders.length }}</p>
 <OrderList :orders="orders" />
 </div>
</template>

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

const props = defineProps(['user', 'orders', 'isLoading', 'hasError', 'errorMsg'])

// Flatten 5 conditions (v-else-if chain)
</script>

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



3. العرض الشرطي باستخدام v-if / v-else-if / v-else

(1) قواعد النحو الأساسية

VUE
<template>
 <!-- Single condition -->
 <p v-if="isVisible">Visible</p>
 
 <!-- Choose one of the two -->
 <p v-if="score >= 60">Passed</p>
 <p v-else>Failed</p>
 
 <!-- Choose one or more -->
 <p v-if="type === 'A'">Type A</p>
 <p v-else-if="type === 'B'">Type B</p>
 <p v-else-if="type === 'C'">Type C</p>
 <p v-else>Unknown</p>
</template>

(2) العنصر template

VUE
<template>
 <!-- template:Grouping Multiple Elements,Do not render DOM -->
 <template v-if="isAdmin">
 <h1>Admin Dashboard</h1>
 <p>Welcome, {{ user.name }}</p>
 <button>Edit</button>
 </template>
 
 <!-- Does not render template element (Savings 1 DOM layer) -->
</template>

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

السيناريو استخدام v-if
مسجل الدخول/غير مسجل الدخول
قيد التحميل.../تم التحميل
لا توجد بيانات/تتوفر بيانات
status الخطأ
التبديل المتكرر بين إظهار/إخفاء ❌ (استخدم v-show)


4. 5 اختلافات رئيسية بين v-show و v-if

(1) الاختلافات الرئيسية

VUE
<template>
 <!-- v-if: When conditions are false, Elements removed from DOM -->
 <p v-if="show">v-if</p>
 <!-- show=false: The element does not exist in DOM -->
 
 <!-- v-show: When conditions are false, display: none -->
 <p v-show="show">v-show</p>
 <!-- show=false: <p style="display: none">v-show</p> -->
</template>

(2) 5 مقارنات رئيسية

الجانب v-if v-show
التعامل مع DOM إزالة العنصر عندما تكون الstatus غير صحيحة يبقى دائمًا في DOM؛ ويتم فقط تبديل status الخاصية display
أداء التبديل ضعيف (إزالة وإعادة إنشاء في كل مرة) جيد (CSS فقط)
العرض الأولي لا يتم العرض إذا كان الشرط غير صحيح يتم العرض دائمًا (حتى لو كان غير مرئي)
التوافق مع الانتقالات ✅ مثالي (حركات الدخول/الخروج) ❌ غير مدعوم
حالات الاستخدام التبديل من حين لآخر التبديل المتكرر

(3) توصيات الاختيار

JS
// Switch Occasionally(If you are logged in/Not logged in)→ v-if
<div v-if="isLoggedIn">Welcome, {{ user.name }}</div>
<div v-else>Please login</div>

// Frequent switching (e.g. tab switch) → v-show
<button v-show="isActive">Active</button>
<button v-show="!isActive">Inactive</button>


5. عرض القوائم باستخدام v-for

(1) التكرار عبر array

VUE
<template>
 <!-- Basic Iteration -->
 <ul>
 <li v-for="item in items" :key="item.id">
 {{ item.name }}
 </li>
 </ul>
 
 <!-- Indexed -->
 <ul>
 <li v-for="(item, index) in items" :key="item.id">
 {{ index + 1 }}. {{ item.name }}
 </li>
 </ul>
</template>

<script setup>
import { ref } from 'vue'
const items = ref([
 { id: 1, name: 'Apple' },
 { id: 2, name: 'Banana' },
 { id: 3, name: 'Cherry' }
])
</script>

(2) التكرار على الكائنات

VUE
<template>
 <ul>
 <li v-for="(value, key, index) in user" :key="key">
 {{ index + 1 }}. {{ key }}: {{ value }}
 </li>
 </ul>
</template>

<script setup>
import { reactive } from 'vue'
const user = reactive({
 name: 'Alice',
 age: 25,
 email: 'alice@example.com'
})
// Output:1. name: Alice 2. age: 25 3. email: alice@example.com
</script>

(3) التكرار عبر الأرقام

VUE
<template>
 <!-- Rendering 1 to 10 -->
 <span v-for="n in 10" :key="n">{{ n }}</span>
 <!-- Output:12345678910 -->
</template>

(4) التكرار عبر سلسلة أحرف

VUE
<template>
 <!-- One character per line span -->
 <span v-for="char in 'Hello'" :key="char">{{ char }}</span>
 <!-- Output:H e l l o -->
</template>


6. الغرض من :key وأفضل الممارسات

(1) ما هو :key؟

:key قم بتعيين معرّف فريد لكل عنصر من عناصر v-for لمساعدة Vue على تحديث DOM بكفاءة.

VUE
<template>
 <!-- ❌ None :key(Vue Use by default index) -->
 <li v-for="item in item">{{ item.name }}</li>
 
 <!-- ✅ Has :key (Use "unique" id) -->
 <li v-for="item in item" :key="item.id">{{ item.name }}</li>
</template>

(2) لماذا يُعد :key ضروريًا؟

100%
graph LR
 A[Original List A B C] --> B[New List B C D]
 B --> C[None key:Possible misalignment]
 B --> D[Has key: Update Correctly]
 
 style C fill:#ff6b6b
 style D fill:#42b883

عندما لا يكون هناك :key:

عندما يكون :key موجودًا:

(3) أفضل الممارسات لـ :key

VUE
<!-- ✅ Recommendations:The Only One ID -->
<li v-for="user in users" :key="user.id">

<!-- ✅ Second choice:Unique Field(Email,Mobile phone number, etc.)-->
<li v-for="user in users" :key="user.email">

<!-- ❌ Avoid:index(When the data changes, the alignment is off.)-->
<li v-for="(user, index) in users" :key="index">

<!-- ❌ Never, under any circumstances:random()(Every render is different,Forced Rebuild)-->
<li v-for="user in users" :key="Math.random()">


7. تصفية القوائم / الفرز / تقسيم الصفحات

(1) التصفية + الفرز (الخصائص المحسوبة)

JS
import { ref, computed } from 'vue'

const items = ref([
 { id: 1, name: 'iPhone', price: 999, category: 'phone' },
 { id: 2, name: 'MacBook', price: 2499, category: 'laptop' },
 { id: 3, name: 'iPad', price: 599, category: 'tablet' }
])

const searchQuery = ref('')
const selectedCategory = ref('all')
const sortBy = ref('price') // 'price' / 'name'

// Filter + Sort(computed Automatic Caching)
const filteredItems = computed(() => {
 let result = items.value
 
 // 1. Filter by search term
 if (searchQuery.value) {
 result = result.filter(item =>
 item.name.toLowerCase().includes(searchQuery.value.toLowerCase())
 )
 }
 
 // 2. Filter by Category
 if (selectedCategory.value !== 'all') {
 result = result.filter(item => item.category === selectedCategory.value)
 }
 
 // 3. Sort
 result = [...result].sort((a, b) => {
 if (sortBy.value === 'price') return a.price - b.price
 if (sortBy.value === 'name') return a.name.localeCompare(b.name)
 return 0
 })
 
 return result
})

(2) ترقيم الصفحات

JS
const currentPage = ref(1)
const pageSize = ref(10)

// Data after pagination
const paginatedItems = computed(() => {
 const start = (currentPage.value - 1) * pageSize.value
 return filteredItems.value.slice(start, start + pageSize.value)
})

// Total Number of Pages
const totalPages = computed(() =>
 Math.ceil(filteredItems.value.length / pageSize.value)
)


8. مثال كامل: قائمة المنتجات الديناميكية

▶ مثال: 1. 5 طرق لاستخدام v-if/v-show

VUE
<template>
 <!-- 1. v-if:Conditional Rendering(Not here DOM) -->
 <p v-if="show">v-if</p>
 
 <!-- 2. v-show:display none(Always there DOM) -->
 <p v-show="show">v-show</p>
 
 <!-- 3. v-else-if:Chained Conditions -->
 <p v-if="type === 'A'">A</p>
 <p v-else-if="type === 'B'">B</p>
 <p v-else>C</p>
 
 <!-- 4. v-if + template:Multi-element -->
 <template v-if="isAdmin">
 <h1>Admin</h1>
 <button>Edit</button>
 </template>
 
 <!-- 5. v-if vs v-show Performance Comparison -->
 <div v-if="occasionally">Switch Occasionally</div>
 <div v-show="frequently">Frequent switching(Not recommended for use in combination with `<transition>`,v-if That's the only way)</div>
</template>
▶ جرّب الكود

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

VUE
<template>
 <!-- 1. Array -->
 <li v-for="item in items" :key="item.id">{{ item.name }}</li>
 
 <!-- 2. Array + Index -->
 <li v-for="(item, i) in items" :key="item.id">
 {{ i + 1 }}. {{ item.name }}
 </li>
 
 <!-- 3. Object -->
 <li v-for="(value, key) in user" :key="key">
 {{ key }}: {{ value }}
 </li>
 
 <!-- 4. Numbers -->
 <span v-for="n in 5" :key="n">{{ n }}</span>
 
 <!-- 5. String -->
 <span v-for="char in 'Hello'" :key="char">{{ char }}</span>
</template>
▶ جرّب الكود

▶ مثال: 3. مقارنة بين 5 طرق لاستخدام :key

VUE
<template>
 <!-- 1. The Only One ID(Best) -->
 <li v-for="user in users" :key="user.id">{{ user.name }}</li>
 
 <!-- 2. Unique Field -->
 <li v-for="user in users" :key="user.email">{{ user.name }}</li>
 
 <!-- 3. Composite key -->
 <li v-for="post in posts" :key="`${post.userId}-${post.id}`">
 {{ post.title }}
 </li>
 
 <!-- 4. Use index (Second choice) -->
 <li v-for="(item, i) in items" :key="i">{{ item.name }}</li>
 
 <!-- 5. ❌ random()(Never, under any circumstances) -->
 <li v-for="item in items" :key="Math.random()">{{ item.name }}</li>
</template>
▶ جرّب الكود

▶ مثال: 4. مثال كامل على تصفية القوائم + الفرز + تقسيم الصفحات

VUE 📖 للعرض فقط
<template>
 <div>
 <!-- Search box -->
 <input v-model="searchQuery" placeholder="Search...">
 
 <!-- Filter by Category -->
 <select v-model="selectedCategory">
 <option value="all">All</option>
 <option value="phone">Phone</option>
 <option value="laptop">Laptop</option>
 </select>
 
 <!-- Sort -->
 <select v-model="sortBy">
 <option value="price">Price</option>
 <option value="name">Name</option>
 </select>
 
 <!-- List -->
 <ul>
 <li v-for="item in paginatedItems" :key="item.id">
 {{ item.name }} - ${{ item.price }}
 </li>
 </ul>
 
 <!-- Pagination -->
 <button :disabled="currentPage === 1" @click="currentPage--">
 Previous
 </button>
 <span>{{ currentPage }} / {{ totalPages }}</span>
 <button :disabled="currentPage === totalPages" @click="currentPage++">
 Next
 </button>
 </div>
</template>

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

const item = ref([
 { id: 1, name: 'iPhone', price: 999, category: 'phone' },
 { id: 2, name: 'MacBook', price: 2499, category: 'laptop' },
 { id: 3, name: 'iPad', price: 599, category: 'tablet' }
])

const searchQuery = ref('')
const selectedCategory = ref('all')
const sortBy = ref('price')
const currentPage = ref(1)
const pageSize = 10

const filteredItems = computed(() => {
 let result = item.value
 if (searchQuery.value) {
 result = result.filter(i => i.name.includes(searchQuery.value))
 }
 if (selectedCategory.value !== 'all') {
 result = result.filter(i => i.category === selectedCategory.value)
 }
 return [...result].sort((a, b) => {
 if (sortBy.value === 'price') return a.price - b.price
 return a.name.localeCompare(b.name)
 })
})

const paginatedItems = computed(() => {
 const start = (currentPage.value - 1) * pageSize
 return filteredItems.value.slice(start, start + pageSize)
})

const totalPages = computed(() =>
 Math.ceil(filteredItems.value.length / pageSize)
)
</script>
59 سطر من الكود المنطقي (تجاوز الحد 40, للعرض فقط)

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

الخطأ الأعراض الحل
لا شيء :key عدم توافق القائمة، ضعف الأداء إضافة :key="item.id"
استخدام v-for و v-if معًا الالتباس بشأن أولوية v-if التغليف باستخدام template أو استخدام computed
استخدام «index» كمفتاح عدم التوافق أثناء الفرز استخدام معرّف فريد
لا يدعم v-show <transition> لا يمكن تحريكه استخدم v-if بدلاً من ذلك + <transition>
القائمة كبيرة جدًا (أكثر من 100,000) تتجمد الصفحة استخدم vue-virtual-scroller للتمرير الافتراضي

▶ مثال: 6. أولوية v-if و v-for

VUE
<!-- In Vue 3, v-if has higher priority than v-for (Vue 2 is the opposite) -->
<ul>
 <!-- Vue 3: First determine v-if, then v-for -->
 <li v-for="user in users" v-if="user.isActive" :key="user.id">
 {{ user.name }}
 </li>
 <!-- ✅ But Vue officially recommends using template to separate -->
 
 <!-- ❌ Incorrect wording(Not recommended) -->
 <li v-for="user in users" v-if="shouldShowUsers(user)" :key="user.id">
 {{ user.name }}
 </li>
 
 <!-- ✅ Recommendations:computed Filter -->
 <li v-for="user in activeUsers" :key="user.id">
 {{ user.name }}
 </li>
</template>
▶ جرّب الكود

❓ أسئلة شائعة

س كيف أختار بين v-if و v-show؟
ج استخدم v-if للتبديل بين الحين والآخر (لتوفير الموارد في مرحلة العرض الأولي)، واستخدم v-show للتبديل المتكرر (لتجنب إزالة بنية DOM وإعادة بنائها بشكل متكرر). استخدم v-if لحالات تسجيل الدخول/تسجيل الخروج، واستخدم v-show للتبديل بين علامات التبويب.
س هل :key مطلوب مع v-for؟
ج نوصي بشدة باستخدام :key لتجنب مشاكل الأداء وعدم تطابق حالات المكونات. يُفضل استخدام معرّف فريد (item.id)، يليه index؛ ولا تستخدم random() أبدًا.
س ما هي الأولوية عند استخدام v-if و v-for معًا؟
ج في Vue 3، يكون لـ v-if الأسبقية على v-for (على عكس Vue 2). ومع ذلك، فإن التوصية الرسمية هي تجنب استخدامهما معًا؛ وبدلاً من ذلك، يجب فصلهما باستخدام template أو التصفية باستخدام computed.
س ما الغرض من عنصر template؟
ج عنصر template هو عنصر غلاف منطقي في Vue لا يتم عرضه في DOM. ويُستخدم لتجنب ظهور عناصر div غير الضرورية عندما يتضمن v-if أو v-for عناصر متعددة.
س ماذا يمكنني أن أفعل إذا كان أداء القائمة ضعيفًا؟
ج 3 تحسينات: (1) أضف :key؛ (2) استخدم computed لتخزين النتائج المؤقتة في cache لتصفية/فرزها؛ (3) بالنسبة للقوائم الكبيرة (100,000+)، استخدم vue-virtual-scroller للتمرير الافتراضي لعرض المنطقة المرئية فقط.
س هل يمكن الوصول إلى المفاتيح والقيم عند تكرار كائن باستخدام v-for؟
ج نعم. v-for="(value, key, index) in obj"، ترتيب المعلمات: القيمة، المفتاح، الفهرس.
س كيف يمكنني عرض رسالة تنبيه في status عدم وجود بيانات؟
ج استخدم مزيجًا من v-if و v-else: <div v-if="item.length">Column </div><div v-else> Data</div>.
س كيف يمكنني تمييز عنصر محدد في قائمة؟
ج أضف activeIndex إلى كل عنصر: @click="activeIndex = item.id" :classe="{ active: activeIndex === item.id }".

📖 ملخص


📝 تمارين

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

    استخدم v-if/v-else للتبديل بين حالتي تسجيل الدخول وتسجيل الخروج:

    • تم تسجيل الدخول: يعرض اسم المستخدم وزر «تسجيل الخروج»
    • لم يتم تسجيل الدخول: يعرض عبارة «يرجى تسجيل الدخول» ونموذج تسجيل الدخول
    • استخدم «موديلو» لتجميع عناصر متعددة
  2. مسائل متقدمة (مستوى الصعوبة: ⭐⭐)

    تنفيذ قائمة المهام باستخدام v-for:

    • 3 حالات: الكل / قيد التنفيذ / مكتمل (يمكنك التبديل بينها باستخدام الأزرار الثلاثة)
    • تعرض القائمة المهام مع الstatus المقابلة لها
    • يحتوي كل عنصر على زرين هما «إكمال» و«حذف»
    • تظهر العبارة «غير مكتمل: N عنصر» في الأسفل
  3. مسألة التحدي (مستوى الصعوبة: ⭐⭐⭐)

    تنفيذ نظام متكامل لتصفية المنتجات وفرزها وتقسيمها إلى صفحات (5 ملفات):

    1. بيانات المنتج: 30 سجلًا، تشمل الاسم والسعر والفئة وتاريخ الإنشاء
    2. البحث: إجراء بحث تقريبي حسب الاسم
    3. التصفية حسب الفئة: 5 فئات (الكل/الهاتف/الكمبيوتر المحمول/الجهاز اللوحي/سماعات الرأس)
    4. الترتيب حسب: السعر (تصاعدي/تنازلي)، الاسم، الأحدث
    5. ترقيم الصفحات: 10 عناصر في كل صفحة، مع التنقل باستخدام أرقام الصفحات
    6. الأداء: تخزين النتائج المحسوبة والمصفاة/المرتبة في ذاكرة التخزين المؤقت
    7. تحسين القوائم الكبيرة: 1,000 عنصر اختبار لضمان الأداء السلس
Web-Tutorial.com

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

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

100%