角指令中link和controller作用域共享的混淆

Confusion on scope sharing in angular directive between link and controller

本文关键字:共享 作用域 controller 指令 link      更新时间:2023-09-26

我理解下面的代码有点困难

HTML

 <div my-example max="77"></div>
指令

        angular
            .module('app')
            .directive('myExample', myExample);
        function myExample() {
            var directive = {
                restrict: 'EA',
                templateUrl: 'app/feature/example.directive.html',
                scope: {
                    max: '='
                },
                link: linkFunc,
                controller: ExampleController,
                controllerAs: 'vm',
                bindToController: true // because the scope is isolated
            };
            return directive;
            function linkFunc(scope, el, attr, ctrl) {
                console.log('LINK: scope.min = %s *** should be undefined', scope.min);
                console.log('LINK: scope.max = %s *** should be undefined', scope.max);
                console.log('LINK: scope.vm.min = %s', scope.vm.min);
                console.log('LINK: scope.vm.max = %s', scope.vm.max);
            }
        }
        ExampleController.$inject = ['$scope'];
        function ExampleController($scope) {
            // Injecting $scope just for comparison
            var vm = this;
            vm.min = 3;
            console.log('CTRL: $scope.vm.min = %s', $scope.vm.min);
            console.log('CTRL: $scope.vm.max = %s', $scope.vm.max);
            console.log('CTRL: vm.min = %s', vm.min);
            console.log('CTRL: vm.max = %s', vm.max);
        }
HTML

        <!-- example.directive.html -->
        <div>hello world</div>
        <div>max={{vm.max}}<input ng-model="vm.max"/></div>
        <div>min={{vm.min}}<input ng-model="vm.min"/></div> 

为什么scope.vm.min定义在linkFunc中?link函数是否共享控制器的作用域?尽管如此,为什么vm不像$scope.vm = vm那样进行显式赋值就自动添加到作用域?

vm存储在控制器的$作用域中。使用这个in指令,我们使用scope而不是$scope。因此,在这种情况下,由于'vm'是控制器的$作用域,它与指令的作用域相同。链接通过在linkFunc的参数中传递作用域来使用它。当指令使用控制器时,同样的作用域被传递给link函数。因此,我们可以直接使用scope.vm.min和其他任何东西。我希望你能理解。

强烈建议你学习指令的基础知识http://www.sitepoint.com/practical-guide-angularjs-directives/

vm什么也不是但是你必须使用controlleras语法所以它们的意思是

作为控制器

的实例

由于指令配置中的controllerAs语法,vm会自动添加到作用域。

return {
    controller: Controller
    controllerAs: 'vm'
};

controllerAs语法创建控制器函数的实例,this对象上的所有内容将通过controllerAs值中给定的别名暴露在作用域中。vm存在于您的link函数中,因为在您的控制器和您的链接函数中,您的指令具有相同的$scope。它不是"共享的",但它是相同的。当编译指令时,它会接收到一个新的$作用域。在编译时,控制器出现并将一些信息附加到作用域。当指令完全呈现时,link函数启动,并在函数的参数中提供相同的$scope。这就是为什么您可以访问link函数中的vm。不管你在视图中声明了什么,比如ng-model=vm.min,它也会附在作用域的vm上。

Angular编译你的指令时所发生的事情的一个更直观的表示(大概):

// First step preparing the new scope and the directive configuration
var $newScope = $rootScope.$new(true); // true for isolated scope
var directiveConfig = {
   controller: Controller,
   controllerAs: 'vm',
   link: function(scope, elem) { ... }
}
// Attaching the new controller instante to your new scope
$newScope[directiveConfig.controllerAs] = new directiveConfig.controller();
// At this point, we have the scope.vm
//Compile the directive to recieve the rendered element attach to the DOM
var elem = $compile('<my-directive></my-directive')($newScope);
// At this point, our scope.vm now contains scope.vm min and scope.vm.max because of the ng-model
// Call the link function with the newScope and the newly renrered element
directiveConfig.link.call(null, $newScope, elem);