نوفيل
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
دخولابدأ مجاناً
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
نوفيل

منصة تعليم البرمجة الأولى بالعربي. تعلم من الصفر حتى الاحتراف مع كورسات احترافية وتحديات ذكاء اصطناعي.

المنصة

  • الكورسات
  • التحديات
  • المقالات
  • الأدوات

الحساب

  • إنشاء حساب
  • تسجيل الدخول
  • لوحة التحكم
  • الملف الشخصي

روابط

  • سياسة الخصوصية
  • شروط الاستخدام
  • عن نوفيل
  • تواصل معنا

© 2026 نوفيل. جميع الحقوق محفوظة.

صُنع بـ في مصر

نوفيل
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
دخولابدأ مجاناً
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
AN

منهج Angular

دليل مرجعي شامل

كل اللغات
مدرسة البرمجة/منهج Angular /التعامل مع أحداث DOM وتدفقات البيانات المستمرة باستخدام

التعامل مع أحداث DOM وتدفقات البيانات المستمرة باستخدام

DOM EventsMemory ManagementfromEventContinuous StreamsEvent HandlingUser Interactions

جدول مرجعي سريع

1
طريقة التعامل مع الحدث (`Approach`)آلية التنفيذ والإدارةالمميزات والعيوب الهندسية
مستمعات DOM التقليدية (`addEventListener`)ربط مباشر بعنصر الشاشة وتحديث المتغيرات يدوياًتتطلب إزالة يدوية دقيقة عبر `removeEventListener` لتجنب تسريب الذاكرة
تدفقات RxJS عبر `fromEvent`تحويل الأحداث المستمرة إلى Observable تفاعلي متكاملتتيح الدمج الفوري مع مشغلات المعالجة مثل `debounceTime` و `switchMap` وإلغاء الاشتراك الآمن

الشرح

يُعتبر التعامل مع تفاعلات المستخدمين وأحداث المتصفح (مثل النقر، الكتابة، أو تحريك الفأرة) أحد أهم ركائز البرمجة التفاعلية. بدلاً من استخدام مستمعات الأحداث التقليدية التي قد تسبب تسريبات في الذاكرة، توفر RxJS دالة الإنشاء fromEvent لتحويل أي حدث DOM مباشر إلى تدفق بيانات مستمر (Continuous Stream) يمكن التحكم به ومعالجته بكل سلاسة.

تفصيل فلسفة وعمل أحداث DOM التدفقية

التعامل مع التدفقات اللانهائية (Infinite Streams):

أحداث DOM مثل النقرات أو الكتابة لا تنتهي تلقائياً (Never Complete)؛ ولذلك فإن إدارتها تتطلب التخلص من الاشتراك (Unsubscribe) عند تدمير المكون (OnDestroy) لمنع تراكم العمليات في الذاكرة.

الدمج مع المعالجات المتقدمة (Operator Chaining):

من خلال تحويل الحدث إلى تدفق عبر fromEvent، يمكنك تطبيق تقنيات تحسين الأداء مثل تأخير الاستجابة عند الكتابة (debounceTime) أو منع التكرار (distinctUntilChanged) بكل سهولة داخل الـ pipe.

أمثلة برمجية موسعة: التطبيق العملي للتعامل مع أحداث DOM

المثال الأول: التقاط أحداث النقر المستمرة على زر وتتبع عداد التفاعل (dom-click-stream.component.ts)

