search

Home  >  Q&A  >  body text

javascript - 使用angularjs,在指令中如何绑定不同的回调函数?

html<input my-datepicker id="1" />
<input my-datepicker id="2" />
javascriptmodule.directive('myDatepicker', function(){
    return {
        link : function(scope, el){
            el.datepicker(function(){
                //这里需要执行在controller里定义的不同的回调函数
            });
        }
    }
});
module.controller('testCtrl', function(){
    vm.callbackA = function(){
        //回调函数A
    };
    vm.callbackB = function(){
        //回调函数B
    }
});
大家讲道理大家讲道理2904 days ago396

reply all(2)I'll reply

  • PHPz

    PHPz2017-04-10 15:00:46

    之前在手机上草草回答了一下,现在补全。

    一个指令使用多次,它们如何去绑定来自于父级(及以上)的表达式——比如方法调用?

    @小俞 童鞋给出了一种答案,原理是多个指令共用父级作用域。这个方法能达到题主的要求么?能,但却是错的!

    让指令继承父级作用域是编写指令的大忌之一,Angular 在设计之初给予指令太大的自由(同时太复杂的定义)一直都是被诟病的一个理由。事实上指令是 Angular 自己的叫法,它基本等价于 WebComponent 里的组件。你去创造一个组件,根本上图个什么?

    1. 高度可重用性
    2. 超低耦合甚至零耦合

    @小俞 童鞋我问你,按你那样写指令的话,以上两点能满足哪一个?指令那样写还不如直接耦合进控制器里,等于没写呀。

    好了,以上是针对评论的回复;以下是正解:

    首先既然是指令,那么就要尽一切可能写成独立作用域的,最不济也得是新建作用域。到了现在这个时间点,不声明 scope 属性的指令等于没写指令(不信等着看 Angular 2.0,去年的 ngEurope 已经证实此点)。

    接下来的问题就是独立作用域之后如何传递外部的表达式(包括方法调用)。

    我们知道 "&" 类型的 scope 属性可以绑定来自于父级作用域的表达式,也包括方法调用。

    如果在你的 DDO(指令定义对象)里有这样的声明:

    javascriptscope: {
      localFn: '&outerFn'
    }
    

    那么你可以这样去写指令:<... outer-fn="doSomething(args)">

    那么在你的 link 函数内,$scope.localFn 就是一个包装函数,调用此函数将向被绑定的对象发出消息(也就是方法调用)。也就是说,这样写:

    javascriptlink: function($scope, ...) {
      $scope.localFn();
    }
    

    就等于通过指令去调用来自外部作用域的方法。

    最后一个问题就是参数如何传递?很显然这样传参:$scope.localFn(args) 是不行的,因为 $scope.localFn 并不是 doSomething 的直接引用,而是一个包装函数去间接调用 doSomething。Angular 的解决方式是通过传递一个对象来引用传入的参数(key 对应入参的参数名):

    javascriptlink: function($scope, ...) {
      $scope.localFn({args: YOUR_ARGS});
    }
    

    解释一下,当 $scope.localFn 被调用时,它首先通过对象参数 {args: YOUR_ARGS} 来匹配目标方法需要的入参,然后再去调用目标方法,类似于:doSomething.call(OUTER_SCOPE, args ...),其中 OUTER_SCOPE 自然是 doSomething 所属的作用域对象,这个过程不需要你干预,声明 DDO 的时候 Angular 已经处理的妥妥的了。当然,如果是多个入参,Angular 也会用数组包装一下然后使用 apply 去调用。

    这样写指令才能做到之前所说的两点几本要求,即:1)高度可重用;2)低耦合。

    reply
    0
  • 巴扎黑

    巴扎黑2017-04-10 15:00:46

    楼主的问题其实是controller与指令的交互。
    例如你这里的myDatepicker是一个通用的指令,希望在不同的情境下调用到controller不同的方法。
    html代码:

    <p ng-controller="testCtrl">
        <input my-datepicker id="1" callback="callbackA()"/>
        <input my-datepicker id="2" callback="callbackB()"/>
    </p>
    

    JavaScript代码:

    .directive('myDatepicker', function () {
        return {
            scope: {
                callback: '&'
            },
            link: function (scope, element, attrs, controller) {
                element.datepicker(function () {
                    scope.callback();
                });
            }
        }
    })
    
    .controller('testCtrl', function ($scope, $log) {
        $scope.callbackA = function () {
            $log.info('callback A');
        };
    
        $scope.callbackB = function () {
            $log.info('callback B');
        }
    })
    

    reply
    0
  • Cancelreply