В чем разница между '@' и '=' в области действия директивы в AngularJS?

949

Я внимательно прочитал документацию AngularJS по этой теме, а затем попробовал директиву. Здесь fiddle.

И вот некоторые соответствующие фрагменты:

  • Из HTML:

    <pane bi-title="title" title="{{title}}">{{text}}</pane>
    
  • В директиве панели:

    scope: { biTitle: '=', title: '@', bar: '=' },
    

Есть несколько вещей, которые я не получаю:

  • Почему мне нужно использовать "{{title}}" с '@' и "title" с помощью '='?
  • Могу ли я получить доступ к родительской области напрямую, не украсив свой элемент атрибутом?
  • В документации говорится: "Часто желательно передавать данные из изолированной области с помощью выражения и в родительскую область", но это, похоже, отлично работает с двунаправленным связыванием. Почему лучше использовать маршрут выражения?

Я нашел еще одну скрипту, которая также показывает выражение: http://jsfiddle.net/maxisam/QrCXh/

  • 16
    Честная оценка. Способность исследовать и находить ответы важна.
  • 1
    stackoverflow.com/questions/14908133/...
Показать ещё 4 комментария
Теги:
angularjs-scope
angularjs-directive
isolated-scope

17 ответов

1168
Лучший ответ

Почему мне нужно использовать "{{title}}" с " @" и "title" с помощью "="?

@ связывает свойство области локального/директивы с оцененным значением атрибута DOM. Если вы используете title=title1 или title="title1", значение атрибута DOM "title" - это просто строка title1. Если вы используете title="{{title}}", значение атрибута DOM "title" - это интерполированное значение {{title}}, поэтому строка будет иметь значение, на которое в настоящее время установлено свойство "title" родительской области. Поскольку значения атрибутов всегда являются строками, вы всегда будете иметь строковое значение для этого свойства в области директивы при использовании @.

= привязывает свойство области локальных/директивных объектов к свойствам родительской области. Таким образом, с = вы используете имя родительской модели/области видимости как значение атрибута DOM. Вы не можете использовать {{}} с =.

С помощью @вы можете делать такие вещи, как title="{{title}} and then some" - {{title}}, затем строка "и их некоторые" объединяется с ней. Конечная конкатенированная строка - это свойство локальной/директивы scope. (Вы не можете сделать это с помощью =, только @.)

С @ вам нужно будет использовать attr.$observe('title', function(value) { ... }), если вам нужно использовать значение в вашей функции связи (ing). Например, if(scope.title == "...") не будет работать так, как вы ожидаете. Обратите внимание, что это означает, что вы можете получить доступ к этому атрибуту асинхронно. Вам не нужно использовать $observ(), если вы используете только значение в шаблоне. Например, template: '<div>{{title}}</div>'.

С = вам не нужно использовать $observ.

Можно ли также напрямую обращаться к родительской области, не украсив мой элемент атрибутом?

Да, но только если вы не используете область изоляции. Удалите эту строку из своей директивы

scope: { ... }

а затем ваша директива не создаст новую область. Он будет использовать родительскую область. Затем вы можете напрямую получить доступ ко всем свойствам родительской области.

В документации говорится: "Часто желательно передавать данные из изолированной области видимости через выражение и в родительскую область", но это, похоже, отлично работает с двунаправленным связыванием. Почему лучше использовать маршрут выражения?

Да, двунаправленная привязка позволяет области локального/директива и родительской области обмениваться данными. "Связывание выражений" позволяет директиве вызывать выражение (или функцию), определяемое атрибутом DOM, - и вы также можете передавать данные в качестве аргументов выражения или функции. Таким образом, если вам не нужно обмениваться данными с родителем, вы просто хотите вызвать функцию, определенную в родительской области - вы можете использовать синтаксис и.

См. также

  • 1
    Да, это действительно странное поведение, особенно если не использовать интерполяцию и просто пытаться передать строку. По-видимому, запрос на удаление действительно был объединен со сборками разработки и находится в сборках RC 1.1.5 и 1.2.0. Хорошо, что они исправили это очень не интуитивное поведение!
  • 45
    Написание «@» или «=» гораздо понятнее, чем написание «eval-dom», «parent-scope» или любого другого читаемого человеком текста. Хорошее дизайнерское решение.
Показать ещё 9 комментариев
550

