手写JS双向数据绑定

<!DOCTYPE html>
<html>
	<head>
		<script>
			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,

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

				if ( prop_name && prop_name !== "" ) {
				  pubSub.publish( object_id + ":uichange", 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(  object_id + ":datachange", function( evt, prop_name, new_val ) {
				alert('ui me');
				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;
			}

			// In the model's setter:
			function User( uid ) {
			  var binder = new DataBinder( uid ),

			  user = {
				attributes: {},

				// The attribute setter publish changes using the DataBinder PubSub
				set: function( attr_name, val, caller ) {
				  this.attributes[ attr_name ] = val;
				  // Use the `publish` method
				  if(caller != this) {
					binder.publish( uid + ":datachange", attr_name, val );
				  }
				},

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

				_binder: binder
			  };

			  // Subscribe to the PubSub
			  binder.on( uid + ":uichange", function( evt, attr_name, new_val ) {
				alert('set me');
				user.set( attr_name, new_val, user );
			  });

			  return user;
			}
		</script>
	</head>
	<body>
	<input type="text" data-bind-123="name" />
	<input type="button" οnclick="myclick();" />
	</body>
	<script>
		var user = new User( 123 );
		user.set( "name", "Wolfgang" );

		function myclick() {
			alert(user.get("name"));
			user.set( "name", "Wolfgang" );
		}
	</script>
</html>


jquery版本

<!DOCTYPE html>
<html>
	<head>
		<script src="jquery.js"></script>
		<script>
			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;

			  // Listen to change events on elements with the data-binding attribute and proxy
			  // them to the PubSub, so that the change is "broadcasted" to all connected objects
			  jQuery( document ).on( "change", "[data-" + data_attr + "]", function( evt ) {
			    var $input = jQuery( this );
				pubSub.trigger( object_id + ":uichange", [ $input.data( data_attr ), $input.val() ] );
			  });

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

				  if ( $bound.is("input, textarea, select") ) {
					$bound.val( new_val );
				  } else {
					$bound.html( new_val );
				  }
				});
			  });

			  return pubSub;
			}

			// In the model's setter:
			function User( uid ) {
			  var binder = new DataBinder( uid );

			  user = {
				attributes: {},

				// The attribute setter publish changes using the DataBinder PubSub
				set: function( attr_name, val, caller ) {
				  this.attributes[ attr_name ] = val;
				  if(caller != this) {
					binder.trigger( uid + ":datachange", [ attr_name, val ] );
				  }
				},

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

				_binder: binder
			  };

			  // Subscribe to the PubSub
			  binder.on( uid + ":uichange", function( evt, attr_name, new_val ) {
				user.set( attr_name, new_val, user );
			  });

			  return user;
			}
		</script>
	</head>
	<body>
	<input type="text" data-bind-123="name" />
	<input type="button" οnclick="myclick();" />
	</body>
	<script>
		var user = new User( 123 );
		user.set( "name", "Wolfgang" );

		function myclick() {
			alert(user.get("name"));
			user.set( "name", "Wolfgang" );
		}
	</script>
</html>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值