404 Not Found

404 Not Found


nginx

المكونات والتخطيطات

فريق Charlie يتكون من خمسة مطورين، وكل واحد يكتب المكونات بطريقة مختلفة—بعضهم يستوردها يدويًا، وآخرون يسجلونها عالميًا، ولا توجد اصطلاحات تسمية متسقة. لاحظت Alice أن الصفحة تحمّل الكثير من المكونات غير الضرورية، مما يبطئ تحميل الشاشة الأولى. أراد Bob استخدام تخطيط مختلف للوحة الإدارة لكنه لم يعرف كيف يبدل إليه.

1. ما ستتعلمه


2. قصة حقيقية عن فريق

(1) نقطة الألم: إدارة مكونات فوضوية

فريق Charlie المكون من خمسة أفراد يعملون بمعزل: Alice تستورد كل مكون يدويًا، Bob يستخدم التسجيل العام مما يضخم حجم الحزمة، والزميل الجديد لا يستطيع معرفة أسماء المكونات. هناك ثلاث طرق مختلفة للإشارة إلى مكون ProductCard واحد عبر ملفات مختلفة.

(2) حل الاستيراد التلقائي في Nuxt 3

يقوم Nuxt 3 بمسح مجلد components/ تلقائيًا، وتوليد أسماء المكونات وفقًا للقواعد، وضمان إشارة الجميع إليها بطريقة متسقة:

VUE
<!-- لا حاجة للاستيراد، فقط استخدمه -->
<ProductCard :product="item" />

(3) الفوائد: توحيد + تقليل الحجم

وحّد الفريق طريقة الإشارة للمكونات؛ بادئة "Lazy" تضمن تحميل المكونات المرئية فقط على الشاشة الأولى، مما قلل حجم JavaScript للشاشة الأولى في MegaShop بنسبة 40%.


3. الاستيراد التلقائي للمكونات

(1) مسح المجلدات واصطلاحات التسمية

100%
graph TB
    A[components/] --> B[Root level]
    A --> C[Sub-directory]
    A --> D[Nested directory]
    B --> E[ProductCard.vue → ProductCard]
    C --> F[product/Card.vue → ProductCard ①]
    D --> G[shop/product/Card.vue → ShopProductCard]
    style G fill:#ffe,stroke:#f90
⚠️ ملاحظة: ① بعد إعداد pathPrefix: false، يصبح product/Card.vue → Card مما قد يؤدي لتعارض في التسمية. نوصي بالاحتفاظ بالبادئة الافتراضية.

(2) مقارنة اصطلاحات التسمية

مسار الملف اسم المكون الافتراضي pathPrefix: false
components/AppHeader.vue AppHeader AppHeader
components/product/Card.vue ProductCard Card
components/shop/ProductCard.vue ShopProductCard ProductCard
components/admin/user/Table.vue AdminUserTable Table

(1) ▶ مثال: الاستيراد التلقائي للمكونات

VUE
<!-- components/ProductCard.vue -->
<template>
  <div class="product-card">
    <img :src="product.image" :alt="product.name" />
    <h3>{{ product.name }}</h3>
    <p>${{ product.price }} USD</p>
    <button @click="$emit('add-to-cart', product)">Add to Cart</button>
  </div>
</template>

<script setup lang="ts">
interface Product {
  id: number
  name: string
  price: number
  image: string
}

defineProps<{ product: Product }>()
defineEmits<{ 'add-to-cart': [product: Product] }>()
</script>

الناتج:

TEXT
// Execution Successful

(2) ▶ مثال: استخدام المكون المستورد تلقائيًا على الصفحة

VUE
<!-- pages/products/index.vue -->
<template>
  <div>
    <h1>All Products</h1>
    <div class="grid">
      <!-- ProductCard مستورد تلقائيًا -->
      <ProductCard
        v-for="p in products"
        :key="p.id"
        :product="p"
        @add-to-cart="handleAdd"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
const { data: products } = await useFetch('/api/products')
function handleAdd(product: any) {
  console.log('Added:', product.name)
}
</script>

الناتج:

TEXT
// Execution Successful

4. نظام التخطيطات Layouts

(1) كيف يعمل التخطيط

100%
graph TB
    A[app.vue] --> B[NuxtLayout]
    B --> C{Current Layout}
    C -->|default| D[layouts/default.vue]
    C -->|sidebar| E[layouts/sidebar.vue]
    D --> F[NuxtPage - Page Content]
    E --> F

(2) العلاقة بين app.vue والتخطيط

VUE
<!-- app.vue - المكون الجذري مع دعم التخطيط -->
<template>
  <NuxtLayout>
    <NuxtPage />
  </NuxtLayout>
</template>

(1) ▶ مثال: التخطيط الافتراضي

