Vue.js: الخصائص المحسوبة

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

الخصائص المحسوبة (computed) هي خصائص خاصة في Vue 3 تُعاد حسابها تلقائيًا استنادًا إلى البيانات التفاعلية. وتكمن قيمتها الأساسية في التخزين المؤقت — حيث لا تُعاد حسابها إلا عند تغير البيانات التي تعتمد عليها؛ وإلا فإنها تعيد ببساطة القيمة السابقة. ويُعد فهم الخصائص المحسوبة أمرًا أساسيًّا لكتابة تطبيقات Vue عالية الأداء.

تتمحور الخصائص المحسوبة حول ثلاث ميزات رئيسية: التتبع التلقائي للتبعيات + تخزين النتائج مؤقتًا + التفاعلية. سيساعدك هذا الدرس على إتقان حالات الاستخدام الخمس لهذه الخصائص وتجنب العقبات الثلاث المرتبطة بها.

1. ما ستتعلمه



2. مشكلة في الأداء تتعلق بالسعر الإجمالي لعربة التسوق

(1) المشكلة: يتم إعادة حساب 100 منتج مع كل نقرة

قامت أليس بإنشاء وظيفة حساب المجموع النهائي لعربة التسوق في لوحة إدارة موقع التجارة الإلكترونية الخاص بها:

JS
// ❌ The "Broken" Version: Use methods
function cartTotal(items) {
  console.log('Calculating...')  // Print on every call
  return items.reduce((sum, item) => sum + item.price * item.quantity, 0)
}
HTML
<template>
  <div>
    <p>Total: ${{ cartTotal(items) }}</p>
    <p>Tax: ${{ cartTotal(items) * 0.08 }}</p>
    <p>Grand Total: ${{ cartTotal(items) * 1.08 }}</p>
    <button @click="showDate = new Date()">Update Time</button>
  </div>
</template>

الأداء سيئ للغاية:

تُظهر أداة مراقبة الأداء ما يلي:

"يتم استدعاء دالة cartTotal 5,000 مرة عند كل تحميل للصفحة. 100 عنصر × 5,000 = 500,000 عملية حسابية لكل عنصر على حدة. تباطؤ لمدة 3 ثوانٍ."

(2) الحل المستند إلى الحسابات في Vue: التخزين المؤقت + تتبع التبعيات

JS
import { ref, computed } from 'vue'

const item = ref([
  { price: 100, quantity: 2 },
  { price: 50, quantity: 1 }
])

// ✅ computed:Rely solely on item,item If it hasn't changed, don't recalculate it.
const cartTotal = computed(() => {
  console.log('Calculating...')  // Only at item Print when changes occur
  return item.value.reduce((sum, item) => sum + item.price * item.quantity, 0)
})

// computed Auto-Processing 3 For use in: Count only 1 time
const tax = computed(() => cartTotal.value * 0.08)
const grandTotal = computed(() => cartTotal.value * 1.08)

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

بعد التحويل إلى الصيغة الحسابية:



3. الاستخدام الأساسي لوظيفة computed()

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

JS
import { ref, computed } from 'vue'

const count = ref(0)

// Basic Computational Properties
const doubleCount = computed(() => {
  return count.value * 2
})

// Abbreviation
const doubleCount = computed(() => count.value * 2)

// Usage
console.log(doubleCount.value)  // 0
count.value = 5
console.log(doubleCount.value)  // 10

(2) الاستخدام في القوالب

VUE
<template>
  <div>
    <p>Count: {{ count }}</p>
    <p>Double: {{ doubleCount }}</p>
    <button @click="count++">+1</button>
  </div>
</template>

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

const count = ref(0)
const doubleCount = computed(() => count.value * 2)
</script>

في القالب، {{ doubleCount }} ليس مطلوبًا .value (يتم تفريغه تلقائيًا).

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

100%
graph TB
    subgraph ComputedKey Features
        A[Automatic Dependency Tracking]
        B[Cache Results]
        C[Responsive]
        D[Lazy Evaluation]
        E[Chainable calls]
    end
    
    style A fill:#42b883,color:#fff
    style B fill:#42b883,color:#fff
    style C fill:#42b883,color:#fff
    style D fill:#42b883,color:#fff
    style E fill:#42b883,color:#fff
