将函数传递给指令以在链接中执行的正确方法

Xav*_*_Ex 10 angularjs angularjs-directive angularjs-scope

我知道我们通常通过一个独立的范围将函数传递给指令:

.directive('myComponent', function () {
    return {
        scope:{
            foo: '&'
        }        
    };
})
Run Code Online (Sandbox Code Playgroud)

然后在模板中我们可以像这样调用这个函数:

<button class="btn" ng-click="foo({ myVal: value })">Submit</button>
Run Code Online (Sandbox Code Playgroud)

父作用域中的myVal函数的参数名称在哪里foo.

现在,如果我打算从link函数而不是模板中使用它,我将不得不用:来调用它scope.foo()(value),因为它scope.foo充当原始函数的包装器.这对我来说似乎有点乏味.

如果我myComponent使用=以下函数将函数传递给指令:

.directive('myComponent', function () {
    return {
        scope:{
            foo: '='
        }        
    };
})
Run Code Online (Sandbox Code Playgroud)

然后我将能够使用scope.foo(value)我的链接功能.那么这是一个有效的用例,对函数使用双向绑定,还是我做了一些我不应该做的黑客攻击?

Joe*_*ger 19

这就是为什么我低估了答案.

首先,你不应该使用'='来传递对指令的函数引用.

'='创建两个监视并使用它们来确保指令范围和父范围引用是相同的(双向绑定).允许指令更改父作用域中函数的定义是一个非常糟糕的主意,这是使用此类绑定时发生的情况.此外,手表应尽量减少 - 虽然它会起作用,但两个额外的手表是不必要的.所以这不好 - 下来投票的一部分是建议它.

第二 - 答案错误地表示"&"的作用.&不是"单向约束".它只是因为,与'='不同,它不会创建任何$ watch,并且在指令范​​围内更改属性的值不会传播到父级.

根据文件:

&or&attr - 提供在父作用域的上下文中执行表达式的方法

在指令中使用&时,它会生成一个函数,该函数返回针对父作用域计算的表达式的值.表达式不必是函数调用.它可以是任何有效的角度表达式.此外,此生成的函数采用一个对象参数,该参数可以覆盖表达式中找到的任何局部变量的值.

要扩展OP的示例,假设父对象以下列方式使用此指令:

<my-component foo="go()">
Run Code Online (Sandbox Code Playgroud)

在指令(模板或链接功能)中,如果你打电话

foo({myVal: 42});
Run Code Online (Sandbox Code Playgroud)

你正在做的是评估表达式"go()",它恰好在父作用域上调用函数"go",不传递任何参数.

或者,

<my-component foo="go(value)">
Run Code Online (Sandbox Code Playgroud)

您正在评估父作用域上的表达式"go(value)",这将基本上调用$ parent.go($ parent.value)"

<my-component foo="go(myVal)">
Run Code Online (Sandbox Code Playgroud)

您正在评估表达式"go(myVal)",但在计算表达式之前,myVal将替换为42,因此计算的表达式将为"go(42)".

<my-component foo="myVal + value + go()">
Run Code Online (Sandbox Code Playgroud)

在这种情况下,$ scope.foo({myVal:42})将返回以下结果:

42 + $parent.value + $parent.go()
Run Code Online (Sandbox Code Playgroud)

从本质上讲,这种模式允许指令"注入"指令的使用者可以在foo表达式中选择使用的变量.

你可以这样做:

<my-component foo="go">
Run Code Online (Sandbox Code Playgroud)

并在指令中:

$scope.foo()(42)
Run Code Online (Sandbox Code Playgroud)

$ scope.foo()将计算表达式"go",它将返回对$ parent.go函数的引用.然后它将其称为$ parent.go(42).此模式的缺点是,如果表达式未计算函数,则会出现错误.

投票结果的最后一个原因是ng-event指令使用&的断言.事实并非如此.没有内置指令创建隔离范围:

scope:{
}
Run Code Online (Sandbox Code Playgroud)

'&foo'的实现是(为简单起见而简化),归结为:

$scope.foo = function(locals) {
    return $parse(attr.foo)($scope.$parent, locals);
}
Run Code Online (Sandbox Code Playgroud)

ng-click的实现类似,但(也简化):

link: function(scope, elem, attr) {
    elem.on('click', function(evt) {
        $parse(attr.ngClick)(scope, {
             $event: evt
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

所以要记住的关键是当你使用'&'时,你没有传递一个函数 - 你正在传递一个表达式.该指令可以通过调用生成的函数随时获取此表达式的结果.

  • (更正,我删除了我的downvote,不玩这个游戏) (2认同)