使用ES6类作为Angular 1.x指令

Bou*_*tee 57 javascript class angularjs ecmascript-6 angularjs-directive

我正在做一个小项目来玩围绕ES6带来的好东西,我正在尝试将一个类设置为一个角度指令,但我遇到了这个错误"TypeError:不能将一个类称为函数"但是从示例中我发现他们只是编写类并将其作为指令注册角色.这是我的指示.

class dateBlock {
  constructor () {
    this.template = '/app/dateblock/dateblock.html';
    this.restrict = 'AE';
    this.scope = {};
  }
};

export default dateBlock
Run Code Online (Sandbox Code Playgroud)

和我的索引,我导入它,然后声明它.

import calendarController from './calendar/calendar.js'
import dateBlock from './dateblock/dateblock.js'

function setup($stateProvider) {
    $stateProvider
      .state('base', {
        url: '',
        controller: calendarController,
        templateUrl: '/app/calendar/calendar.html'
      });
    };

setup.$inject = ['$stateProvider']

var app = angular.module('calApp',['ngAnimate','ui.router','hmTouchEvents', 'templates'])
  .config(setup)
  .controller('calendarController', calendarController)
  .directive('dateBlock', dateBlock)
Run Code Online (Sandbox Code Playgroud)

如果我错过了一些关键的步骤,我很乐意听到它.另外一个问题是,将所有应用程序组件导入索引并在那里注册它们或导出应用程序并导入和注册组件更清晰吗?

小智 64

从我的角度来看,不需要使用像register.js这样的外部库,因为你可以用这种方式创建指令作为ES6类:

class MessagesDirective {
    constructor() {
        this.restrict = 'E'
        this.templateUrl = 'messages.html'
        this.scope = {}
    }

    controller($scope, $state, MessagesService) {
        $scope.state = $state;
        $scope.service = MessagesService;
    }

    link(scope, element, attrs) {
        console.log('state', scope.state)
        console.log('service', scope.service)
    }
}
angular.module('messages').directive('messagesWidget', () => new MessagesDirective)
Run Code Online (Sandbox Code Playgroud)

使用指令控制器允许您注入依赖项,即使没有附加声明(例如MessagesDirective.$inject = ['$scope', '$state', 'MessagesService']),因此如果需要,您可以通过作用域使用链接功能中的服务.

  • 为了记录,如果你使用`ng-annotate`,不要忘记用`ngInject`注释`controller`:`controller($ scope,$ state,MessagesService){'ngInject'; ...}`.只是说因为我浪费了2个小时,所以:惭愧: (5认同)
  • 没有过度设计和清晰.如果可以的话,我会更多地投票.谢谢. (3认同)

Mic*_*ley 48

正如评论中所提到的,该module.directive()方法需要工厂函数而不是构造函数.

最简单的方法是将类包装在返回实例的函数中:

angular.module('app')
    .directive('dateBlock', () => new DateBlock());
Run Code Online (Sandbox Code Playgroud)

但是,这只能在最有限的意义上工作 - 它不允许依赖注入,compile并且link指令的函数和函数(如果已定义)将无法按预期工作.

事实上,这是一个我已经广泛研究过的问题,事实证明这个问题相当棘手(至少对我而言).

我写了一篇涵盖我的解决方案的大量文章,但就您而言,我可以指出您对需要解决的两个主要问题的讨论:

  1. 将类定义动态转换为角度兼容的工厂函数

  2. 允许将指令linkcompile函数定义为类方法

我认为完整的解决方案涉及太多的代码粘贴在这里,但我已经整理了一个工作的演示项目,它允许您将指令定义为ES6类,如下所示:

class MyDirective {
    /*@ngInject*/
    constructor($interval) {
        this.template = '<div>I\'m a directive!</div>';
        this.restrict = 'E';
        this.scope = {}
        // etc. for the usual config options

        // allows us to use the injected dependencies
        // elsewhere in the directive (e.g. compile or link function)
        this.$interval = $interval;
    }

    // optional compile function
    compile(tElement) {
        tElement.css('position', 'absolute');
    }

    // optional link function
    link(scope, element) {
        this.$interval(() => this.move(element), 1000);
    }

    move(element) {
        element.css('left', (Math.random() * 500) + 'px');
        element.css('top', (Math.random() * 500) + 'px');
    }
}

// `register` is a helper method that hides all the complex magic that is needed to make this work.
register('app').directive('myDirective', MyDirective);
Run Code Online (Sandbox Code Playgroud)

在这里查看演示仓库,这里是代码register.directive()


bma*_*ggi 22

@Michael是对的钱:

module.directive()方法需要一个工厂函数

然而我用另一种技术解决了它,我认为它有点清洁,它对我来说很好,但它并不完美......我定义了一个静态方法,它返回一个模块所需的工厂()

class VineDirective {
    constructor($q) {
        this.restrict = 'AE';
        this.$q = $q;
    }

    link(scope, element, attributes) {
        console.log("directive link");
    }

    static directiveFactory($q){
        VineDirective.instance = new VineDirective($q);
        return VineDirective.instance;
    }
}

VineDirective.directiveFactory.$inject = ['$q'];

export { VineDirective }
Run Code Online (Sandbox Code Playgroud)

在我的应用程序中,我做:

angular.module('vineyard',[]).directive('vineScroller', VineDirective.directiveFactory)
Run Code Online (Sandbox Code Playgroud)

我相信没有其他方法可以使用类似于这样的黑客攻击的类+指令,只需选择容易的方法;-)


leg*_*80s 20

更简单,更清晰,更易读的解决方案.

class ClipBoardText {

  constructor() {
    console.log('constructor');

    this.restrict = 'A';
    this.controller = ClipBoardTextController;
  }

  link(scope, element, attr, ctr) {

    console.log('ctr', ctr);
    console.log('ZeroClipboard in link', ctr.ZeroClipboard);
    console.log('q in link', ctr.q);

  }

  static directiveFactory() {
    return new ClipBoardText();
  }
}

// do not $inject like this
// ClipBoardText.$inject = ['$q'];

class ClipBoardTextController {
  constructor(q) {
    this.q = q;
    this.ZeroClipboard = 'zeroclipboard';
  }
}

ClipBoardTextController.$inject = ['$q'];


export default ClipBoardText.directiveFactory;
Run Code Online (Sandbox Code Playgroud)

你不能得到$qlink功能,thislinkundefinednull.探索-ES6类合angularjs-1-X#_section-工厂

当Angular调用链接函数时,它不再在类实例的上下文中,因此.$ interval将是未定义的

因此,请使用controller指令中的函数,并在函数中注入要访问的依赖项或任何内容link.


Alo*_*lon 5

我的解决方案

class myDirective {
   constructor( $timeout, $http ) {
       this.restrict = 'E';
       this.scope = {};

       this.$timeout = $timeout;
       this.$http = $http;
   }
   link() {
       console.log('link myDirective');
   }
   static create() {
       return new myDirective(...arguments);
   }
}

myDirective.create.$inject = ['$timeout', '$http'];

export { myDirective }
Run Code Online (Sandbox Code Playgroud)

并在主app文件中

app.directive('myDirective', myDirective.create)
Run Code Online (Sandbox Code Playgroud)


小智 0

我有类似的问题。但就我而言,当我部署到生产环境时,它起作用了,但失败了。但它失败了,因为生产环境有最新版本的 6to5。这可以通过使用来防止npm shrinkwrap。根据最新的 ES6 规范,你不能使用这样的类。https://github.com/babel/babel/issues/700