VUE
<!-- layouts/default.vue -->
<template>
  <div class="layout-default">
    <AppHeader />
    <main class="content">
      <!-- محتوى الصفحة يُعرض هنا -->
      <slot />
    </main>
    <AppFooter />
  </div>
</template>

الناتج:

TEXT
// Execution Successful

(2) ▶ مثال: تخطيط الشريط الجانبي

VUE
<!-- layouts/sidebar.vue -->
<template>
  <div class="layout-sidebar">
    <AppHeader />
    <div class="main-wrapper">
      <aside class="sidebar">
        <nav>
          <NuxtLink to="/admin">Dashboard</NuxtLink>
          <NuxtLink to="/admin/products">Products</NuxtLink>
          <NuxtLink to="/admin/orders">Orders</NuxtLink>
        </nav>
      </aside>
      <main class="content">
        <slot />
      </main>
    </div>
  </div>
</template>

الناتج:

TEXT
// Execution Successful

(3) ▶ مثال: تبديل تخطيط الصفحة

VUE
<!-- pages/admin/index.vue -->
<template>
  <div>
    <h1>Admin Dashboard</h1>
    <p>Welcome, Bob</p>
  </div>
</template>

<script setup lang="ts">
// التبديل إلى تخطيط الشريط الجانبي لهذه الصفحة
definePageMeta({
  layout: 'sidebar'
})
</script>

الناتج:

TEXT
// Execution Successful

(3) مقارنة التخطيط مقابل المسارات المتداخلة

