1. 程式人生 > >angularjs表單相關之封裝radio、select、filter

angularjs表單相關之封裝radio、select、filter

在這幾個月裡,一直一邊學習angular,一邊重新把我們公司的後臺重寫。想象確實是美好的,但是時間起來真是苦難重重,不過功夫不負有心人,終於寫出一點靠譜的東西,而且應用到實踐上,就一個字,爽!!以前費半天勁想寫一個介面,還得考慮這個,還得考慮那個,真是費死勁了。現在似乎問題迎刃而解了,當然,在用angular的前期還是要廢掉很多的腦力的,畢竟真的入門門檻有點高(主要對於我這種學渣來說,英語就是最大的障礙)。

好了,廢話不多說開始整。

一、為什麼要這幾個一起說?

因為我在建立統一的filter時,就發現,哦~~原來還可以這麼搞,確實省了不少程式碼。當然你要是處女座的話,我覺得你可以分開寫,只要注入就好了。反正對於我來說都是自己寫的指令,就暫時放在一起嘍。

書歸正題,首先這個地方我覺得還少了checkbox,但是目前沒有實踐,等實踐完了再把這塊內容補上。

先說說大體思路,我們首先為我們需要的列舉來建一個factory,然後用這個factory來指導自定義的radio,select ,filter。當然,這只是我的一點淺見。

好了,下面說幹就幹。

二、實踐部分(我覺的直接上程式碼比較容易,然後再講)

1. 最開始我們先建一個module(這個沒什麼好講的)

<span style="font-size:18px;">var allInput = angular.module('allInput', []);</span>
2. 新建一個我們需要的factory
<span style="font-size:18px;">allInput.factory('$status', function(){
<span style="white-space:pre">	</span>var status = {
<span style="white-space:pre">		</span>0: '稽核拒絕',
<span style="white-space:pre">		</span>1: '稽核通過',  //我故意省略2
<span style="white-space:pre">		</span>3: '未稽核',
<span style="white-space:pre">		</span>4: '重新提交稽核',
<span style="white-space:pre">		</span>'hehe': '已封禁' //如果後端的列舉是hehe或者什麼的我們應該也能應付
<span style="white-space:pre">	</span>};

<span style="white-space:pre">	</span>return status;
});</span>
<span style="font-size:18px;">
</span>
<span style="font-size:18px;">//這個地方是兩個控制元件都要用到的公共配置</span>
<span style="font-size:18px;"></span><pre name="code" class="javascript">allInput.factory('$defaultOption', function($status){
	return {
		status: {
			data: $status
		},
		//這個下面還可以填充好多類似於上面的東西
		removeDiff: function(a, b){
			//這塊的主要意思是b裡面有的東西就要替換a
			if(a == null){
				return b;
			}

			if(b == null){
				return a;
			}

			//如果都沒有空,就返回a配置
			for (i in a){
				if(i in b){
					a[i] = b[i];
				}
			}

			return a;
		}
	};
});

好了,解釋一下程式碼,就是建一個factory,然後將status這個陣列,用$status來表示,其實就是很簡單!!!前面的索引數字代表的是列舉值,後面代表的是含義,當然,我們也可以寫成英文或者什麼,並不影響什麼。比如說已封禁那個。中間的2是我故意省去的,為了大家看了可以更好的舉一反三(或許對於程式設計師這種高智商的動物並沒有什麼卵用,anyway)

後面這個地方是我又思考了一下,貼上在上面的,因為可以提出來共同使用

3. 新建一個filter

allInput.filter('status', function($status){
	return function(input){
		return input in $status ? $status[input] : '未知';
	}
});

好了,一個合理合法的filter就這麼建好了,是不是特別的開心?是不是特別的簡單,當然,我們也可以不用引入$status,我們只要把$status那一坨放在filter的回撥函式裡就可以啦,呵呵呵

4. 建一個統一的select控制元件