Здесь есть много отличных ответов, но я хотел бы предложить свою точку зрения о различиях между привязками @, = и &, которые оказались полезными для меня.

Все три привязки - это способы передачи данных из родительской области в вашу выделенную область директивы через атрибуты элемента:

  • @ привязка для передачи строк.    Эти строки поддерживают выражения {{}} для интерполированных значений.    Например:    , Интерполированное выражение оценивается против    директивной родительской области.

  • = привязка предназначена для привязки двухсторонней модели. Модель в родительском пространстве    связан с моделью в изолированной области действия. Изменения в    одна модель влияет на другую, и наоборот.

  • & привязка предназначена для передачи метода в область вашей директивы, чтобы    его можно вызвать в вашей директиве. Метод предварительно привязан к    директивной родительской области и поддерживает аргументы. Например, если метод hello (name) в родительской области, то в    чтобы выполнить метод изнутри вашей директивы, вы должны    вызов $scope.hello({name: 'world'})

Я нахожу, что легче запомнить эти различия, обратившись к привязкам к области с помощью более короткого описания:

  • @ Связывание строки атрибута
  • = Двусторонняя привязка модели
  • & привязка метода обратного вызова

Символы также уточняют, что представляет собой переменная области видимости внутри вашей директивной реализации:

  • @ строка
  • = модель
  • & метод

В порядке полезности (для меня в любом случае):

  • =
  • @
  • &
  • 13
    На самом деле, "&" поддерживает аргументы (или, скорее, локальные) в форме: callback({foo: "some value"}) , которая затем может быть использована <my-dir callback="doSomething(foo)"> . В противном случае хороший ответ
  • 11
    Должен быть принят ответ. Вот краткая статья с той же информацией, но с добавленными примерами кода: umur.io/…
Показать ещё 7 комментариев
61

= означает двунаправленное связывание, поэтому ссылка на переменную на родительскую область. Это означает, что при изменении переменной в директиве она также будет изменена в родительской области.

@ означает, что переменная будет скопирована (клонирована) в директиву.

Насколько я знаю, <pane bi-title="{{title}}" title="{{title}}">{{text}}</pane> тоже должен работать. bi-title получит значение переменной родительского объекта, которое может быть изменено в директиве.

Если вам нужно изменить несколько переменных в родительской области, вы можете выполнить функцию в родительской области из директивы (или передать данные через службу).

  • 1
    Да, та часть, которую я получаю, вижу скрипку в вопросе. Но как насчет неясных частей?
  • 4
    дело в том, что {{}} не работает с =. = не оценивается, но строка принимается как имя свойства как есть. Спасибо за ответ!
Показать ещё 4 комментария
35

@ получить как строку

  • Это не создает никаких привязок. Вы просто получаете слово, которое вы передали в виде строки

= 2-сторонняя привязка

  • изменения, внесенные с контроллера, будут отражены в ссылке, содержащейся в директиве, и наоборот

& Это ведет себя по-другому, потому что область получает функцию, которая возвращает объект, который был передан в. Я предполагаю, что это необходимо, чтобы заставить его работать. Эта скрипка должна быть понятной.

  • После вызова этой функции getter результирующий объект ведет себя следующим образом:
    • если функция была передана: тогда функция выполняется в закрытии родителя (контроллера) при вызове
    • если была передана нефункция: просто получите локальную копию объекта, у которого нет привязок


Эта скрипка должна продемонстрировать, как они работают. Обратите особое внимание на функции области с get... в названии, чтобы, надеюсь, лучше понять, что я имею в виду &

35

Если вы хотите увидеть больше, как это работает с живым примером. http://jsfiddle.net/juanmendez/k6chmnch/

var app = angular.module('app', []);
app.controller("myController", function ($scope) {
    $scope.title = "binding";
});
app.directive("jmFind", function () {
    return {
        replace: true,
        restrict: 'C',
        transclude: true,
        scope: {
            title1: "=",
            title2: "@"
        },
        template: "<div><p>{{title1}} {{title2}}</p></div>"
    };
});
  • 2
    Есть несколько примеров, связанных в вопросе и верхнем ответе. Что это добавляет?
  • 9
    @iwein, это добавляет ясности. Если бы я мог понять и усвоить полнофункциональные примеры, мне бы этот сайт не понадобился.
Показать ещё 5 комментариев
32

В директиве можно добавить три способа:

  1. Родительский охват: это наследование по умолчанию.

