如何让自定义对象侦听子自定义对象的事件?

时间:2012-06-11 04:21:35

标签: javascript jquery

我正在尝试用JavaScript创建一些自定义对象,我不确定我是否以正确的方式处理事情。

我有两个对象:' UserInterface'和' VolumeSlider'。直到片刻之前,这两个对象是独立的,但通过方法耦合。我决定UserInterface而不应该“#In;一个VolumeSlider。

所以:

UserInterface = {
    _volumeSlider: null,

    initialize: function () {
        this._volumeSlider = VolumeSlider; //TODO: Should this be a new volumeSlider();
        this._volumeSlider.initialize();

        //I want to setup a listener for VolumeSlider's change-volume events here.
    }
}

VolumeSlider = {
    _volumeSlider: null,

    initialize: function () {
        this._volumeSlider = $('#VolumeSlider');
        var self = this;
        this._volumeSlider.slider({
            orientation: 'horizontal',
            max: 100,
            min: 0,
            value: 0,
            slide: function (e, ui) {
                self.passVolumeToPlayer(ui.value);
            },
            change: function (e, ui) {
                self.passVolumeToPlayer(ui.value);
            }
        });
    },

    passVolumeToPlayer: function (volume) {
        if (volume != 0)
            UserInterface.updateMuteButton(volume);
        else
            UserInterface.updateMuteButton('Muted');
    }
}

问题是双重的:

  • 这是创建我的对象和设置孩子的好方法吗?
  • 我希望UserInterface能够响应VolumeSlider._volumeSlider的更改和幻灯片事件,而不必明确告知。我该如何完成这项工作?

2 个答案:

答案 0 :(得分:1)

  

这是创建对象和设置孩子的好方法吗?

如果有效,那就“好吧”:) 但严肃地说,实际上有无数种方法可以设置类似的东西。很大程度上取决于您的需求。

但是,我会说,例如,如果需要超过1个滑块,那么您的代码将变得难以处理。


  

我希望UserInterface能够响应VolumeSlider._volumeSlider的更改和幻灯片事件,而不必明确告知。我怎样才能完成这个?

我可能只是跳过VolumeSlider对象。它不是构造函数(“类”),因此它是一次性使用并硬编码到#VolumeSlider元素。此外,从您的代码中,它并没有真正。似乎只是一个中间人。

这是另一种选择:

UserInterface = {
  initialize: function () {
    // Internal function to create a horizontal 0-100 slider
    // Takes a selector, and a function that will receive the
    // value of the slider
    function buildSlider(selector, callback) {
      var element = $(selector);
      var handler = function (event, ui) { callback(ui.value); };
      element.slider({
        orientation: 'horizontal',
        max:   100,
        min:   0,
        value: 0,
        slide:  handler,
        change: handler
      });
      return element;
    }

    // We probably want to bind the scope of setVolume, so use $.proxy
    this.volumeSlider = buildSlider("#VolumeSlider", $.proxy(this.setVolume, this));

    // Want more sliders? Just add them
    // this.speedSlider = buildSlider("#SpeedSlider", $.proxy(this.setSpeed, this));
    // this.balanceSlider = buildSlider("#BalanceSlider", $.proxy(this.setBalance, this)); 
    // etc...
  },

  setVolume: function (value) {
    if( value != 0 ) {
      // not muted
    } else {
      // muted
    }
  }
}

有了这个,您可以想象为您需要的任何目的创建X个滑块。并且没有单独的一次性VolumeSlider对象;所有内容都在UserInterface对象中处理。

当然,这本身可能不是最好的主意,但出于这个简单的目的,它没关系。但是,您可能希望将buildSlider提取到更通用的UIElements对象中。它可能包含buildSliderbuildButton等方法

或者,您可以使用“Unobtrusive JavaScript”,并拥有特殊的类名和data-属性,这些属性将声明元素在UI中的位置和位置。例如

<div id="volumeSlider" class="ui-element" data-role="slider" data-action="setVolume">...

可以使用$(".ui-element").each ...与所有其他UI元素一起找到,之后可以解析其属性以表示它应该被创建为名为“volumeSlider”的滑块,并且其幻灯片/更改事件应该调用{ {1}} ... 等等。

同样,有许多方法可以解决这个问题。

答案 1 :(得分:1)

我认为你的原始结构根本不会变得笨拙。 JavaScript的内置数据结构在这种情况下会有所帮助。

如果您需要多个音量滑块,只需将此位_volumeSlider: null,更改为_volumeSliders: [],

如果您需要参考滑块,请将_volumeSliders初始化为dict。然后通过_volumeSliders[selector]引用它们,你就得到了你的对象。

不是向上传递值的函数,而是向下发送对父实例的引用。然后你可以写parent.volume = value

根据经验,我严格遵循坚实,合乎逻辑的等级结构。永远不要改变您的架构,只需创建范围引用。在这种情况下,对父作用域的引用。我不会使用第一个回答者的方法,因为我可能不得不四处寻找正在创建的对象的来源。

第一个回答者有一些好主意。您可能会注意到某些重复的模式,例如:设置jQuery元素引用。我通常会等到我注意到这些重复的模式,然后DRY以抽象为例,例如像Flambino建议的基类,例如: UIElement