>  기사  >  웹 프론트엔드  >  javascript data_javascript 기술의 양방향 바인딩을 쉽게 구현

javascript data_javascript 기술의 양방향 바인딩을 쉽게 구현

WBOY
WBOY원래의
2016-05-16 15:32:411329검색

양방향 데이터 바인딩은 객체의 속성이 변경되면 해당 UI도 동시에 변경될 수 있으며 그 반대의 경우도 가능하다는 의미입니다. 즉, name 속성이 있는 사용자 개체가 있는 경우 user.name에 새 값을 설정할 때마다 UI에 새 값이 표시됩니다. 마찬가지로 UI에 사용자 이름에 대한 입력 상자가 포함된 경우 새 값을 입력하면 사용자 개체의 이름 속성이 그에 따라 변경됩니다.

Ember.js, Angular.js 또는 KnockoutJS와 같은 많은 인기 있는 자바스크립트 프레임워크는 양방향 데이터 바인딩을 주요 기능 중 하나로 홍보합니다. 이는 처음부터 이를 구현하는 것이 어렵다는 의미도 아니며, 이 기능이 필요할 때 이러한 프레임워크를 사용하는 것이 유일한 옵션이라는 의미도 아닙니다. 내부의 기본 아이디어는 실제로 매우 기본적이며 구현은 다음 세 가지로 요약될 수 있습니다.

  • 어떤 UI 요소가 어떤 속성에 바인딩되어 있는지 확인하는 방법이 필요합니다.
  • 속성 및 UI의 변화를 모니터링해야 합니다
  • 바인딩된 모든 객체와 UI 요소에 변경 사항을 전파해야 합니다.

이러한 목표를 달성하는 방법은 여러 가지가 있지만 간단하고 효율적인 방법은 게시-구독자 패턴을 통해 구현하는 것입니다. 방법은 간단합니다. 사용자 정의된 데이터 속성을 HTML 코드에 바인딩해야 하는 속성으로 사용할 수 있습니다. 함께 바인딩된 모든 JavaScript 개체와 DOM 요소는 이 게시-구독 개체를 구독합니다. Javascript 객체나 HTML 입력 요소에서 변경 사항을 감지할 때마다 이벤트 프록시를 게시-구독 객체에 전달한 다음 바인딩된 객체와 요소에서 발생하는 모든 변경 사항을 전달하고 이를 통해 전달합니다.

jQuery로 구현한 간단한 예제

JQuery를 통해 위에서 논의한 내용을 구현하는 것은 매우 간단하고 간단합니다. 인기 있는 라이브러리인 jQuery를 사용하면 DOM 이벤트를 쉽게 구독하고 게시할 수 있으며 이벤트를 사용자 정의할 수도 있기 때문입니다.

function DataBinder(object_id){
  // Use a jQuery object as simple PubSub
  var pubSub=jQuery({});

  // We expect a `data` element specifying the binding
  // in the form:data-bind-<object_id>="<property_name>"
  var data_attr="bind-"+object_id,
    message=object_id+":change";

  // Listen to chagne events on elements with data-binding attribute and proxy
  // then to the PubSub, so that the change is "broadcasted" to all connected objects
  jQuery(document).on("change","[data-]"+data_attr+"]",function(eve){
    var $input=jQuery(this);

    pubSub.trigger(message,[$input.data(data_attr),$input.val()]);
  });

  // PubSub propagates chagnes to all bound elemetns,setting value of
  // input tags or HTML content of other tags
  pubSub.on(message,function(evt,prop_name,new_val){
    jQuery("[data-"+data_attr+"="+prop_name+"]").each(function(){
      var $bound=jQuery(this);

      if($bound.is("")){
        $bound.val(new_val);
      }else{
        $bound.html(new_val);
      }
    });
  });
  return pubSub;
}

JavaScript 객체의 경우 최소 사용자 데이터 모델 구현의 예는 다음과 같습니다.

