UEGrids.js
最近项目需要,接触了一下angularjs, 感觉双向绑定非常的强大,于是花几个小时的时间,把项目里要实现的一个类似表格数据交换的功能写了一下,angular支持module封装,上手后使用感觉思维也很清晰。于是贴一下主要代码:
首先是页面
<uegrids grids="gridsLeft" selected="selected" width="200"></uegrids>
这个是自定义的uegrids指令,在controller里面我定议了一个数组对象$scope.gridsLeft, 一个变量$scope.selected,和一个元素属性 width = 200;
$scope.gridsLeft = [ { id: "10010", with: "red", value: 0.2000 }, { id: "10010", with: "red", value: 0.2010 }, { id: "10010", with: "red", value: 0.2013 }, { id: "10010", with: "red", value: 0.2014 }, { id: "10010", with: "red", value: 0.2002 }, { id: "10010", with: "red", value: 0.2012 }, { id: "10010", with: "red", value: 0.2020 }, { id: "10010", with: "red", value: 0.2030 }, { id: "10010", with: "red", value: 0.2003 }, { id: "10010", with: "red", value: 0.2013 }, { id: "10010", with: "red", value: 0.2025 }, { id: "10010", with: "red", value: 0.2034 }, { id: "10010", with: "red", value: 0.2005 }, { id: "10010", with: "red", value: 0.2015 }, { id: "10010", with: "red", value: 0.2026 }, { id: "10010", with: "red", value: 0.2038 } ];
$scope.selected = false;
$scope.$watch("selected", function(bool) {
console.log(bool);
});
我使用的是编辑器webstrom 8,代码自动提示完成包含了requirejs、angularjs,真的很方便
然后看下指令部分:
angular.module('directives', []). factory("setPos", function() { return function(width, rows) { console.time("setPos"); var posArr = [], liW = width/ 4, liH = 25, row = 0, col = 1; for (var row = 0; row < rows; row++) { for (var col = 1; col <= 4; col++) { posArr.push({left:col*liW, top:row*liH}); } } console.timeEnd("setPos"); return posArr; } }). directive('uegrids', function() { return { restrict: "E", scope: { grids: "=", selected: "=" }, templateUrl: "template/uegrids.html", controller: function($scope, $element, setPos) { // console.info($scope.grids, $element); // this.grids = $scope.grids; var width = $element.attr("width") || 200, rows = $scope.grids.length/ 4, selectedId = null; $scope.setGrid = function(grid) { return grid.with ? grid.with : "gray"; }; $scope.selectGrid = function(event) { if (event.toElement.tagName.toUpperCase() == "LI") { $(event.toElement).parent().find("li").removeClass("active"); $(event.toElement).addClass("active"); var curId = Number(event.toElement.dataset.id), temp; if (curId != selectedId && selectedId !== null) { $scope.selected = true; // 交换数据 temp = $scope.grids[selectedId]; $scope.grids[selectedId] = $scope.grids[curId]; $scope.grids[curId] = temp; console.log("交互后,索引是", selectedId); $(event.toElement).removeClass("active"); selectedId = null; } else { // $scope.selected = false; selectedId = curId; } } event.preventDefault(); return false; }; var gridPos = setPos(width, rows); $scope.setPosition = function(index) { var pos = gridPos[index]; return "left: "+pos.left+"px; top: "+pos.top+"px"; }; }, link: function(scope, element, attribute, ctrl) { /*console.log(scope.grids, element, attribute);*/ var lis = element.find("li"); }, replace: true } })
这里代码有点罗嗦,反正也是第一次写指令,将就一下。然后就是我在requirejs引用了jquery, angualrjs自身有个qlite的dom操作模块,如果检测到引入了jquery,就会优先使用了jquery,我在指令里使用了dom操作。可能这不太符合angualrjs的提倡,但这里只是一个主要思路,并不是一个完整的项目,所以就不按use strict方式来了。
另外发现,在angularjs指令里做循环或计算操作,会使性能下降很快,比如:
<div class="uegrids" ng-click="selectGrid($event)"> <ul> <li ng-class="setGrid(grid)" style="{{setPosition($index)}}" data-id="{{$index}}" ng-repeat="grid in grids">{{grid.value}}</li> </ul> </div>
假如我在li里加一个ng-style="setPosition($index, grid)", 然后我在setPosition里面去获取$index, grid,然后一堆的计算位置,不好意思,在directive的controller或link里,可能会抛异常。比较好的做法是在controller里预先计算好位置,存到一个变量里面,这里setPosition($index), 只返回变量的引用值即可,效率很高。
数据的交互同于angular的双向绑定,让开发者减少了很多dom的操作,只需要通过简单的ng-click, ng-bind就可以在controller改变数据的同时,迅速地反映在页面上, 而且更妙的是使用scope: {a: "="},使得指令里的a和业务层controller里的a关联了起来,同时发生改变。
然后我在业务层提交的数据,也是指令层交换后的数据,一点也不需要额外做数据修改的处理。