Angular指令实现原型

时间:2014-01-22 23:34:52

标签: angularjs coffeescript angularjs-directive prototype

我正在尝试在canvas中使用angular指令实现我的游戏,但我无法弄清楚如何实现我的类“原型”

我的代码是在coffeeScript中,但javascript不是问题:)

我的指示:

angular.module("tetris", []).directive("tetris", ($timeout) ->
 restrict: "E"
 transclude: true
 scope: {}
 link: ($scope, $element, $log) ->
  game = new Game($element.children()[0],$element.children()[1],$element.children()[2])
  game.initGame()
   document.onkeydown=(e)->
    game.keyDown(e);
   document.onkeyup=(e)->
    game.keyUp(e);
  return
 template:"<div class=\"row relative\" id=\"canvas\">"+
 "<canvas class=\"absolute\" width=\"120\" height=\"250\" style=\"z-index:1\">"+
 "Your browser is not supporting canvas"+
 "</canvas>"+
 "<canvas class=\"absolute\" width=\"120\" height=\"250\" style=\"z-index:2\"></canvas>"+
 "<canvas class=\"absolute\" width=\"120\" height=\"250\" style=\"z-index:3\"></canvas>"+
 "</div>"
 replace: true
)

这是我的eventHandler类,我想实现指令只是将变量和事件提升到范围。这个类是从Game类调用的。

基本上我想将变量从Game原型提升到指令的父范围

class EventHandler
 constructor:->
  @scoreElm = document.getElementById('score')
  @levelElm = document.getElementById('level')
  @bombElm = document.getElementById('bomb')
  @nextElm = document.getElementById('next')

 updateScore:(score)->
  @scoreElm.innerHTML=score

 setBombCountDown:(time)->
  @bombElm.style.display.block
  @bombElm.innerHTML=time

 hideBombCountDown:->
  @bombElm.style.display.none

//编辑:

我想出了怎么做,但我觉得这不是一个正确的方法。你有什么建议怎么做得更好吗?

angular.module("tetris", []).directive("tetris", ($timeout) ->
  restrict: "E"
  transclude: true
  scope: false
  link: ($scope, $element, $log) ->
    class EventHandler
      updateScore:(score)->
        $scope.score = score
        $scope.$apply()

      setBombCountDown:(time)->
        $scope.bombTime=time
        $scope.$apply()

      hideBombCountDown:->
        $scope.bombTime=null
        $scope.$apply()

    game = new Game($element.children()[0],$element.children()[1],$element.children()[2],EventHandler)
    game.initGame()
    document.onkeydown=(e)->
      game.keyDown(e);
    document.onkeyup=(e)->
      game.keyUp(e);
    return

  template:"<div class=\"row relative\" id=\"canvas\">"+
  "<canvas class=\"absolute\" width=\"120\" height=\"250\" style=\"z-index:1\">"+
  "Your browser is not supporting canvas"+
  "</canvas>"+
  "<canvas class=\"absolute\" width=\"120\" height=\"250\" style=\"z-index:2\"></canvas>"+
  "<canvas class=\"absolute\" width=\"120\" height=\"250\" style=\"z-index:3\"></canvas>"+
  "</div>"
  replace: true
)

1 个答案:

答案 0 :(得分:1)

现在你的指令通过直接向其添加任意成员来操纵其父作用域,这在你的指令和外部世界之间创建了一种隐式接口。这种方法容易出错,很难维护。

解决方案

在构建可重用指令时,通常使用isolate scope通过指令元素上的属性公开其成员。这样,父作用域可以决定将哪个属性与指令的成员绑定。

作为一个例子来说明这一点,以下是如何重构tetris指令:

.directive('tetris', function ($timeout) {
    return {
        restrict: 'E',
        scope: {
            score: '=',
            bombTime: '='
        },
        link: function (scope, el) {
            // Same code as in your example
        }
    };
};

这里的主要区别是范围是isolate(意味着我们的指令无法“污染”父范围)并且我们将scorebombTime属性绑定到我们的指令的dom元素上的属性,父作用域可以安全访问。

注意 - 似乎没有理由使用transclude: true,因为您的指令没有将父视图提供给它的内容合并到任何行为中方式。

现在使用该指令如下所示:

<tetris score="myScore" bomb-time="myBombTime"></tetris>
<span>Score: {{myScore}}</span>
<span>Time: {{myBombTime}}</span>

现在,您的指令的用户可以选择与此游戏中的scorebombTime属性(myScoremyBombTime相关联的范围成员,以说明他们属于父范围)。

结论

虽然这种编写指令的方法起初可能看起来过于冗长,但是如果您计划更改指令所在页面的结构,将指令放入已经设置了不同范围成员的页面,这一点很重要。保持分数和时间,或者你打算为你的代码编写单元测试。