هل من الممكن الاستماع إلى التغييرات التي تطرأ على سمات الكائن في JavaScript؟

StackOverflow https://stackoverflow.com/questions/240592

  •  04-07-2019
  •  | 
  •  

سؤال

أنا أعمل على واجهة ويب معقدة تم إنشاؤها في الغالب باستخدام JavaScript.إنه في الأساس شكل واحد كبير (جدًا) به العديد من الأقسام.يتم إنشاء كل قسم بناءً على خيارات من أجزاء أخرى من النموذج.كلما تغيرت هذه الخيارات، تتم الإشارة إلى القيم الجديدة في كائن نوع "التسجيل" ويتم إعادة ملء الأقسام الأخرى وفقًا لذلك.

إن وجود مستمعي الأحداث في العديد من حقول النماذج بدأ في إبطاء الأمور، كما أن تحديث النموذج بالكامل لكل تغيير سيكون ثقيلًا/بطيئًا للغاية بالنسبة للمستخدم.

أتساءل عما إذا كان من الممكن إضافة مستمعين إلى سمات كائن التسجيل بدلاً من عناصر النموذج لتسريع الأمور قليلاً؟وإذا كان الأمر كذلك، هل يمكنك تقديم/توجيهي إلى بعض نماذج التعليمات البرمجية؟

مزيد من المعلومات:

  • يعد هذا مكونًا إضافيًا لـ jQuery، لذا فإن أي وظيفة يمكنني البناء عليها من تلك المكتبة ستكون مفيدة ولكنها ليست ضرورية.
  • يستخدم مستخدمونا IE6/7 وSafari وFF2/3، لذا إذا كان ذلك ممكنًا ولكن للمتصفحات "الحديثة" فقط، فسأضطر إلى إيجاد حل مختلف.
هل كانت مفيدة؟

المحلول 2

شكرا لرجال التعليقات.لقد ذهبت مع ما يلي:

var EntriesRegistry = (function(){

    var instance = null;

    function __constructor() {

        var
            self = this,
            observations = {};

        this.set = function(n,v)
        {
            self[n] = v;

            if( observations[n] )
                for( var i=0; i < observations[n].length; i++ )
                    observations[n][i].apply(null, [v, n]);

        }

        this.get = function(n)
        {
            return self[n];
        }

        this.observe = function(n,f)
        {

            if(observations[n] == undefined)
                observations[n] = [];

            observations[n].push(f);
        }

    }

    return new function(){
        this.getInstance = function(){
            if (instance == null)
            {
                instance = new __constructor();
                instance.constructor = null;
            }
            return instance;
        }
    }
})();

var entries = EntriesRegistry.getInstance();

var test = function(v){ alert(v); };

entries.set('bob', 'meh');

entries.get('bob');

entries.observe('seth', test);

entries.set('seth', 'dave');

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

وهذا يعمل بشكل جيد بالنسبة لي حتى الآن ...هل يمكنكم يا رفاق رؤية أي مشاكل في هذا؟

نصائح أخرى

بقدر ما أعرف، لا توجد أحداث تم إطلاقها على تغييرات سمة الكائن (تحرير:باستثناء، على ما يبدو، ل Object.watch).

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

على سبيل المثال (برنامج jQuery الخاص بي صدئ، اعذرني لاستخدام Prototype بدلاً من ذلك، ولكنني متأكد من أنك ستتمكن من تعديله بسهولة):

$(form).observe('change', function(e) {
    // To identify changed field, in Proto use e.element()
    // but I think in jQuery it's e.target (as it should be)
});

يمكنك أيضًا التقاط input و keyup و paste الأحداث إذا كنت تريد إطلاقها على حقول النص قبل أن تفقد التركيز.الحل الخاص بي لهذا عادة هو:

  1. المتصفحات المعتمدة على Gecko/Webkit: يراقب input على ال form.
  2. أيضًا في المتصفحات المستندة إلى Webkit: يراقب keyup و paste الأحداث على textareaق (لا يطلقون النار input على textareaس لسبب ما).
  3. أي: يراقب keyup و paste على ال form
  4. يراقب change على ال form (هذا يشتعل selectس).
  5. ل keyup و paste الأحداث، قارن القيمة الحالية للحقل بالقيمة الافتراضية (ما كانت قيمته عند تحميل الصفحة) من خلال مقارنة قيمة حقل النص value لها defaultValue

يحرر:فيما يلي رمز المثال الذي قمت بتطويره لمنع إرسال النموذج غير المعدل وما شابه:

ما هي أفضل طريقة لتتبع التغييرات في النموذج عبر جافا سكريبت؟

