13

我正在通过指令创建一个可重用的 html 位。html 将有一些我想从原始范围传递的变量。这很容易通过在指令上声明属性,然后创建隔离范围并捕获它们来完成。问题是,对于更多的变量,是否有更好的方法来做到这一点?我曾想过传入一个像这样的{firstAttr: $scope.one, secondAttr: $scope.two...}对象,然后把这个对象拆开来得到每一块。这是第一次工作,但双向数据绑定不起作用(即使使用'=')。

问题是绑定的是对象,而不是对象的每个单独部分。我可以使用指令中的编译函数将每个属性添加到元素或其他东西吗?所以:

<mydirective databinding="{one:'first one', two:'second one'}">

将被翻译成:

<mydirective one="first one" two="second one">

这样,我的数据绑定将通过捕获指令中的属性按预期工作。我将如何完成该设计,或者是否有另一种方法可以完全做到这一点?

4

3 回答 3

15

数据绑定指令的想法是一个有趣的想法,但我不会这样做,因为我相信您会遇到指令优先级问题,而且它非常不标准并且会使您的代码难以为未来的程序员遵循。有几种方法可以做到这一点,所以我将讨论我使用过的 3 种不同的解决方案。

解决方案 1

如果您只需要一种方式的数据绑定,最简单的解决方案是在使用 {{}} 在其上插入任何简单的范围变量之后,对指令内对象的字符串表示形式使用 angular 的 scope.$eval 函数。字符串表示甚至不必是有效的 JSON,因为您会注意到在下面的示例中我没有在对象键周围包含引号。

在视图中:

<div databinding="{one:'first', two:{{scopeVar}}, complex:[1,2, "Hi"]}"></div>

在javascript中:

app.directive('databinding', function () {
   return{
      link: function (scope, elm, attrs) {

        console.debug(scope.$eval(attrs['databinding']));

      }
   }
});

解决方案 2

另一种单向数据绑定解决方案是在控制器内部创建一个选项对象,并使用“@”(甚至“=”)将其传递给指令:

在控制器中:

$scope.options = {one: "first, two: "second"};

在视图中:

<div databinding="options"></div>

在javascript中:

app.directive('databinding', function () {
   return{
      scope: {

        options: "@" //Can also use = here

      },
      link: function (scope, elm, attrs) {

        console.log(scope.options);

      }
   }
});

解决方案 3

如果您确实需要双向数据绑定,那么您很不走运,因为没有优雅的方法可以做到这一点。但是,如果您在市场上寻找 hackish 解决方案,您可以使用与解决方案 2 非常相似但更改选项对象的方法来完成双向数据绑定。

与其声明包含简单原始数据类型(如字符串)的选项对象,不如在选项对象内创建一个虚拟对象,然后在其中声明变量。这样做,控制器中范围变量的更改也将在指令内实现,如超时所示。

控制器:

$scope.someScopeVar = "Declared in controller"    

$scope.options = {
  dummy: {
     one: $scope.someScopeVar,
     two: "second"
  }
}

window.setTimeout(function(){

  $scope.someScopeVar = "Changed in controller";

}, 2000)

看法:

<div databinding="options"></div>

指示:

app.directive('databinding', function () {
   return{
      scope: {
        options: "=" //You need to use = with this solution
      },
      link: function (scope, elm, attrs) {

        console.log(scope.options.dummy.one); //Outputs "Declared in controller"

        window.setTimeout(function(){

           console.log(scope.options.dummy.one) //Outputs "Changed in controller"

        }, 5000)

      }
   }
});

此方法有效,因为 javascript 通过引用传递对象,而原语被复制。通过将对象嵌套在对象中,可以保留数据绑定。

于 2013-12-17T18:09:08.943 回答
1

您可以按如下方式更改指令中的范围

.('mydirective ', function(){

   var linker = function(scope, element){
        console.log(scope.one, scope.two);    
   }    
   return {
        link: linker,
        scope: {one:"=", two:"="}
   }    
});
于 2013-03-21T21:27:44.037 回答
0

问题是,对于更多的变量,是否有更好的方法来做到这一点?

我不这么认为。正如您已经发现的那样,尝试将它们作为一个对象传递会导致对象被数据绑定,而不是单个部分。

即使您可以使用 $compile 进行工作,其他阅读您的代码的人也不会清楚发生了什么。

另一种选择是不创建范围(scope: false,这是指令的默认值),或创建新的子范围(scope: true),但要求调用范围必须使用某些范围属性名称才能使用指令。然后您不必指定任何属性。这使得指令的使用更具限制性,但我认为这是您的两个选择:指定多个属性,或需要某些范围属性名称。

于 2013-03-22T04:19:44.367 回答