<span style="font-size:18px;">allInput.directive('selectInput', function($defaultOption){</span><span style="font-size:18px;">
	return {
		restrict: 'AE',
<span style="white-space:pre">		</span>replace: ture,
		scope: {
			ngType: '@',  //這個地方是為了說明這個控制元件到底要顯示哪個列舉(我們可能有多個列舉)
			myConfig: '='//這個地方可以傳入一些我們自定義的配置,這樣我們就可以不用侷限於他自己的type了			
		},
		//我這裡寫到controller純粹是因為他簡單,第二一點,我也沒有真正理解,為什麼放入link是最佳實踐
		//這裡的$selectOption 是我們要為了自定義的方法而用的,看到這裡不明白先不要著急
		controller: function($scope, $defaultOption){</span><span style="font-size:18px;">
			//這個地方是要把真實的值傳給option做渲染
			$scope.option = $defaultOption.removeDiff($defaultOption[$scope.ngType], $scope.myConfig);
		},
		templateUrl: 'select.html'
	};
});</span>
<span style="font-size:18px;">

//最後的最後再加一個模板,就完事兒了

allInput.run(function($templateCache){
	$templateCache.put('select.html',
		' \
		<select \
			ng-options = "key as value for (key, value) in option.data"> \
		</select> \
		'
	);
});</span>
<span style="font-size:18px;">引用例項 <select-input ng-type = "status"  ng-model = "xxx" /></span>

做到這個地方,基本上我們我們一個select 控制元件就完成了, 是不是特別的簡單,想一想,每次只要新增一個factory就可以用一行程式碼來建立一個下拉框。反正我覺得真的是大大提高了工作效率。

5. 建立一個統一的radio控制元件

<span style="font-size:18px;">// 這個要提前寫,寫這個控制元件的時候,我真的遇到了不少麻煩,所以只能進行一丟丟的dom操作,還希望哪個厲害的大哥可以指點我一下
//然後開始擼程式碼
allInput.directive('radioInput', function($defaultOption){
	return {
		restrict: 'AE',
		replace: true,
		scope: {
			ngType: '@',  //這倆跟上面一樣
			myConfig: '='
		},
		//這個地方因為是寫demo,我是犯個懶,用之前select的
		controller: function($scope, $defaultOption){
			$scope.option = $defaultOption.removeDiff($defaultOption[$scope.ngType], $scope.myConfig);
		},
		templateUrl: 'radio.html'
	};
});

//這裡也寫一個模板
allInput.run(function($templateCache){
	//這個地方是我最頭疼的,因為不能同步ng-model,所以我寫了一個指令來進行dom操作
	$templateCache.put('radio.html', 
		'<input ng-repeat = "(key, value) in option.data" radio-to-name type = "radio" value = "{{key}}" radio-value = "{{value}}">'
	);
});

//這個地方就是重點,我目前為止還不知道怎麼處理,所以只能寫一個dom來操作,有大神可以指點我,呵呵
allInput.directive('radioToName', function(){
	return {
		restrict: 'A',
		terminal: true, //這個地方指定優先順序最低,要讓ng-repeat指令完成之後才可以執行
		link: function(scope, ele, attr){
			ele.after('' + attr.radioValue + '');
		}
	};
});</span>


三 實踐效果與坑

1. 實踐效果

到了這一步,基本上沒什麼好講的了,大家就可以放開了用了,下面寫幾個應用例項

效果預覽:http://4.pandaliu.sinaapp.com/

程式碼:https://github.com/sd142400/angular-input

2. 坑

基本上上面的程式碼沒有看什麼資料,完全就是按照之前我做專案的經驗手打了一遍,但是在用的時候大概出現了以下幾個坑

2.1 ng-options 這種命令,需要新增ng-model才可以生效

2.2 radio 這個控制元件,如果是直接$scope.xxx這個作用域會變成子作用域下,所以要用$scope.model.xxx來解決這個問題。當然,model也可以換成別的什麼

以上就是我的一些經驗,歡迎大神來指正。這篇文章是上週日寫的,寫到最後除錯不了,我就去跑了10公里,回來就睡覺了。結果本週忙的要死,今天才抽出空來把這些程式碼搞定。但是當時遇到的一些坑確實忘記了一點,以後會補充進來。