الميزة الوصف
التتبع التلقائي للتبعيات يكتشف تلقائيًا البيانات التفاعلية المستخدمة داخل أجسام الدوال
النتائج المخزنة مؤقتًا تُحسب عمليات الوصول المتعددة كعملية واحدة فقط إذا بقيت التبعيات دون تغيير
متجاوب يُعاد حسابه تلقائيًا عند تغير التبعيات
التقييم المتأخر لا يتم تقييمه ما لم يتم الوصول إليه (يوفر الأداء)
قابلة للتسلسل قد تعتمد القيمة المحسوبة على خصائص محسوبة أخرى


4. القيم المحسوبة مقابل الطرق: 5 اختلافات رئيسية

الجانب المحسوب الطرق
التخزين المؤقت ✅ لا تتم إعادة الحساب إذا بقيت التبعيات دون تغيير ❌ تتم إعادة الحساب عند كل استدعاء
متجاوب ✅ يتتبع التبعيات تلقائيًا ❌ لا يتتبع التبعيات (يتطلب تمرير المعلمات يدويًّا)
الوصول إلى القالب {{ doubleCount }} {{ doubleCount() }}
المعلمات ❌ غير مدعومة ✅ تقبل أي معلمات
حالات الاستخدام القيم المشتقة البسيطة المنطق المعقد، معالجة الأحداث

(4) 5 سيناريوهات للاختيار من بينها

السيناريو باستخدام القيم المحسوبة باستخدام الطرق
مضاعفة الرقم المعروض
حساب المبلغ الإجمالي لعربة التسوق
معالجة النقر على الزر
إرسال طلب API
تنسيق التاريخ (بدون تبعيات)
قائمة التصفية (حسب البيانات)
التحقق من صحة النموذج


5. Getter/Setter: الخصائص المحسوبة ثنائية الاتجاه

(1) بشكل افتراضي، لا يوجد سوى دالة الحصول

JS
const firstName = ref('Alice')
const lastName = ref('Smith')

// There is only one getter
const fullName = computed(() => `${firstName.value} ${lastName.value}`)

console.log(fullName.value)  // Alice Smith
// fullName.value = 'Bob Lee'  // ❌ Warning:Calculated properties are read-only.

(2) دالات الحصول + دالات التعيين الكاملة

JS
const firstName = ref('Alice')
const lastName = ref('Smith')

const fullName = computed({
  // Read:Put it together
  get() {
    return `${firstName.value} ${lastName.value}`
  },
  // Write:Unpack
  set(newValue) {
    const parts = newValue.split(' ')
    firstName.value = parts[0]
    lastName.value = parts[1] || ''
  }
})

// ✅ Read and write access is now available
fullName.value = 'Bob Lee'
console.log(firstName.value)  // Bob
console.log(lastName.value)   // Lee

(3) الربط ثنائي الاتجاه في القوالب

VUE
<template>
  <div>
    <input v-model="fullName">
    <p>First: {{ firstName }}</p>
    <p>Last: {{ lastName }}</p>
  </div>
</template>

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

const firstName = ref('Alice')
const lastName = ref('Smith')

const fullName = computed({
  get: () => `${firstName.value} ${lastName.value}`,
  set: (val) => {
    const parts = val.split(' ')
    firstName.value = parts[0]
    lastName.value = parts[1] || ''
  }
})
</script>


6. المكالمات المتسلسلة للخصائص المحسوبة

(1) حساب متداخل

JS
const items = ref([
  { price: 100, quantity: 2 },
  { price: 50, quantity: 3 }
])

// First Floor:Total Original Price
const subtotal = computed(() =>
  items.value.reduce((sum, item) => sum + item.price * item.quantity, 0)
)

// Second Floor: Tax (Based on subtotal)
const tax = computed(() => subtotal.value * 0.08)

// Third Floor: Discount (Based on subtotal)
const discount = computed(() => subtotal.value > 200 ? 20 : 0)

// Fourth Floor:Final Total Price
const total = computed(() => subtotal.value + tax.value - discount.value)

console.log(total.value)  // 350 * 1.08 - 20 = 358

(2) آلية cache محسوبة متسلسلة

100%
graph TB
    A[items change] --> B[subtotal Recalculate]
    B --> C[tax Recalculate]
    B --> D[discount Recalculate]
    C --> E[total Recalculate]
    D --> E
    
    style A fill:#42b883
    style B fill:#42b883
    style E fill:#42b883