typescript
1import { Component, OnInit, OnDestroy, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
2import { CommonModule } from '@angular/common';
3import { fromEvent, Subscription } from 'rxjs';
4
5@Component({
6 selector: 'app-dom-click-stream',
7 standalone: true,
8 imports: [CommonModule],
9 template: `
10 <div class="dom-demo-card">
11 <h3>التعامل مع أحداث النقر عبر fromEvent</h3>
12 <button #actionBtn class="action-button">اضغط هنا لتوليد حدث تدفقي</button>
13 <p><strong>عدد مرات النقر المكتشفة:</strong> {{ clickCount }}</p>
14 </div>
15 `,
16 styles: [`
17 .dom-demo-card { background: #090d16; color: #fff; padding: 24px; border-radius: 12px; border: 1px solid #1e293b; margin-bottom: 16px; }
18 .action-button { background: #38bdf8; color: #090d16; border: none; padding: 10px 20px; font-weight: bold; border-radius: 6px; cursor: pointer; }
19 .action-button:hover { background: #0284c7; color: #fff; }
20 p { color: #94a3b8; margin-top: 12px; }
21 strong { color: #10b981; }
22 `]
23})
24export class DomClickStreamComponent implements AfterViewInit, OnDestroy {
25 clickCount: number = 0;
26 private clickSub!: Subscription;
27
28 @ViewChild('actionBtn') actionBtn!: ElementRef;
29
30 ngAfterViewInit(): void {
31 // تحويل حدث النقر على عنصر DOM إلى تدفق تفاعلي مستمر
32 this.clickSub = fromEvent(this.actionBtn.nativeElement, 'click').subscribe({
33 next: (event: any) => {
34 this.clickCount++;
35 console.log('تم رصد حدث النقر بنجاح:', event);
36 }
37 });
38 }
39
40 ngOnDestroy(): void {
41 // إيقاف الاستماع للتدفق لمنع تسريب الذاكرة عند مغادرة المكون
42 if (this.clickSub) {
43 this.clickSub.unsubscribe();
44 }
45 }
46}

المثال الثاني: مراقبة مدخلات الحقول النصية واستخراج قيم الكتابة الحية (dom-input-stream.component.ts)

typescript
1import { Component, OnInit, OnDestroy, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
2import { CommonModule } from '@angular/common';
3import { fromEvent, Subscription } from 'rxjs';
4import { map, debounceTime, distinctUntilChanged } from 'rxjs/operators';
5
6@Component({
7 selector: 'app-dom-input-stream',
8 standalone: true,
9 imports: [CommonModule],
10 template: `
11 <div class="dom-demo-card">
12 <h3>مراقبة مدخلات حقل البحث بشكل حي</h3>
13 <input #searchInput type="text" placeholder="اكتب للبحث الفوري..." class="search-input" />
14 <p><strong>النص المُعالج بعد التحسين:</strong> {{ typedValue }}</p>
15 </div>
16 `,
17 styles: [`
18 .dom-demo-card { background: #090d16; color: #fff; padding: 24px; border-radius: 12px; border: 1px solid #1e293b; }
19 .search-input { width: 100%; padding: 10px; background: #1e293b; border: 1px solid #334155; color: #fff; border-radius: 6px; margin-bottom: 12px; box-sizing: border-box; }
20 p { color: #94a3b8; }
21 strong { color: #38bdf8; }
22 `]
23})
24export class DomInputStreamComponent implements AfterViewInit, OnDestroy {
25 typedValue: string = '';
26 private inputSub!: Subscription;
27
28 @ViewChild('searchInput') searchInput!: ElementRef;
29
30 ngAfterViewInit(): void {
31 // إنشاء تدفق من حقل الإدخال وتحسينه عبر المشغلات
32 this.inputSub = fromEvent(this.searchInput.nativeElement, 'input').pipe(
33 map((event: any) => event.target.value), // استخراج القيمة النصية مباشرة
34 debounceTime(300), // تأخير الاستجابة 300 ميلي ثانية لتقليل الضغط
35 distinctUntilChanged() // تجاهل القيم المتكررة المتطابقة
36 ).subscribe({
37 next: (value) => {
38 this.typedValue = value;
39 console.log('قيمة البحث المعالجة:', value);
40 }
41 });
42 }
43
44 ngOnDestroy(): void {
45 if (this.inputSub) {
46 this.inputSub.unsubscribe();
47 }
48 }
49}

نصائح احترافية

  • —احرص دائماً على تطبيق مشغلات الأداء مثل debounceTime مع أحداث الكتابة السريعة عبر fromEvent!
  • —هذا يمنع إرسال طلبات متكررة وكثيفة غير مبررة إلى الخادم مع كل حرف يكتبه المستخدم، مما يحسّن كفاءة وأداء التطبيق بشكل ملحوظ.

الدرس السابق

إنشاء التدفقات يدوياً باستخدام دالة الإنشاء

الدرس التالي

تنقية وتحويل البيانات باستخدام مشغلات الأساسية مثل map و filter و tap

نوفيل

منصة تعليم البرمجة الأولى بالعربي. تعلم من الصفر حتى الاحتراف مع كورسات احترافية وتحديات ذكاء اصطناعي.

المنصة

  • الكورسات
  • التحديات
  • المقالات
  • الأدوات

الحساب

  • إنشاء حساب
  • تسجيل الدخول
  • لوحة التحكم
  • الملف الشخصي

روابط

  • سياسة الخصوصية
  • شروط الاستخدام
  • عن نوفيل
  • تواصل معنا

© 2026 نوفيل. جميع الحقوق محفوظة.

صُنع بـ في مصر