البُعد التخطيط المسارات المتداخلة
موقع التعريف layouts/*.vue pages/parent.vue
فتحة المحتوى slot NuxtPage
طريقة التبديل definePageMeta تلقائي (التسلسل الهرمي للتوجيه)
استرجاع البيانات غير مستحسن كل واحد يحصل على ما يحتاجه
حالات الاستخدام تخطيط الصفحة العام واجهة مستخدم مشتركة عبر مستويات التوجيه

5. التحميل الكسول للمكونات

(1) آلية التحميل الكسول

يسجل Nuxt 3 تلقائيًا نسخة "Lazy" من كل مكون، حيث يُحمل الكود فقط عند تصيير المكون لأول مرة.

(1) ▶ مثال: التحميل الكسول ببادئة Lazy

VUE
<template>
  <div>
    <!-- تحميل فوري - مضمّن في الحزمة الأولية -->
    <AppHeader />

    <!-- تحميل كسول - تقسيم الكود، يُحمل عند أول تصيير -->
    <LazyProductCard
      v-for="p in products"
      :key="p.id"
      :product="p"
    />

    <!-- Lazy مع v-if - يُحمل فقط عندما يكون الشرط صحيحًا -->
    <LazyProductReviewModal
      v-if="showReviewModal"
      :product-id="selectedProductId"
      @close="showReviewModal = false"
    />
  </div>
</template>

الناتج:

TEXT
// Execution Successful

(2) ▶ مثال: تحميل غير متزامن مع Suspense

VUE
<template>
  <div>
    <Suspense>
      <template #default>
        <LazyHeavyChart :data="chartData" />
      </template>
      <template #fallback>
        <div class="loading">Loading chart...</div>
      </template>
    </Suspense>
  </div>
</template>

الناتج:

TEXT
// Execution Successful

(2) مقارنة استراتيجيات التحميل الكسول

الاستراتيجية التنفيذ توقيت التحميل السيناريوهات المناسبة
تحميل فوري ProductCard عند تحميل الصفحة المكونات الأساسية على الشاشة الأولى
بادئة Lazy LazyProductCard عند أول تصيير المكونات أسفل الطية
v-if + Lazy LazyModal v-if عندما يكون الشرط صحيحًا نوافذ منبثقة/أدراج
Suspense تغليف Suspense عندما تكون العملية غير المتزامنة جاهزة حالة "تحميل" مطلوبة

6. أفضل الممارسات لـ Props و Emits

(1) ▶ مثال: Props و Emits آمنة النوع

VUE
<!-- components/ProductCard.vue -->
<script setup lang="ts">
interface Product {
  id: number
  name: string
  price: number
  image: string
  inStock: boolean
}

// Props آمنة النوع مع قيم افتراضية
const props = withDefaults(
  defineProps<{
    product: Product
    showStock?: boolean
    currency?: string
  }>(),
  {
    showStock: true,
    currency: 'USD'
  }
)

// Emits آمنة النوع
const emit = defineEmits<{
  'add-to-cart': [product: Product]
  'toggle-wishlist': [productId: number]
}>()
</script>

<template>
  <div class="card">
    <img :src="product.image" :alt="product.name" />
    <h3>{{ product.name }}</h3>
    <p>{{ product.price }} {{ currency }}</p>
    <p v-if="showStock">
      {{ product.inStock ? 'In Stock' : 'Out of Stock' }}
    </p>
    <button @click="emit('add-to-cart', product)">Add to Cart</button>
    <button @click="emit('toggle-wishlist', product.id)">Wishlist</button>
  </div>
</template>

الناتج:

TEXT
// Execution Successful

7. مثال شامل: نظام مكونات تخطيط MegaShop

VUE
<!-- components/AppHeader.vue -->
<template>
  <header class="app-header">
    <NuxtLink to="/" class="logo">MegaShop</NuxtLink>
    <nav>
      <NuxtLink to="/products">Products</NuxtLink>
      <NuxtLink to="/categories">Categories</NuxtLink>
    </nav>
    <div class="user-area">
      <NuxtLink to="/cart">Cart ({{ cartCount }})</NuxtLink>
      <NuxtLink v-if="isLoggedIn" to="/admin">Admin</NuxtLink>
      <NuxtLink v-else to="/login">Sign In</NuxtLink>
    </div>
  </header>
</template>

<script setup lang="ts">
const cart = useState<any[]>('cart', () => [])
const cartCount = computed(() => cart.value.length)
const isLoggedIn = useState('isLoggedIn', () => false)
</script>
VUE
<!-- components/AppFooter.vue -->
<template>
  <footer class="app-footer">
    <p>&copy; 2026 MegaShop. All rights reserved.</p>
    <nav>
      <NuxtLink to="/about">About</NuxtLink>
      <NuxtLink to="/contact">Contact</NuxtLink>
      <NuxtLink to="/privacy">Privacy Policy</NuxtLink>
    </nav>
  </footer>
</template>
VUE
<!-- layouts/default.vue -->
<template>
  <div class="layout-default">
    <AppHeader />
    <main>
      <slot />
    </main>
    <AppFooter />
  </div>
</template>

❓ أسئلة شائعة

س لماذا لا يُستورد مكوني تلقائيًا؟
ج تحقق مما إذا كان الملف في مجلد components/، وما إذا كان اسم الملف يبدأ بحرف كبير، وما إذا كان المسار مستثنى من إعداد components في nuxt.config.ts. حاول إعادة تشغيل خادم التطوير.
س هل تؤدي بادئة Lazy إلى تأخير تصيير المكون؟
ج لا. Lazy تؤخر فقط تحميل كود JavaScript الخاص بالمكون؛ بمجرد تصيير المكون يعمل بشكل طبيعي. إنها تقوم بتقسيم الكود، وليس تأخير التصيير.
س هل يمكن للتخطيط استرجاع البيانات؟
ج تقنيًا نعم، لكن لا يُوصى بذلك. التخطيط هو إطار واجهة مستخدم؛ استرجاع البيانات يجب أن يتم داخل الصفحة أو Composable. التخطيط مسؤول فقط عن هيكل التخطيط.
س هل يمكن لصفحة واحدة استخدام تخطيطات متعددة؟
ج لا. كل صفحة يمكنها تحديد تخطيط واحد فقط باستخدام definePageMeta. إذا كنت تحتاج تخطيطات مختلفة لأقسام مختلفة، حقق ذلك بدمج المكونات.
س هل يجب أن يكون definePageMeta في المستوى الأعلى من script setup؟
ج نعم. definePageMeta هو ماكرو مترجم ويجب استدعاؤه مباشرة في المستوى الأعلى من script setup؛ لا يمكن وضعه داخل عبارات شرطية أو دوال.
س هل يؤثر وضع المكونات في مجلد فرعي عميق جدًا تحت components/ على الأداء؟
ج لا يؤثر على أداء وقت التشغيل، لأن Nuxt 3 يجمع فقط المكونات المستخدمة فعليًا. لكن التسلسل الهرمي العميق للمجلدات يزيد من تعقيد التسمية؛ نوصي بتحديده بمستويين كحد أقصى.

📖ملخص


📝تمارين

  1. تمرين أساسي (الصعوبة: ⭐): أنشئ مكوني AppHeader و AppFooter واستخدمهما في التخطيط الافتراضي.
  2. تمرين متقدم (الصعوبة: ⭐⭐): أنشئ تخطيط شريط جانبي وبدّل بين التخطيطين على صفحة الإدارة باستخدام definePageMeta. قارن نتائج التخطيطين.
  3. تحدٍ (الصعوبة: ⭐⭐⭐): استخدم بادئة Lazy و v-if لتنفيذ مكون نافذة منبثقة لتفاصيل المنتج يُحمل فقط عند النقر، واستخدم Suspense لعرض حالة التحميل.

---|

Web-Tutorial.com

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

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

100%