将函数传递给指令以在链接中执行的正确方法 [英] Proper way to pass functions to directive for execution in link

查看:23
本文介绍了将函数传递给指令以在链接中执行的正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道我们通常通过隔离作用域将函数传递给指令:

I know we usually pass functions to directives via an isolated scope:

.directive('myComponent', function () {
    return {
        scope:{
            foo: '&'
        }        
    };
})

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

And then in the template we can call this function like such:

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

其中 myVal 是父作用域中函数 foo 所采用的参数名称.

Where myVal is the name of the parameter that function foo in the parent scope takes.

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

Now if I intend to use this from the link function instead of template, I will have to call it with: scope.foo()(value), since scope.foo serves as a wrapper of the original function. This seems a bit tedious to me.

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

If I pass the function to the myComponent directive using =:

.directive('myComponent', function () {
    return {
        scope:{
            foo: '='
        }        
    };
})

然后我将能够从我的链接函数中使用 scope.foo(value).那么这是在函数上使用 2 向绑定的有效用例,还是我在做一些我不应该做的 hack?

Then I will be able to just use scope.foo(value) from my link function. So is this a valid use case to use 2-way binding on functions, or am I doing some sort of hack that I shouldn't be doing?

推荐答案

这就是我对答案投反对票的原因.

Here is why I downvoted the answer.

首先,永远不要使用="将函数引用传递给指令.

First, you should never use '=' to pass function references to directives.

'=' 创建两个监视并使用它们来确保指令范围和父范围引用相同(双向绑定).允许指令更改父作用域中函数的定义是一个非常糟糕的主意,当您使用这种类型的绑定时就​​会发生这种情况.此外,手表应该最小化——虽然它可以工作,但两个额外的 $watches 是不必要的.所以这不好 - 部分否决票是为了暗示它是.

'=' creates two watches and uses them to ensure that both the directive scope and the parent scope references are the same (two-way binding). It is a really bad idea to allow a directive to change the definition of a function in your parent scope, which is what happens when you use this type of binding. Also, watches should be minimized - while it will work, the two extra $watches are unnecessary. So it is not fine - part of the down vote was for suggesting that it was.

第二 - 答案曲解了&"做.&不是单向绑定".之所以会出现这种用词不当,仅仅是因为与 '=' 不同,它不会创建任何 $watches,并且更改指令范围中的属性值不会传播到父级.

Second - the answer misrepresents what '&' does. & is not a "one way binding". It gets that misnomer simply because, unlike '=', it does not create any $watches and changing the value of the property in the directive scope does not propagate to the parent.

根据文档:

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

& or &attr - provides a way to execute an expression in the context of the parent scope

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

When you use & in a directive, it generates a function that returns the value of the expression evaluated against the parent scope. The expression does not have to be a function call. It can be any valid angular expression. In addition, this generated function takes an object argument that can override the value of any local variable found in the expression.

为了扩展 OP 的示例,假设父级以以下方式使用此指令:

To extend the OP's example, suppose the parent uses this directive in the following way:

<my-component foo="go()">

在指令(模板或链接函数)中,如果调用

In the directive (template or link function), if you call

foo({myVal: 42});

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

What you are doing is evaluating the expression "go()", which happens to call the function "go" on the parent scope, passing no arguments.

或者,

<my-component foo="go(value)">

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

You are evaluating the expression "go(value)" on the parent scope, which will is basically calling $parent.go($parent.value)"

<my-component foo="go(myVal)">

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

You are evaluating the expression "go(myVal)", but before the expression is evaluated, myVal will be replaced with 42, so the evaluated expression will be "go(42)".

<my-component foo="myVal + value + go()">

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

In this case, $scope.foo({myVal: 42}) will return the result of:

42 + $parent.value + $parent.go()

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

Essentially, this pattern allows the directive to "inject" variables that the consumer of the directive can optionally use in the foo expression.

你可以这样做:

<my-component foo="go">

并在指令中:

$scope.foo()(42)

$scope.foo() 将计算表达式go",它将返回对 $parent.go 函数的引用.然后它将调用它为 $parent.go(42).这种模式的缺点是,如果表达式的计算结果不是函数,您将收到错误消息.

$scope.foo() will evaluate the expression "go", which will return a reference to the $parent.go function. It will then call it as $parent.go(42). The downside to this pattern is that you will get an error if the expression does not evaluate to a function.

否决票的最后一个原因是断言 ng-event 指令使用 &.事实并非如此.没有任何内置指令创建隔离作用域:

The final reason for the down vote was the assertion that the ng-event directives use &. This isn't the case. None of the built in directives create isolated scopes with:

scope:{
}

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

The implementation of '&foo' is (simplified for clarity), boils down to:

$scope.foo = function(locals) {
    return $parse(attr.foo)($scope.$parent, locals);
}

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

The implementation of ng-click is similar, but (also simplified):

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

所以要记住的关键是,当您使用&"时,您不是在传递函数——而是在传递一个表达式.该指令可以通过调用生成的函数随时获取该表达式的结果.

So the key to remember is that when you use '&', you are not passing a function - you are passing an expression. The directive can get the result of this expression at any time by invoking the generated function.

这篇关于将函数传递给指令以在链接中执行的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