لن يتم إعادة حساب سوى القيم المحسوبة التي تعتمد على السلسلة؛ أما القيم غير المستخدمة فلن يتم إعادة حسابها.



7. مثال كامل: السعر الإجمالي لعربة التسوق في موقع التجارة الإلكترونية

▶ مثال: 1. الحسابات الأساسية

VUE
<template>
  <div>
    <p>Subtotal: ${{ subtotal }}</p>
    <p>Tax (8%): ${{ tax }}</p>
    <p>Discount: -${{ discount }}</p>
    <p><strong>Total: ${{ total }}</strong></p>
  </div>
</template>

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

const items = ref([
  { name: 'iPhone', price: 999, quantity: 1 },
  { name: 'Case', price: 50, quantity: 2 }
])

const subtotal = computed(() =>
  items.value.reduce((sum, item) => sum + item.price * item.quantity, 0)
)

const tax = computed(() => subtotal.value * 0.08)
const discount = computed(() => subtotal.value > 1000 ? 50 : 0)
const total = computed(() => subtotal.value + tax.value - discount.value)
</script>
▶ جرّب الكود

▶ مثال: 2. دالات الاسترجاع + دالات التعيين

VUE
<template>
  <div>
    <input v-model="fullName" placeholder="First Last">
    <p>First: {{ firstName }}</p>
    <p>Last: {{ lastName }}</p>
  </div>
</template>

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

const firstName = ref('Alice')
const lastName = ref('Smith')

const fullName = computed({
  get: () => `${firstName.value} ${lastName.value}`,
  set: (val) => {
    const parts = val.split(' ')
    firstName.value = parts[0] || ''
    lastName.value = parts[1] || ''
  }
})
</script>
▶ جرّب الكود

▶ مثال: 3. استدعاءات السلسلة المحسوبة

JS
import { ref, computed } from 'vue'

const score = ref(85)

// First Floor:Base Score
const baseScore = computed(() => score.value)

// Second Floor:Bonus Points(Base Score × Difficulty Level)
const difficultyBonus = computed(() => {
  if (baseScore.value >= 90) return 10
  if (baseScore.value >= 80) return 5
  return 0
})

// Third Floor:Level
const grade = computed(() => {
  const total = baseScore.value + difficultyBonus.value
  if (total >= 95) return 'A+'
  if (total >= 90) return 'A'
  if (total >= 80) return 'B'
  return 'C'
})
▶ جرّب الكود

▶ مثال: 4. مقارنة بين القيم المحسوبة والأساليب

JS
// ❌ methods:Recalculate on every call
function getTotal() {
  console.log('Calculated!')  // If used multiple times in the template, it will be printed multiple times.
  return items.value.reduce((sum, i) => sum + i.price * i.quantity, 0)
}

// ✅ computed: Count only 1 time
const total = computed(() => {
  console.log('Calculated!')  // Print Only 1 time
  return items.value.reduce((sum, i) => sum + i.price * i.quantity, 0)
})
▶ جرّب الكود

▶ مثال: 5. خمسة سيناريوهات لمقارنة الأداء

المشهد عدد الطرق التي تم استدعاؤها عدد المكالمات المحسوبة
استُخدم مرة واحدة في القالب 1 1
استُخدم 3 مرات في القالب 3 1
استُخدم 10 مرات في القالب 10 1
يتم تحديث المكون الأصلي لكن العناصر تظل دون تغيير تم استدعاؤها لم تتم إعادة حسابها
تغييرات التبعيات الاسترجاع إعادة الحساب

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

الخطأ الأعراض الحل
استبدال «المُحسب» بـ«الأساليب» ضعف الأداء عند الاستخدام المتكرر التحول إلى «المُحسب»
تم تمرير المعلمات بشكل غير صحيح إلى computed خطأ لا يدعم computed المعلمات؛ استخدم methods بدلاً من ذلك
مُعيّن: اكتب كودك الخاص حلقة لا نهائية مُعيّن: قم بتعديل التبعية؛ لا تستخدم fullName.value = ...
التبعية الدائرية A→B→A حلقة لا نهائية إزالة إحدى التبعيات
منطق معقد مكتوب في الخصائص المحسوبة يصعب تصحيح الأخطاء قم باستخراجه إلى دالة؛ واجعل الخاصية المحسوبة تستدعي هذه الدالة


❓ أسئلة شائعة