يمكنك إرفاق مستمع بحاوية (النص أو النموذج) ثم استخدام معلمة الحدث للتفاعل مع التغيير.يمكنك الحصول على كل مزايا المستمع ولكن عليك فقط إرفاق واحدة للحاوية بدلاً من واحدة لكل عنصر.

$('body').change(function(event){
    /* do whatever you want with event.target here */
    console.debug(event.target); /* assuming firebug */
 });

يحتوي الحدث.target على العنصر الذي تم النقر عليه.

سايتبوينت لديه شرح لطيف هنا لتفويض الحدث:

يعد تفويض أحداث JavaScript أسلوبًا بسيطًا يمكنك من خلاله إضافة معالج حدث واحد إلى عنصر أصل لتجنب الاضطرار إلى إضافة معالجات أحداث إلى عناصر فرعية متعددة.

دعم المتصفحات التي تعمل بمحركات موزيلا Object.watch, ، لكنني لست على علم بوجود مكافئ متوافق مع المتصفحات المتعددة.

هل قمت بإعداد ملف تعريف للصفحة باستخدام Firebug للحصول على فكرة عن سبب البطء بالضبط، أم أن "الكثير من معالجات الأحداث" مجرد تخمين؟

تعديل صغير على الإجابة السابقة:من خلال نقل التعليمات البرمجية التي يمكن ملاحظتها إلى كائن ما، يمكن للمرء إنشاء تجريد منه واستخدامه لتوسيع كائنات أخرى باستخدام طريقة تمديد jQuery.

ObservableProperties = {
    events : {},
    on : function(type, f)
    {
        if(!this.events[type]) this.events[type] = [];
        this.events[type].push({
            action: f,
            type: type,
            target: this
        });
    },
    trigger : function(type)
    {
        if (this.events[type]!==undefined)
        {
            for(var e = 0, imax = this.events[type].length ; e < imax ; ++e)
            {
                this.events[type][e].action(this.events[type][e]);
            }
        }
    },
    removeEventListener : function(type, f)
    {
        if(this.events[type])
        {
            for(var e = 0, imax = this.events[type].length ; e < imax ; ++e)
            {
                if(this.events[type][e].action == f)
                    this.events[type].splice(e, 1);
            }
        }
    }
};
Object.freeze(ObservableProperties);

var SomeBusinessObject = function (){
    self = $.extend(true,{},ObservableProperties);
    self.someAttr = 1000
    self.someMethod = function(){
        // some code
    }
    return self;
}

انظر الكمان: https://jsfiddle.net/v2mcwpw7/3/

مسج هو مجرد مدهش.على الرغم من أنه يمكنك إلقاء نظرة على ASP.NET AJAX Preview.

بعض الميزات هي مجرد ملفات .js، ولا تعتمد على .NET.قد تجد أن تنفيذ نمط المراقب مفيد.

var o = { foo: "Change this string" };

Sys.Observer.observe(o);

o.add_propertyChanged(function(sender, args) {
    var name = args.get_propertyName();
    alert("Property '" + name + "' was changed to '" + sender[name] + "'.");
});

o.setValue("foo", "New string value.");

كما أن قوالب جانب العميل جاهزة للاستخدام في بعض السيناريوهات المثيرة للاهتمام.

ملاحظة أخيرة، هذا متوافق تمامًا مع jQuery (وليست مشكلة مع $)

الروابط: الصفحة الرئيسية, النسخة التي أستخدمها حاليا

كنت أبحث عن نفس الشيء وأجبت على سؤالك.لم تلبي أي من الإجابات احتياجاتي لذلك توصلت إلى هذا الحل الذي أود مشاركته:

var ObservedObject = function(){
    this.customAttribute = 0
    this.events = {}
    // your code...
}
ObservedObject.prototype.changeAttribute = function(v){
     this.customAttribute = v
     // your code...
     this.dispatchEvent('myEvent')
}
ObservedObject.prototype.addEventListener = function(type, f){
    if(!this.events[type]) this.events[type] = []
    this.events[type].push({
        action: f,
        type: type,
        target: this
    })
}
ObservedObject.prototype.dispatchEvent = function(type){
    for(var e = 0; e < this.events[type].length; ++e){
        this.events[type][e].action(this.events[type][e])
    }
}
ObservedObject.prototype.removeEventListener = function(type, f){
    if(this.events[type]) {
        for(var e = 0; e < this.events[type].length; ++e){
            if(this.events[type][e].action == f)
                this.events[type].splice(e, 1)
        }
    }
}

var myObj = new ObservedObject()

myObj.addEventListener('myEvent', function(e){// your code...})

إنه تبسيط لـ DOM Events API ويعمل بشكل جيد!هنا أكثر اكتمالا مثال

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top