写一个* wrapper *指令声明为AngularJS

时间:2013-02-09 02:03:23

标签: angularjs angularjs-directive

我正在使用AngularJS和Reveal.js创建幻灯片。显示需要表格

<div class="slides">
    <section>
    </section>
</div>

用于水平幻灯片。垂直幻灯片有两个部分:

<div class="slides">
    <section>
        <section>
        </section>
    </section>
</div>

我使用angular渲染此页面:                                      

<div ng-app='myApp' class="reveal">
    <div class="slides" ng-controller='MyController'>
        <section slide ng-repeat="slide in slides">
        </section>
    </div>
</div>

<script src="https://raw.github.com/hakimel/reveal.js/master/js/reveal.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.js"></script>
</body>
</html>

多个步骤的幻灯片应该是垂直的。所有其他人应该是横向的。控制器返回步骤并设置Reveal:

function MyController($scope) {
    $scope.slides = [
        { 'steps': ['a'] },
        { 'steps': ['b1', 'b2'] },
        { 'steps': ['c1'] }
    ];
    setTimeout(function() {
            Reveal.initialize({
                loop: false,
                transition: Reveal.getQueryHash().transition || 'none'
            });
    }, .1 * 1000);
}

该指令需要在步骤周围添加新元素和属性。这是我的丑陋,令人尴尬,命令式的jQuery指令:

app.directive('slide', function () {

var wrapContent = function (content) {
    return '<h1>' + content + '</h1>';
};

return {
    restrict: 'A'
    ,link: function (scope, element, attrs, controller) {
    // resorting to imparative jQuery way
    if (scope.slide.steps.length == 1) {
        element.html(
        wrapContent(scope.slide.steps[0])
        );
    } else {
        var sections = '';
        for (i=0,len=scope.slide.steps.length; i < len; ++i) {
        sections +=
            '<section ' +
            function () {
            result = '';
            if (i !== len-1) {
                result = 'data-autoslide="1000" ';
            }
            return result;
            }() +
            '>' +
            wrapContent(scope.slide.steps[i]) +
            '</section>';
        }
        element.html(sections);
    }
    }
}
});

我怎么写这个看起来像角度代码? jsfiddle

我尝试编译,链接,替换,ng-switch都无济于事。

1 个答案:

答案 0 :(得分:3)

由于您在范围内的slides属性中定义了所有部分,因此我可能会将整个幻灯片显示为指令。

<div ng-app='myApp' class='reveal' ng-controller='MyController'>
  <div slideshow='slides'></div>
</div>

在指令本身内部,我将迭代每个幻灯片并创建一个<section>元素。对于每张幻灯片,迭代步骤并创建<section>元素(如果有多个)或<h1>元素(如果只有一个)。它可能看起来像这样:

for (var i = 0; i < slides.length; i++) {
  var section = angular.element("<section>");
  var steps = scope.slides[i].steps;

  if (steps.length == 1) {
    var content = angular.element("<h1>").html(steps[0]);
    section.append(content);
  } else {
    for (var j = 0; j < steps.length; j++) {
      var subSection = angular.element("<section>");
      if (j < steps.length - 1)
        subSection.attr('data-autoslide', '1000');
      var content = angular.element("<h1>").html(steps[j]);
      subSection.append(content);
      section.append(subSection);
    }
  }
}

然后,您可以将section附加到指令的元素。因为,在指令中,我们知道DOM是在构建完成的,我们可以将调用Reveal.initialize从控制器(通常不是最好的想法来进行DOM操作或库调用)转移到指令中本身。

将所有内容与一些小修改结合在一起,您最终可能会在此jsFiddle中找到代码:http://jsfiddle.net/BinaryMuse/CXqAb/

虽然您可能在指令中以更具声明性的方式编写此代码,但我认为这可能更具可读性,并且当与第二方库(如Reveal)集成时期望某个DOM结构时,会导致更容易的时间创建一个可预测且干净的DOM结构,而不是使用一堆DOM元素,其中ngShowngSwitch分散在其中。