function User(uid){
  var binder=new DataBinder(uid),
    
    user={
      attributes:{},
      // The attribute setter publish changes using the DataBinder PubSub
      set:function(attr_name,val){
        this.attributes[attr_name]=val;
        binder.trigger(uid+":change",[attr_name,val,this]);
      },

      get:function(attr_name){
        return this.attributes[attr_name];
      },
    
      _binder:binder
    };

  // Subscribe to PubSub
  binder.on(uid+":change",function(evt,attr_name,new_val,initiator){
    if(initiator!==user){
      user.set(attr_name,new_val);
    }
  });

  return user;
}

이제 객체의 속성을 UI에 바인딩할 때마다 해당 HTML 요소에 적절한 데이터 속성을 설정하기만 하면 됩니다.

// javascript 
var user=new User(123);
user.set("name","Wolfgang");

// html
<input type="number" data-bind-123="name" />

입력 상자의 값 변경 사항은 자동으로 사용자 이름 속성에 매핑되며 그 반대의 경우도 마찬가지입니다. 이제 끝났습니다!

jQuery가 필요하지 않은 구현

요즘 대부분의 프로젝트는 일반적으로 jQuery를 사용하므로 위의 예는 완전히 수용 가능합니다. 하지만 jQuery와 완전히 독립되어야 한다면 어떻게 될까요? 글쎄요, 실제로는 어렵지 않습니다(특히 IE8 이상만 지원하는 경우에는 더욱 그렇습니다). 마지막으로 게시-구독자 패턴을 통해 DOM 이벤트를 관찰하면 됩니다.

function DataBinder( object_id ) {
 // Create a simple PubSub object
 var pubSub = {
  callbacks: {},

  on: function( msg, callback ) {
   this.callbacks[ msg ] = this.callbacks[ msg ] || [];
   this.callbacks[ msg ].push( callback );
  },

  publish: function( msg ) {
   this.callbacks[ msg ] = this.callbacks[ msg ] || []
   for ( var i = 0, len = this.callbacks[ msg ].length; i < len; i++ ) {
    this.callbacks[ msg ][ i ].apply( this, arguments );
   }
  }
 },

 data_attr = "data-bind-" + object_id,
 message = object_id + ":change",

 changeHandler = function( evt ) {
  var target = evt.target || evt.srcElement, // IE8 compatibility
    prop_name = target.getAttribute( data_attr );

  if ( prop_name && prop_name !== "" ) {
   pubSub.publish( message, prop_name, target.value );
  }
 };

 // Listen to change events and proxy to PubSub
 if ( document.addEventListener ) {
  document.addEventListener( "change", changeHandler, false );
 } else {
  // IE8 uses attachEvent instead of addEventListener
  document.attachEvent( "onchange", changeHandler );
 }

 // PubSub propagates changes to all bound elements
 pubSub.on( message, function( evt, prop_name, new_val ) {
var elements = document.querySelectorAll("[" + data_attr + "=" + prop_name + "]"),
  tag_name;

for ( var i = 0, len = elements.length; i < len; i++ ) {
 tag_name = elements[ i ].tagName.toLowerCase();

 if ( tag_name === "input" || tag_name === "textarea" || tag_name === "select" ) {
  elements[ i ].value = new_val;
 } else {
  elements[ i ].innerHTML = new_val;
 }
}
 });

 return pubSub;
}

PubSub의 사용자 정의 게시 메소드로 대체될 수 있는 setter의 jQuery 트리거 메소드 호출을 제외하고 데이터 모델은 변경되지 않고 그대로 유지될 수 있습니다.

// In the model's setter:
function User( uid ) {
 // ...

 user = {
  // ...
  set: function( attr_name, val ) {
     this.attributes[ attr_name ] = val;
     // Use the `publish` method
     binder.publish( uid + ":change", attr_name, val, this );
  }
 }

 // ...
}

예제를 통해 설명했고, 유지 관리 가능한 순수 JavaScript로 100줄도 안 되는 내용으로 다시 한번 원하는 결과를 얻었습니다. JavaScript 데이터의 양방향 바인딩을 구현하는 데 모든 사람에게 도움이 되기를 바랍니다.

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.