أساسيات التفاعلية
تفضيلات واجهة البرمجة
هاته الصفحة والعديد من المحاور الأخرى في المرجع تحتوي على محتوى مختلف بواجهة الخيارات و الواجهة التركيبية. تفضيلك الحاليل هو الواجهة التركيبية. يمكنك التبديل بين نمطي الواجهتين باستخدام مفاتيح التبديل "تفضيلات واجهة البرمجة" في أعلى جانب الشريط الجانبي الأيسر.
التصريح بحالة تفاعلية
ref()
في الواجهة التركيبية، الطريقة الموصى بها للتصريح بالحالة التفاعلية هي استخدام دالة ()ref
:
js
import { ref } from 'vue'
const count = ref(0)
الدالة ()ref
تأخذ الوسيط وتعيده مغلفا داخل كائن تفاعلي مع خاصية value.
:
js
const count = ref(0)
console.log(count) // { value: 0 }
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
اطلع أيضا على : كيفية إضافة النوع إلى ref
من أجل الوصول إلى المرجع التفاعلي في قالب المكون، قم بتصريحه وإرجاعه من دالة ()setup
للمكون:
js
import { ref } from 'vue'
export default {
// `setup` هو خطاف خاص مخصص للواجهة التركيبية
setup() {
const count = ref(0)
// عرض المرجع للقالب
return {
count
}
}
}
template
<div>{{ count }}</div>
تجدر الملاحظة أننا لم نحتاج إلى إضافة value.
عند استخدام المرجع التفاعلي في قالب المكون. بشكل ملائم، يفك المرجع تلقائيًا عند استخدامه داخل القوالب (مع بعض التنبيهات).
يمكنك أيضًا تغيير المرجع مباشرة في معالجات الأحداث:
template
<button @click="count++">
{{ count }}
</button>
من أجل الشيفرة المعقدة، يمكننا التصريح يالدوال التي تغيّر المراجع في نفس النطاق وعرضها كتوابع إلى جانب الحالة:
js
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
function increment() {
// .value مطلوب في جافاسكريبت
count.value++
}
// لا تنسى عرض الدالة أيضًا.
return {
count,
increment
}
}
}
الدوال المعروضة يمكن استخدامها كمستمعات للأحداث:
template
<button @click="increment">
{{ count }}
</button>
هنا المثال المباشر على Codepen، بدون استخدام أي أدوات بناء.
<script setup>
عرض الحالة والتوابع يدويا من خلال ()setup
يمكن أن يكون مطولا. لحسن الحظ، يمكن تجنب ذلك عند استخدام المكونات أحادية الملف (SFCs). يمكننا تبسيط الاستخدام مع <script setup>
:
vue
<script setup>
import { ref } from 'vue'
const count = ref(0)
function increment() {
count.value++
}
</script>
<template>
<button @click="increment">
{{ count }}
</button>
</template>
استيرادات المستوى الأعلى، المتغيرات والدوال المعرفة في <script setup>
يمكن استخدامها تلقائيا في قالب نفس المكون. تخيل القالب كدالة JavaScript معرفة في نفس النطاق - لديها بشكل طبيعي الوصول إلى كل شيء معرف بجانبها.
ملاحظة
في بقية الدليل، سنستخدم بشكل أساسي صيغة المكونات أحادية الملف + <script setup>
في أمثلة الواجهة البرمجية التركيبية، حيث أن هذا هو الاستخدام الأكثر شيوعا لمطوري Vue.
إذا لم تكن تستخدم المكونات أحادية الملف، يمكنك استخدام الواجهة البرمجية التركيبية مع خيار ()setup
.
لماذ المراجع التفاعلية Refs؟
ربما تتساءل لماذا نحتاج إلى المراجع مع value.
بدلا من الاستخدام المباشر للمتغيرات العادية. لشرح ذلك، سنحتاج إلى مناقشة نظام التفاعلية في Vue بشكل موجز.
عند استخدام المرجع في قالب المكون، وتغيير قيمة المرجع لاحقا، يكتشف Vue تلقائيا التغيير ويحدث الـDOM وفقا لذلك. يتم ذلك بفضل نظام التفاعلية القائم على تتبع الاعتماديات. عندما يصير المكون للمرة الأولى، يقوم Vue بتتبع كل مرجع استخدم خلال التصيير. في وقت لاحق، عندما يتغير المرجع، سيؤدي ذلك إلى تشغيل إعادة التصيير للمكونات التي تتتبعه.
في Javascript القياسية، لا يوجد طريقة لكشف الوصول أو التغيير للمتغيرات العادية. ومع ذلك، يمكننا اعتراض عمليات الحصول والتعيين لخصائص الكائن باستخدام توابع الحصول والتعيين.
الخاصية value.
تعطي Vue الفرصة لكشف متى تم الوصول إلى المرجع أو تغييره. وراء الكواليس، تقوم Vue بتتبع في دالته المحصلة، وتقوم بالتشغيل في دالة التعيين. من الناحية المفهومية، يمكنك تخيل المرجع ككائن يبدو كالتالي:
js
// شيفرة وهمية، ليست تنفيذ فعلي
const myRef = {
_value: 0,
get value() {
track()
return this._value
},
set value(newValue) {
this._value = newValue
trigger()
}
}
خاصية أخرى جميلة للمراجع هي أنه على عكس المتغيرات العادية، يمكنك تمرير المراجع إلى الدوال مع الاحتفاظ بالوصول إلى أحدث قيمة و ربط التفاعلية. هذا مفيد بشكل خاص عند إعادة تنظيم الشيفرة المعقدة إلى شيفرة قابلة لإعادة الاستخدام.
نظام التفاعلية يناقش بتفاصيل أكثر في قسم التفاعلية بالتفصيل.
التفاعلية العميقة
المراجع يمكن أن تحمل أي نوع قيمة، بما في ذلك الكائنات المتداخلة بشكل عميق، المصفوفات، أو هياكل البيانات المدمجة في JavaScript مثل Map
.
المرجع يجعل قيمته تفاعلية بشكل عميق. هذا يعني أنه يمكنك توقع كشف التغييرات حتى عند تغيير الكائنات المتداخلة أو المصفوفات:
js
import { ref } from 'vue'
const obj = ref({
nested: { count: 0 },
arr: ['foo', 'bar']
})
function mutateDeeply() {
// هذه ستعمل كما هو متوقع
obj.value.nested.count++
obj.value.arr.push('baz')
}
القيم غير الأساسية تتحول إلى وسائط تفاعلية عبر ()reactive
، والتي ستناقش أدناه.
من الممكن أيضًا الاستغناء عن التفاعل العميق مع المراجع السطحية. بالنسبة للمراجع السطحية، يتم تتبع الوصول إلى value.
فقط من أجل التفاعلية. يمكن استخدام المراجع السطحية لتحسين الأداء عن طريق تجنب تكلفة مراقبة الكائنات الكبيرة، أو في الحالات التي تدار الحالة الداخلية بواسطة مكتبة خارجية.
للمزيد من القراءة:
توقيت تحديثات الـDOM
عندما تقوم بتغيير الحالة التفاعلية، يُحدَّث DOM تلقائيًا. ومع ذلك ، يجب أن يُذكر أن تحديثات DOM لا تُطبق بشكل متزامن. بدلاً من ذلك ، تُخزن Vue تحديثاتها في الذاكرة المؤقتة حتى تطبق في "النبضة الموالية" في دورة التحديث لضمان أن يحدث كل مكون مرة واحدة فقط بغض النظر عن عدد التغييرات في الحالة التي قمت بها.
لانتظار اكتمال تحديث DOM بعد تغيير الحالة ، يمكنك استخدام الواجهة البرمجية العامة ()nextTick :
js
import { nextTick } from 'vue'
async function increment() {
count.value++
await nextTick()
// الوصول إلى DOM المحدث
}
reactive()
هناك طريقة أخرى للتصريح بالحالة التفاعلية، مع الواجهة البرمجية ()reactive
. على عكس المرجع الذي يغلف القيمة الداخلية في كائن خاص، ()reactive
يجعل الكائن نفسه تفاعليا:
js
import { reactive } from 'vue'
const state = reactive({ count: 0 })
انظر أيضا: كيفية إضافة النوع إلى reactive
الاستخدام في القالب:
template
<button @click="state.count++">
{{ state.count }}
</button>
الكائنات التفاعلية هي وسائط JavaScript وتتصرف مثل الكائنات العادية. الفرق هو أن Vue قادرة على تتبع الوصول إلى خاصيات وتغييرات الكائن التفاعلي. إذا كنت ترغب في معرفة التفاصيل، سنشرح كيفية عمل نظام التفاعلية في Vue في قسم التفاعل بالتفصيل - لكننا نوصي بقراءته بعد إتمام الدليل الرئيسي.
الدالة ()reactive
تحوّل الكائن بشكل عميق: الكائنات المتداخلة تغلف أيضًا مع ()reactive
عند الوصول إليها. كما تستدعى من قبل ()ref
داخليا عندما تكون قيمة المرجع كائن. مشابهة للمراجع السطحية، هناك أيضا الواجهة البرمجية ()shallowReactive
للاستغناء عن التفاعل العميق.
الوسيط التفاعلي مقابل الأصلي
من المهم ملاحظة أن القيمة الراجعة من ()reactive
هي عبارة عن وسيط Proxy للكائن الأصلي ، وهو ليس مساويًا له :
js
const raw = {}
const proxy = reactive(raw)
// الوسيط ليس مساويًا للأصلي
console.log(proxy === raw) // false
فقط الوسيط هو المتفاعل - تغيير الكائن الأصلي لن يتسبب في تحديثه. لذلك ، أفضل ممارسة عند العمل مع نظام التفاعلية في Vue هي استخدام النسخ الوسيطة فقط من الحالات.
من أجل ضمان الوصول المستمر إلى الوسيط، استدعاء ()reactive
على نفس الكائن يعيد دائمًا نفس الوسيط ، و استدعاء ()reactive
على وسيط موجود يعيد أيضًا نفس الوسيط:
js
// استدعاء reactive() على نفس الكائن يعيد نفس الوسيط
console.log(reactive(raw) === proxy) // true
// استدعاء reactive() على وسيط موجود يعيد نفس الوسيط
console.log(reactive(proxy) === proxy) // true
تُطبق هذه القاعدة أيضًا على الكائنات المتداخلة. بسبب التفاعل العميق، تصبح الكائنات المتداخلة داخل كائن تفاعلي أيضًا عبارة عن وسائط:
js
const proxy = reactive({})
const raw = {}
proxy.nested = raw
console.log(proxy.nested === raw) // false
محدودية ()reactive
الواجهة البرمجية لـ()reactive
لها بعض المحدوديات:
أنواع قيم محدودة: يعمل فقط مع أنواع الكائنات (الكائنات والمصفوفات و أنواع المجموعات مثل
Map
وSet
). لا يمكن أن يحتوي على أنواع البيانات الأولية مثلstring
،number
أوboolean
.عدم القدرة على استبدال الكائن بأكمله بما أن تتبع التفاعل في Vue يعمل على مستوى الوصول إلى الخاصية أي تحديثه لابد أن يتم بواسطة خاصية، يجب أن نبقى دائمًا على نفس المرجع للكائن التفاعلي. وهذا يعني أننا لا يمكننا بسهولة "استبدال" كائن تفاعلي لأن الاتصال التفاعلي مع المرجع الأول قد فُقِد:
jslet state = reactive({ count: 0 }) // المرجع السابق ({ count: 0 }) لم يعد يتم تتبعه // (الاتصال التفاعلي قد فُقِد!) state = reactive({ count: 1 })
غير متوافق مع التفكيك: عندما نقوم بتفكيك خاصية نوع الكائن التفاعلي الأولي إلى متغيرات محلية، أو عندما نمرر هذه الخاصية إلى دالة، سنفقد الاتصال التفاعلي:
jsconst state = reactive({ count: 0 }) // count لم يعد متصلا بـ state.count عند التفكيك let { count } = state // لا يؤثر على الحالة الأصلية count++ // الدالة تستقبل رقم عادي ولن تكون // قادرة على تتبع التغييرات لـ state.count // يجب علينا تمرير الكائن بأكمله للحفاظ على التفاعلية callSomeFunction(state.count)
بسبب هذه المحدوديات، نوصي باستخدام ()ref
كواجهة برمجية أساسية للتصريح بالحالة التفاعلية.
تفاصيل إضافية حول فك ref
كخاصية لكائن تفاعلي (reactive)
يفك المرجع تلقائيًا عند الوصول إليه أو تغييره كخاصية لكائن تفاعلي. بعبارة أخرى، يتصرف كخاصية عادية:
js
const count = ref(0)
const state = reactive({
count
})
console.log(state.count) // 0
state.count = 1
console.log(count.value) // 1
إذا تم تعيين ref جديدة لخاصية مرتبطة بـref موجودة ، فسَتَسْبدل الـref القديمة:
js
const otherCount = ref(2)
state.count = otherCount
console.log(state.count) // 2
// ref الأصلية الآن غير متصلة بـ state.count
console.log(count.value) // 1
يحدث فك المرجع فقط عندما يضمن داخل كائن تفاعلي عميق. لا ينطبق عند الوصول إليه كخاصية لـ كائن تفاعلي سطحي.
التنبيه في المصفوفات والمجموعات
على عكس الكائنات التفاعلية، لا يوجد فك عند الوصول إلى المرجع كعنصر في مصفوفة تفاعلية أو نوع مجموعة مدمج مثل Map
:
js
const books = reactive([ref('Vue 3 Guide')])
// يجب إضافة .value
console.log(books[0].value)
const map = reactive(new Map([['count', ref(0)]]))
// يجب إضافة .value
console.log(map.get('count').value)
تنبيه عند الفك في قالب
فك المرجع في قوالب ينطبق فقط إذا كان المرجع خاصية في أعلى المستوى في سياق تصيير القالب.
في المثال أدناه، count
و object
هما خاصيتان في أعلى المستوى، ولكن object.id
ليس كذلك:
js
const count = ref(0)
const object = { id: ref(0) }
لذلك، هذا التعبير يعمل كما هو متوقع:
template
{{ count + 1 }}
...بينما هذا لا يعمل كما هو متوقع:
template
{{ object.id + 1 }}
النتيجة المصيرة ستكون 1[object Object]
لأن object.id
لم يفك عند تقييم التعبير ويظل كائن مرجع. لإصلاح هذا، يمكننا تفكيك id
إلى خاصية مستوى أعلى:
js
const { id } = object
template
{{ id + 1 }}
الآن النتيجة المصيرة ستكون 2
.
شيء آخر يجب ملاحظته هو أن المرجع يفك إذا كانت القيمة المقيّمة النهائية لتعبير نصي (أي علامة {{ }}
)، لذلك ستصير الشيفرة الآتية النتيجة 1
:
template
{{ object.id }}
هذه ميزة ملائمة للاقحام النصي ومكافئة لـ {{ object.id.value }}
.