Директива и ее родительская (контроллер/директива, внутри которой она лежит) обладают одинаковыми свойствами. Поэтому любые изменения, внесенные в переменные области внутри директивы, также отражаются в родительском контроллере. Вам не нужно указывать это значение по умолчанию.

  1. Директива Child scope: direct создает дочернюю область, которая наследуется от родительской области, если вы укажете переменную scope директивы как true.

Здесь, если вы измените переменные области видимости внутри директивы, она не будет отображаться в родительской области, но если вы измените свойство переменной области видимости, которое отражается в родительской области, так как вы фактически изменили переменную области действия родительской,

Пример,

app.directive("myDirective", function(){

    return {
        restrict: "EA",
        scope: true,
        link: function(element, scope, attrs){
            scope.somvar = "new value"; //doesnot reflect in the parent scope
            scope.someObj.someProp = "new value"; //reflects as someObj is of parent, we modified that but did not override.
        }
    };
});
  1. Изолированная область: это используется, когда вы хотите создать область, которая не наследуется от области контроллера.

Это происходит, когда вы создаете плагины, поскольку это делает директиву универсальной, поскольку она может быть помещена в любой HTML-код и не зависит от ее родительской области.

Теперь, если вы не хотите никакого взаимодействия с родительской областью, вы можете просто указать область как пустой объект. как,

scope: {} //this does not interact with the parent scope in any way

В основном это не так, поскольку нам нужно некоторое взаимодействие с родительской областью, поэтому мы хотим, чтобы некоторые из значений/изменений проходили. По этой причине мы используем:

1. "@"   (  Text binding / one-way binding )
2. "="   ( Direct model binding / two-way binding )
3. "&"   ( Behaviour binding / Method binding  )

@ означает, что изменения в области контроллера будут отражены в области директивы, но если вы измените значение в области директивы, переменная области контроллера не будет затронута.

@всегда ожидает, что отображаемый атрибут будет выражением. Это очень важно; потому что для работы префикса "@" нам нужно обернуть значение атрибута внутри {{}}.

= является двунаправленным, поэтому, если вы изменяете переменную в области директивы, изменяется и переменная области контроллера

& используется для привязки метода области управления, так что при необходимости мы можем вызвать его из директивы

Преимущество здесь состоит в том, что имя переменной не должно быть одинаковым в области контроллера и области действия.

Например, область действия директивы имеет переменную "dirVar", которая синхронизируется с переменной "contVar" области управления. Это дает большую мощность и обобщение директивы, поскольку один контроллер может синхронизироваться с переменной v1, в то время как другой контроллер, использующий ту же директиву, может запрашивать dirVar для синхронизации с переменной v2.

Ниже приведен пример использования:

Директива и контроллер:

 var app = angular.module("app", []);
 app.controller("MainCtrl", function( $scope ){
    $scope.name = "Harry";
    $scope.color = "#333333";
    $scope.reverseName = function(){
     $scope.name = $scope.name.split("").reverse().join("");
    };
    $scope.randomColor = function(){
        $scope.color = '#'+Math.floor(Math.random()*16777215).toString(16);
    };
});
app.directive("myDirective", function(){
    return {
        restrict: "EA",
        scope: {
            name: "@",
            color: "=",
            reverse: "&"
        },
        link: function(element, scope, attrs){
           //do something like
           $scope.reverse(); 
          //calling the controllers function
        }
    };
});

И html (обратите внимание на differnce для @и =):

<div my-directive
  class="directive"
  name="{{name}}"
  reverse="reverseName()"
  color="color" >
</div>

Вот ссылка на блог, который описывает это красиво.

  • 0
    & не является ни «привязкой поведения», ни «привязкой метода», это привязка углового выражения.
21

Просто мы можем использовать: -

  • @: - для значений String для одного способа привязки данных. в одном случае привязка данных вы можете передать значение области только директиве

  • =: - для значения объекта для двусторонней привязки данных. в двухстороннем связывании данных вы можете изменить значение области как в директиве, так и в html.

  • &: - для методов и функций.

ИЗМЕНИТЬ

В нашем определении Компонент для Angular версии 1.5 И выше
существует четыре разных типа привязок:

  • = Двусторонняя привязка данных: - если мы изменим значение, оно автоматически обновит
  • < односторонняя привязка: - когда мы просто хотим прочитать параметр из родительской области и не обновлять его.

  • @ это для Строковые параметры

  • & это для Callbacks, если ваш компонент должен вывести что-то в свою родительскую область

