Skip to content

الخاصيات المحسوبة

مثال بسيط

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

js
export default {
  data() {
    return {
      author: {
        name: 'John Doe',
        books: [
          'Vue 2 - Advanced Guide',
          'Vue 3 - Basic Guide',
          'Vue 4 - The Mystery'
        ]
      }
    }
  }
}
js
const author = reactive({
  name: 'John Doe',
  books: [
    'Vue 2 - Advanced Guide',
    'Vue 3 - Basic Guide',
    'Vue 4 - The Mystery'
  ]
})

و نريد عرض رسائل مختلفة بناءً على author (المؤلف) إذا كان لديه كتب أو لا:

template
<p>Has published books:</p>
<span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span>

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

لهذا السبب، في المعالجة المعقدة التي تتضمن بيانات تفاعلية متداخلة، يُوصى باستخدام خاصية محسوبة. هذا المثال السابق مع إعادة تصميمه بهاته الخاصية:

js
export default {
  data() {
    return {
      author: {
        name: 'John Doe',
        books: [
          'Vue 2 - Advanced Guide',
          'Vue 3 - Basic Guide',
          'Vue 4 - The Mystery'
        ]
      }
    }
  },
  computed: {
    //  خاصية محسوبة مُحصلة
    publishedBooksMessage() {
    // `this` يشير إلى  نسخة المكون
      return this.author.books.length > 0 ? 'نعم' : 'لا'
  }
}
template
<p>هل نشر كتبا؟</p>
<span>{{ publishedBooksMessage }}</span>

اختبرها في حقل التجارب

هنا صرحنا بخاصية محسوبة مسماة publishedBooksMessage.

جرب تغيير قيمة books في البيانات و سترى كيف تتغير publishedBooksMessage وفقا لذلك.

يمكنك ربط الخصائص المحسوبة كبيانات في القوالب مثل أي خاصية عادية. يعرف Vue أن this.publishedBooksMessage يعتمد على this.author.books، لذلك سيقوم بتحديث أي ربط يعتمد على this.publishedBooksMessage عند تغيير this.author.books.

الق نظرة على: إضافة النوع إلى الخصائص المحسوبة

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

const author = reactive({
  name: 'John Doe',
  books: [
    'Vue 2 - Advanced Guide',
    'Vue 3 - Basic Guide',
    'Vue 4 - The Mystery'
  ]
})

//مرجع خاصية محسوبة 
const publishedBooksMessage = computed(() => {
  return author.books.length > 0 ? 'نعم' : 'لا'
})
</script>

<template>
  <p>هل نشر كتبا؟</p>
  <span>{{ publishedBooksMessage }}</span>
</template>

اختبرها في حقل التجارب

هنا صرحنا بخاصية محسوبة مسماة publishedBooksMessage. تتوقع الدالة ()computed أن تتلقى دالة محصلة، ويتم إرجاع قيمة ref محسوب. مثل الـrefs العادية، يمكنك الوصول إلى النتيجة المحسوبة باستخدام publishedBooksMessage.value. تتم إزالة المراجع المحسوبة تلقائيًا في القوالب لذلك يمكنك الإشارة إليها دون value. في تعبيرات القالب.

خاصية محسوبة تتبع تلقائيًا إعتمادياتها التفاعلية. يعرف Vue أن حساب publishedBooksMessage يعتمد على author.books، لذلك سيقوم بتحديث أي ربط يعتمد على publishedBooksMessage عند تغيير author.books.

الق نظرة على: إضافة النوع إلى الخاصيات المحسوبة

تخزين بالخاصيات المحسوبة مقابل التوابع

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

template
<p>{{ calculateBooksMessage() }}</p>
js
// داخل المكون
methods: {
  calculateBooksMessage() {
    return this.author.books.length > 0 ? 'Yes' : 'No'
  }
}
js
// داخل المكون
function calculateBooksMessage() {
  return author.books.length > 0 ? 'Yes' : 'No'
}

بدلا من خاصية محسوبة، يمكننا تعريف نفس الدالة كتابعة. من أجل الحصول على النتيجة النهائية، فإن كلا الطريقتين تفيان بنفس الغرض. ومع ذلك، فإن الفرق هو أن الخاصيات المحسوبة مخزنة بناءً على إعتمادياتها التفاعلية. ستقوم خاصية محسوبة بإعادة التقييم فقط عندما تتغير بعض إعتمادياتها التفاعلية. هذا يعني أنه بمجرد عدم تغير author.books، فإن الوصول المتعدد إلى publishedBooksMessage سيعيد النتيجة المحسوبة مسبقًا بدون الحاجة إلى تشغيل الدالة المحصلة مرة أخرى.

هذا يعني أيضا أن الخاصية المحسوبة التالية لن تَتحيَّن أبدا، لأن ()Date.now ليست إعتمادية تفاعلية:

js
computed: {
  now() {
    return Date.now()
  }
}
js
const now = computed(() => Date.now())

بالمقارنة، استدعاء تابع سيقوم بتشغيل الدالة دائمًا عندما يحدث إعادة التصيير.

لماذا نحتاج إلى التخزين؟ تصور أنه لدينا خاصية محسوبة مُكْلِفة مسماة list، والتي تتطلب المرور عبر جميع عناصر مصفوفة كبيرة والقيام بالكثير من الحسابات. ثم قد نملك خاصيات محسوبة أخرى تعتمد على list بدورها. بدون التخزين، سنقوم بتشغيل الدالة المحصلة على list عدة مرات أكثر من الضروري! في حالات لا تريد التخزين، استدع تابع بدلاً من ذلك.

الخاصيات المحسوبة القابلة للكتابة

الخاصيات المحسوبة غير قابلة للتعيين افتراضيًا. إذا حاولت تعيين قيمة جديدة لخاصية محسوبة، ستحصل على تحذير خلال وقت التشغيل. في الحالات النادرة التي تحتاج إلى خاصية محسوبة "قابلة للكتابة"، يمكنك إنشاء واحدة من خلال توفير الدالتين المُحصِّلة و المعيّنة:

js
export default {
  data() {
    return {
      firstName: 'John',
      lastName: 'Doe'
    }
  },
  computed: {
    fullName: {
      // مُحصلة
      get() {
        return this.firstName + ' ' + this.lastName
      },
      // معيّنة
      set(newValue) {
        // ملاحظة: استخدمنا هنا صيغة التعيين عن طريق التفكيك.
        [this.firstName, this.lastName] = newValue.split(' ')
      }
    }
  }
}

الآن عندما تقوم بتشغيل 'محمد عبيدي' = this.fullName سيتم تشغيل المعيّن وسيتم بالتالي تحديث this.firstName و this.lastName.

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

const firstName = ref('John')
const lastName = ref('Doe')

const fullName = computed({
  // مُحصلة
  get() {
    return firstName.value + ' ' + lastName.value
  },
   // معيّنة
  set(newValue) {
  // ملاحظة: استخدمنا هنا صيغة التعيين عن طريق التفكيك.
    [firstName.value, lastName.value] = newValue.split(' ')
  }
})
</script>

الآن عندما تقوم بتشغيل 'محمد عبيدي' = this.fullName سيتم تشغيل المعيّن وسيتم بالتالي تحديث this.firstName و this.lastName.

الممارسات الجيّدة

يجب أن تكون الدوال المحصلة خالية من التأثيرات الجانبية

من المهم أن نتذكر أن الدوال المُحصلة يجب أن تقوم فقط بحسابات بحتة وبدون تأثيرات جانبية. على سبيل المثال، لا تقم بطلبات غير متزامنة أو تغيير الـDOM داخل دالة محصلة!. تصور أي خاصية محسوبة كوصف تصريحي لكيفية استخراج قيمة استنادًا إلى قيم أخرى - يجب أن تكون مسؤوليتها فقط حساب القيمة وإرجاعها. في وقت لاحق في هذا الدليل، سنتحدث عن كيفية تنفيذ التأثيرات الجانبية بالرد على تغييرات الحالة باستخدام الخاصيات المراقبة.

تجنب تعيين القيمة المحسوبة

القيمة المُرجعة من خاصية محسوبة هي حالة مشتقة. فكر فيها كلقطة مؤقتة - كلما تغيرت الحالة المصدرية، سيتم إنشاء لقطة جديدة. بديهيا لا يمكن تعديل لقطة، لذا يجب على أي قيمة محسوبة مُرجعة أن تُقرأ فقط وأن لا يتم تعديلها - بدلاً من ذلك، قم بتحديث الحالة المصدرية التي يعتمد عليها لتشغيل حسابات جديدة.

الخاصيات المحسوبة has loaded