Angular 好文章收录-模块化开发(四)

前端之家收集整理的这篇文章主要介绍了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>

出来结果,还行。

隔了一天,产品老大想了想,要增强体验,在选择性别的时候,名称要根据男女颜色变化;输入名称的时候,要自动匹配近似名称,并且首字母大写。行,改呗。demoCtrl加上以下逻辑

$scope.nameChange = function () {
    //处理名称变更
};

$scope.sexyChange = //处理性别变更
};

又隔了一天,产品老大终于定稿,这个学生信息填写卡,要应用到demo页、demo1页、demo2页上,而3个页面保存功能指向的后端接口都不一样。

前端单身狗:虽然不至于问候您大爷,但至少要好好考虑如何实现才省功夫吧。难道要把demoCtrl的相关代码都copy到另外两个页面吗?这个时候,只要是写过代码的同志都会say no吧!

赶紧指令化。

隔离

首先,把信息卡的DOM结构独立开来,创建指令student。指令scope参数要设为{},如果设为falsetrue达不到完全隔离的效果哦,不理解原因的童鞋请回顾上一章节。

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

虽然独立了信息卡代码,但有两个问题是显而易见的

  1. 隔离以后,指令内部如何获得3个demoCtrl的stu?

  2. 保存按钮又是如何调用外部3个demoCtrl不同的save方法

问题其实指明了解决思路,student需要两个接口与外部通讯:scope.stu&scope.save()

通讯

为大家介绍3种通讯方案。

scope {}

指令scope {}参数,可以完全隔离作用域,但是也预留了3种绑定策略,实现子域与父域通讯。

为指令建立两个通讯接口,stu采取=双向绑定父域对象的策略;而onSave则采取$反向调用父域函数策略。

scope: { stu: '=',//=为双向绑定策略 onSave: '&' //$反向调用父域函数策略 },

优点:简单、简洁
缺点:

  1. 通讯接口要求比较多、复杂的情况下,指令scope {}要配置的绑定策略也比较多;

  2. 造成指令与指令之间的通讯容易混乱;

  3. 指令内部好像没有办法,往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) { //这里省略信息卡交互逻辑…… } }; }); </ 效果

ngModel

ngModel,这个内置指令相信大家都不会陌生。自定义指令引用其自身的ngModel指令,其原理就是:

  • 父域对象绑定ngModel

  • ngModel绑定指令子域对象

优点:可以充分利用ngModel的特性,例如commit、rollback等特性,也可以搭配ng-model-options进行使用。

缺点:

  1. 相对于方案1,父子对象绑定中间还要多一层ngModel的绑定,性能必然降低;

  2. 相对于方案1,使用比较麻烦;

  3. 自身不能实现反向调用父域函数,需要借助$parse转换表达式方案实现

"ngModel.$modelValue.name" /> </"ngModel.$modelValue.sexy"> <"$parse",0)">function ($parse) { require: ['ngModel'],link: function (scope,element,attr,ctrls) { //link阶段,通过require获取指令自身的控制器,及ngModel指令的控制器 var stCtrl = ctrls[0]; var ngModelCtrl = ctrls[1]; //并将ngModel指令的控制器,通过自身控制器的init()方法传入到其中 stCtrl.init(ngModelCtrl); },161)">//创建controller的对外初始化方法,并将外部ngModel的控制器设置本地作用域对象 this.init = function (ngModelCtrl) { $scope.ngModel = ngModelCtrl; }; //获得on-save属性指向的表达式{{saveEditing()}} var saveInvoker = $parse($attrs.onSave); $scope.onSave = //在父域中,执行表达式{{saveEditing()}}——执行父域saveEditing() saveInvoker($scope.$parent,null); }; } }; }]); </body>

$parse

在ngModel的解决方案中,已经有过通过$parse获取执行表达式操作父域函数的例子:$parse($attrs.onSave)。这个方案不仅能够执行父域函数表达式,同时也能够执行对象的get/set表达式。但是本方案本质其实是对于父域$scope.$parent的直接操作,只是通过$parse服务实现解耦。

关于$parse服务,想了解更多,请移步——
http://segmentfault.com/a/1190000002749571

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

End

转载地址:http://www.jb51.cc/article/p-rpcdbvsr-b.html

原文链接:https://www.f2er.com/angularjs/148953.html

猜你在找的Angularjs相关文章