10

Я создал небольшой HTML файл, содержащий угловой код, демонстрирующий различия между ними:

<!DOCTYPE html>
<html>
  <head>
    <title>Angular</title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
  </head>
  <body ng-app="myApp">
    <div ng-controller="myCtrl as VM">
      <a my-dir
        attr1="VM.sayHi('Juan')" <!-- scope: "=" -->
        attr2="VM.sayHi('Juan')" <!-- scope: "@" -->
        attr3="VM.sayHi('Juan')" <!-- scope: "&" -->
      ></a>
    </div>
    <script>
    angular.module("myApp", [])
    .controller("myCtrl", [function(){
      var vm = this;
      vm.sayHi = function(name){
        return ("Hey there, " + name);
      }
    }])
    .directive("myDir", [function(){
      return {
        scope: {
          attr1: "=",
          attr2: "@",
          attr3: "&"
        },
        link: function(scope){
          console.log(scope.attr1);   // =, logs "Hey there, Juan"
          console.log(scope.attr2);   // @, logs "VM.sayHi('Juan')"
          console.log(scope.attr3);   // &, logs "function (a){return h(c,a)}"
          console.log(scope.attr3()); // &, logs "Hey there, Juan"
        }
      }
    }]);
    </script>
  </body>
</html>
6

= - это двусторонняя привязка, которая позволяет вам иметь живые изменения внутри вашей директивы. Когда кто-то изменяет эту переменную из директивы, вы будете иметь эти измененные данные внутри своей директивы, но @ не является двухсторонней привязкой. Он работает как Текст. Вы связываете один раз, и у вас будет только его значение.

Чтобы сделать это более ясно, вы можете использовать эту замечательную статью:

Область действия AngularJS '@' и '='

3

@ свойство локальной видимости используется для доступа к строковым значениям, которые определены вне директивы.

= В тех случаях, когда вам нужно создать двустороннюю привязку между внешней областью и директивой, выделите область действия, вы можете использовать символ.

& Локальное свойство scope позволяет потребителю директивы передавать функцию, которую может вызывать директива.

Просьба проверить приведенную ниже ссылку, которая дает вам четкое понимание с примерами. Я нашел ее очень полезной, поэтому подумал об обмене ею.

http://weblogs.asp.net/dwahlin/creating-custom-angularjs-directives-part-2-isolate-scope

3

Я реализовал все возможные варианты в скрипте.

Он имеет все опции:

scope:{
    name:'&'
},

scope:{
    name:'='
},

scope:{
    name:'@'
},

scope:{

},

scope:true,

https://jsfiddle.net/rishulmatta/v7xf2ujm

2

Даже если область локальная, как и в вашем примере, вы можете получить доступ к родительской области с помощью свойства $parent. Предположим в приведенном ниже коде, что title определяется в родительской области. Затем вы можете получить титул как $parent.title:

link : function(scope) { console.log(scope.$parent.title) },
template : "the parent has the title {{$parent.title}}"

Однако в большинстве случаев один и тот же эффект лучше получается с использованием атрибутов.

Пример того, где я нашел "&" нотация, которая используется "для передачи данных из изолированной области видимости через выражение и в родительскую область", полезная (и двухсторонняя привязка данных не может быть использована) была в директиве для предоставления специальной структуры данных внутри ng-repeat.

<render data = "record" deleteFunction = "dataList.splice($index,1)" ng-repeat = "record in dataList" > </render>

Одной частью рендеринга была кнопка удаления, и здесь было полезно прикрепить функцию delete из внешней области через &. Внутри рендеринговой директивы это выглядит как

scope : { data = "=", deleteFunction = "&"},
template : "... <button ng-click = "deleteFunction()"></button>"

Двухсторонняя привязка данных, т.е. data = "=", не может использоваться, поскольку функция удаления будет выполняться в каждом цикле $digest, что не очень хорошо, поскольку запись затем сразу же удаляется и никогда не отображается.

1

основное различие между ними - это просто

@ Attribute string binding
= Two-way model binding
& Callback method binding
1

@ и = см. другие ответы.

Один полученный &
TL; DR;
& получает выражение (не только как в примерах в других ответах) от родителя и устанавливает его как функцию в директиве, вызывающую выражение. И эта функция имеет возможность заменить любую переменную (даже имя функции) выражения, передав объект с переменными.