س أيهما يجب أن أستخدم — computed أم methods؟
ج استخدم computed كلما أمكن ذلك (التخزين المؤقت + التتبع التلقائي). استخدم methods فقط في الحالات التالية: (1) عندما تحتاج إلى تمرير معلمات؛ (2) عندما لا تعتمد على البيانات التفاعلية؛ (3) لمعالجات الأحداث (@click، إلخ).
س هل يمكن لـ computed قبول معلمات؟
ج لا. لا يمكن لـ computed أن تحتوي إلا على 0 معلمة. إذا كنت بحاجة إلى تمرير معلمات، فاستخدم methods بدلاً من ذلك: getDouble(n) { return n * 2 }، أو اجعل computed تُرجع دالة: computed(() => (n) => n * 2).
س هل يمكن الوصول إلى computed من خارج setup؟
ج نعم. تُرجع computed كائن ref، والذي يمكن تمريره إلى مكونات أو دوال أخرى. ومع ذلك، للحفاظ على التفاعلية، يُنصح باستخدام computed كـ«مرجع مشتق».
س ما الفرق بين computed وwatch؟
ج computed هي «قيمة مشتقة» (حساب قيمة جديدة بناءً على البيانات)، بينما watch هي «مراقب» (تنفيذ الآثار الجانبية عند تغير البيانات). computed مناسب للحسابات البحتة، بينما watch مناسب لتقديم الطلبات، وتعيين الstatus، وما إلى ذلك.
س كيف يتفوق أداء computed على methods؟
ج التخزين المؤقت. يُنفذ methods الدالة عند كل استدعاء، بينما لا يُنفذ computed إلا عندما تتغير تبعياته. في القالب، يؤدي استخدام computed ثلاث مرات إلى عملية حسابية واحدة فقط؛ بينما يؤدي استخدام methods إلى ثلاث عمليات حسابية.
س كيف أكتب دالة تعيين (setter) بحيث لا تدخل في حلقة لا نهائية؟
ج في دالة التعيين، قم بتحديث تبعيات المتغير المحسوب (ref) فقط؛ ولا تقم بتعيين قيمة مباشرة للمتغير المحسوب نفسه. على سبيل المثال، يجب أن تقوم دالة التعيين الخاصة بـ fullName بتحديث firstName وlastName، وليس fullName.value = ....
س هل يمكن أن تكون computed غير متزامنة؟
ج لا. computed متزامنة؛ استخدم watch أو watchEffect للعمليات غير المتزامنة. إذا كنت بحاجة إلى «خصائص محسوبة غير متزامنة»، فاستخدم مزيجًا من data() { return { result: null } } وwatch + onMounted.

📖 ملخص


📝 تمارين

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

    اكتب خاصية محسوبة wordCount تحسب عدد الكلمات في نص ما (باستخدام split لتقسيم النص حسب المسافات).

    البيانات: const text = ref('Hello Vue 3 from Alice') يجب أن تكون النتيجة 4.

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

    اكتب معادلة لحساب إجمالي سلة التسوق تتضمن 3 خصائص محسوبة:

    • subtotal: مجموع السعر والكمية لجميع الأصناف
    • discount: وفر 10 عند الطلبات التي تبلغ قيمتها 100 أو أكثر؛ وفر 30 عند الطلبات التي تبلغ قيمتها 200 أو أكثر
    • total: المجموع الفرعي - الخصم
    • 3 قطع: آيفون 999 دولارًا × 1، غطاء 50 دولارًا × 2، شاحن 30 دولارًا × 1
  3. مسألة التحدي (مستوى الصعوبة: ⭐⭐⭐)

    تنفيذ «نظام إجمالي سلة التسوق» الكامل:

    1. 5 منتجات، كل منها مع الاسم والسعر والكمية
    2. المجموع الفرعي / الضريبة (8٪) / الخصم (20 عند شراء 200 أو أكثر) / المجموع — 4 قيم محسوبة
    3. استخدم دالات الاسترجاع والتعيين للخاصية المحسوبة fullName؛ وفي دالة التعيين، قم بتحديث firstName وlastName بناءً على المدخلات.
    4. اختبار تتبع التبعيات لخمس خصائص محسوبة (أي منها يتم إعادة حسابها بعد تعديل أي منتج)
    5. استخدم Mermaid لرسم مخطط التبعية للخصائص المحسوبة
Web-Tutorial.com

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

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

100%