1. 程式人生 > >記錄下用jquery實現雙向繫結的

記錄下用jquery實現雙向繫結的

首先複習下javascript物件的建立方法,一共有3種,分別是:

1,使用內建物件

例如,var obj= new String("aaa");

2,使用json

例如,var obj = {};

3,自定義物件

例如,function obj{this.name="aaa";this.text=function(){alert("aaa")}}

var obj= new obj();

然後把javascript物件轉換成jquery物件方法就是var jquery = $(obj);

雙向繫結用到了觀察者模式,首先介紹下什麼是觀察者模式

觀察者模式又叫做釋出訂閱模式,它定義了一種一對多的關係,讓多個觀察者物件同時監聽某一個主題物件,這個主題物件的狀態發生改變時就會通知所有觀察著物件。它是由兩類物件組成,主題和觀察者,主題負責釋出事件,同時觀察者通過訂閱這些事件來觀察該主體,釋出者和訂閱者是完全解耦的,彼此不知道對方的存在,兩者僅僅共享一個自定義事件的名稱。


理解觀察者模式:


JS傳統事件就是一個觀察者模式,之所以要有觀察者模式,是因為有時候和傳統事件無關的事件,比如:2個或者更多模組的直接通訊問題,比如說我有個index.html頁面,我有很多JS檔案,比如:


a.js: function a(){};    b.js: function b(){};  c.js  function c(){};  等等。後面還有許多這樣的JS, 那麼我要在index.html初始化這些函式的話,我需要這樣呼叫a();b();c()等等,也就是說頁面呼叫的時候 我要這樣呼叫,增加了依賴性,我要知道有多少個函式要這樣初始化呼叫,但是如果我們現在用觀察者模式就不需要知道有哪些訂閱者,比如一個模組(或者多個模組)訂閱了一個主題(或者事件),另一個模組釋出這個主題時候,訂閱這個主題模組就可以執行了,觀察者主要讓訂閱者與釋出者解耦,釋出者不需要知道哪些模組訂閱了這個主題,它只管釋出這個主題就可以了,同樣訂閱者也無需知道那個模組會發布這個主題,它只管訂閱這個主題就可以了。這樣2個模組(或更多模組)就實現了關聯了。而不需要和上面程式碼一樣,我要知道哪些模組要初始化,我要怎樣初始化。這只是一個簡單的列子解釋觀察者模式要使用在什麼地方,我也看過很多部落格關於這方面的資料,但是很多人寫部落格只是講了如何實現觀察者模式及觀察者模式的好處,並沒有講我們什麼時候該使用觀察者模式,所以我列舉了上面的列子,就是多個不同業務模組需要相互關聯的時候,可以使用觀察者模式。就好比requireJS,seaJS,KISSY解決依賴的問題一樣(比如A依賴於B,B依賴於C,只要一個解決入口檔案,其他都會非同步加載出來一樣)。也就是說各個模組之間的關聯性可以使用觀察者模式來設計。

這種模式有多種實現,比如jquery外掛 pub/sub

這裡我不用外掛直接用jquery的tirgger方法來發布,用on方法來訂閱

$(selector).trigger(event,[param1,param2,...])

jQueryObject.on( events [, selector ] [, data ], handler )

<%@ page language="java" import="java.util.*"
	contentType="text/html; charset=utf-8"%>
<html>
<script src="jquery.js"></script>
<script type="text/javascript">
	var jsonObj = {};
	//釋出訊息
	function doTest() {
		$(jsonObj).trigger("test", [ "aaa", "bbb" ]);
	}
	
	//程式初始化的時候就訂閱訊息
	$(jsonObj).on("test", function(e, para1, para2) {
		alert(para1)
	});
</script>
<body>
	<input type="button" onclick="doTest()" value="測試釋出訂閱模式">
</body>
</html>
OK,這個釋出訂閱模式明白了再看下面這個用jquery實現的雙向繫結的程式碼就會簡單一些了。

下面這段程式碼最後的button是用來測試修改model也會更改UI的。

<%@ page language="java" import="java.util.*"
	contentType="text/html; charset=utf-8"%>
<html>
<script src="jquery.js"></script>
<script type="text/javascript">
	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("input,textarea,select")) {
							$bound.val(new_val);
						} else {
							$bound.html(new_val);
						}
					});
		});
		return pubSub;
	}

	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;
	}

	var user = new User(123);
	user.set("name", "999");
	function setNewVal(val) {
		user.set("name", $("#newVal").val());
	}
</script>
<body>
	<h2>Hello World!</h2>

	<input type="text" data-bind-123="name" />
	<br />
	<br />
	<br />
	<input type="button" value="修改value的值 " onclick="setNewVal()">
	<input type="text" id="newVal" />
</body>
</html>

最後忘了說雙向繫結的概念了

雙向資料繫結指的是當物件的屬性發生變化時能夠同時改變對應的UI,反之亦然。換句話說,如果我們有一個user物件,這個物件有一個name屬性,無論何時你對user.name設定了一個新值,UI也會展示這個新的值。同樣的,如果UI包含一個用於資料使用者名稱字的輸入框,輸入一個新值也會導致user物件的name屬性發生相應的改變。

應用場景:

雙向資料繫結最經常的應用場景就是表單了,這樣當用戶在前端頁面完成輸入後,不用任何操作,我們就已經拿到了使用者的資料存放到資料模型中了。