объяснил
& является ссылкой на выражение, это означает, что если вы передаете что-то вроде <myDirective expr="x==y"></myDirective>
в директиве это expr будет функцией, которая вызывает выражение, например:
function expr(){return x == y}.
поэтому в директиве html <button ng-click="expr()"></button> вызывается выражение. В js директивы просто $scope.expr() также вызовет выражение.
Выражение будет вызываться с помощью $scope.x и $scope.y родителя.
У вас есть возможность переопределить параметры!
Если вы установили их по вызову, например. <button ng-click="expr({x:5})"></button>
то выражение будет вызываться с вашим параметром x и родительским параметром y.
Вы можете переопределить оба.
Теперь вы знаете, почему работает <button ng-click="functionFromParent({x:5})"></button>.
Поскольку он просто вызывает выражение родителя (например, <myDirective functionFromParent="function1(x)"></myDirective>) и заменяет возможные значения вашими указанными параметрами, в этом случае x.
это может быть:
<myDirective functionFromParent="function1(x) + 5"></myDirective>
или
<myDirective functionFromParent="function1(x) + z"></myDirective>
с детским звонком:
<button ng-click="functionFromParent({x:5, z: 4})"></button>.
или даже с заменой функции:
<button ng-click="functionFromParent({function1: myfn, x:5, z: 4})"></button>.

это просто выражение, неважно, является ли это функцией или многими функциями, или просто сравнением. И вы можете заменить любую переменную этого выражения.

Примеры:
шаблон директивы против вызываемого кода:
parent определил $scope.x, $scope.y:
родительский шаблон: <myDirective expr="x==y"></myDirective>
<button ng-click="expr()"></button> вызывает $scope.x==$scope.y
<button ng-click="expr({x: 5})"></button> звонки 5 == $scope.y
<button ng-click="expr({x:5, y:6})"></button> вызывает 5 == 6

родитель определил $scope.function1, $scope.x, $scope.y:
родительский шаблон: <myDirective expr="function1(x) + y"></myDirective>

<button ng-click="expr()"></button> звонки $scope.function1($scope.x) + $scope.y
<button ng-click="expr({x: 5})"></button> звонки $scope.function1(5) + $scope.y
<button ng-click="expr({x:5, y:6})"></button> звонки $scope.function1(5) + 6
директива имеет $scope.myFn как функцию:
<button ng-click="expr({function1: myFn, x:5, y:6})"></button> вызывает $scope.myFn(5) + 6

0

@связывает свойство области локального/директива с оцененным значением атрибута DOM. = привязывает свойство области локальной/директивы к свойству родительской области. & binding - это передача метода в область вашей директивы, чтобы его можно было вызвать внутри вашей директивы.

@Связывание строки атрибута = привязка двухсторонней привязки и привязка метода обратного вызова

0

@Связывание строки атрибута (в одну сторону) = Двусторонняя привязка к модели & Амп; Связывание метода обратного вызова

0

Почему мне нужно использовать "{{title}}" с "@" и "title" с помощью "="?

Когда вы используете {{title}}, для представления и оценки директивы будет передано только значение родительской области. Это ограничивается одним способом, что означает, что изменение не будет отражено в родительской области. Вы можете использовать '=', если хотите также отразить изменения, внесенные в директиву child в родительскую область. Это два пути.

Могу ли я также напрямую обращаться к родительской области, не украшая мои элемент с атрибутом?

Когда директива имеет в ней атрибут scope (scope: {}), вы больше не сможете напрямую обращаться к родительской области. Но все же можно получить доступ к нему через scope. $Parent и т.д. Если вы удалите область из директивы, к ней можно получить доступ напрямую.

В документации говорится: "Часто желательно передавать данные из изолированный объем через выражение и родительскую область", но это похоже, отлично работает с двунаправленным связыванием. Почему путь выражения лучше?

Это зависит от контекста. Если вы хотите вызывать выражение или функцию с данными, вы используете, и если вы хотите использовать общие данные, вы можете использовать метод biderectional, используя '='

Вы можете найти различия между несколькими способами передачи данных в директиву по ссылке ниже:

AngularJS - изолированные области - @vs = vs &

http://www.codeforeach.com/angularjs/angularjs-isolated-scopes-vs-vs

Ещё вопросы

Сообщество Overcoder
Наверх
Меню