Angular 好文章收录-模块化开发(四)
指令化,其实本质就是代码的通用化与模块化,AngularJS的指令化工作,将逻辑与DOM都结合在一起,能够做到即插即用,与Asp的Component是相似的概念。 要做到模块化,必要的要求就是通用代码与业务代码的解耦。而解耦并不代表完全的隔绝,解耦要做的是,通用模块与业务模块的隔离,同时也保留接口提供两者通讯。 啰嗦,赶紧实例吧! 某天,产品老大压下来需求,要做个学生信息填写卡,说白了就是一个表单编辑器,so easy,前端单身狗拍拍脑袋马上开工。 <body>
<div ng-controller='demoCtrl'>
<class="panel">
<h3>student card</h3>
<p>
<span>name:</span>
<input type="text" ng-model="stu.name" />
</p>
<span>sexy :</select "stu.sexy">
<option value="1">male</option>
<"2">female</option>
</select>
</p>......</button "btn btn-info" "button" ng-click="saveEditing()">save</button>
</div>
</div>
<script> var app = angular.module("app",[]); app.controller('demoCtrl',function ($scope) { $scope.stu = { name: "mark",sexy: 1 }; $scope.saveEditing = function () { //$http.post("...",{ stu: $scope.guy }); console.log($scope.guy.name + " is saving!"); console.log($scope.guy); }; //这里省略信息卡交互逻辑…… }); </script>
</body>
出来结果,还行。
隔了一天,产品老大想了想,要增强体验,在选择性别的时候,名称要根据男女颜色变化;输入名称的时候,要自动匹配近似名称,并且首字母大写。行,改呗。 $scope.nameChange = function () {
//处理名称变更
};
$scope.sexyChange = //处理性别变更
};
又隔了一天,产品老大终于定稿,这个学生信息填写卡,要应用到demo页、demo1页、demo2页上,而3个页面保存功能指向的后端接口都不一样。 前端单身狗:虽然不至于问候您大爷,但至少要好好考虑如何实现才省功夫吧。难道要把demoCtrl的相关代码都copy到另外两个页面吗?这个时候,只要是写过代码的同志都会say no吧! 赶紧指令化。 隔离 首先,把信息卡的DOM结构独立开来,创建指令 <div ng-controller='demoCtrl'>
<student></student>
</div>
<div ng-controller='demo1Ctrl'>
<student></student>
</div>
<div ng-controller='demo2Ctrl'>
<student></student>
</div>
<!--信息卡DOM模板->
<script type="text/html" id="t1">
<div class="panel">
<p>
<span>name:</span>
<input type="text" ng-model="stu.name" />
</p>
<p>
<span>sexy :</span>
<select ng-model="stu.sexy">
<option value="1">male</option>
<option value="2">female</option>
</select>
</p>
<button class="btn btn-info" type="button" ng-click="onSave()">save</button>
</div>
</script>
<script>
[]); app.directive('student',function () { return { restrict: 'E',scope: {},template: function (elem,attr) { return document.getElementById('t1').innerHTML; },controller:function($scope){ //这里省略信息卡交互逻辑…… } }; }); </script>
虽然独立了信息卡代码,但有两个问题是显而易见的
问题其实指明了解决思路,student需要两个接口与外部通讯: 通讯为大家介绍3种通讯方案。 scope {}指令scope {}参数,可以完全隔离作用域,但是也预留了3种绑定策略,实现子域与父域通讯。 为指令建立两个通讯接口, scope: { stu: '=',//=为双向绑定策略 onSave: '&' //$反向调用父域函数策略 },
优点:简单、简洁
DOM写法: student stu="guy" on-save="saveEditing()"></student>
完整例子: 'demoCtrl'>
<!--指令scope.stu双向绑定demoCtrl scope.guy-->
<!--指令scope.onSave函数指向demoCtrl scope.saveEditing()-->
<student>
</script "text/html" id="t1"> <div class="panel"> <p> <span> <"stu.name" /> </"stu.sexy"> <option> <option> </select> </"onSave()">save</button> </div> </script>
<function ($scope) { $scope.guy = { name: console.log($scope.guy); }; }); app.directive('student',0)">function () { return { restrict: 'E',scope: { stu: '=',//=为双向绑定策略 onSave: '&' //$反向调用父域函数策略 },template: function (elem,attr) { return document.getElementById('t1').innerHTML; },controller: function ($scope,$element,$attrs,$transclude) { //这里省略信息卡交互逻辑…… } }; }); </ 效果:
$parse 在ngModel的解决方案中,已经有过通过$parse获取执行表达式操作父域函数的例子: 关于$parse服务,想了解更多,请移步—— var getClassName,setClassName,saveInvoker = angular.noop; //注意:建议查阅一下$parse内置表达式转换函数的使用方法。 //获得stu属性指向的表达式{{guy}} getStudent = $parse($attrs.stu); setStudent = getStudent.assign; //获得on-save属性指向的表达式{{saveEditing()}} saveInvoker = $parse($attrs.onSave); //监听父域的{{guy}} $scope.$parent.$watch(getStudent,0)">function (stu) { $scope.stu = stu; }); $scope.onSave = //在父域中,执行表达式{{guy}} assign——将本地对象stu设置到父域guy setStudent($scope.$parent,$scope.stu);
|