angularJS指令实战,制作一个可复用的幻灯组件(二)

上一篇文章介绍了ngSlide插件,接下来就该为大家介绍它是如何被制作出来的了。

指令

我们看到这个插件的基本用法就是

那么这里的slider是angularJs中的指令名,指令是用来做HTML扩展的,我在上一文的示例




  • 标题





  • 标题





  • 标题



  • 中并没有写ul,但它实际上在浏览器里的运行效果却是这样的





    • 标题





    • 标题





    • 标题




    那么多出来的这些代码就是由angular的指令生成的了,创建一个js文件,命名为ngSlide.js,书写代码如下:

    angular.model("ngSlide",[])
    .directive("slider",[function(){
    return{
    restrict: 'A',
    replace: true,
    template:"" +
    "

    " +
    '
      ' +
      "
      "
      }
      }])
      这里ngSlide的是你的ng-app名,restrict指的是指令的声明方式,其实A是指属性方式,如果将其定义为E的话会更加语义化,可以这样调用

      但是因为这种方式对IE6和7不太友好,所以我写成了A,replace则是指是否覆盖你声明指令的代码,template就是你要覆盖的代码了,
      拥有了这段代码以后,你只要在你的index.html中写如下代码:







      就会自动被浏览器渲染成



        transclude

        接下来还要生成那些li,因为图片的地址和上面的文字每次使用插件的时候是不一样的,这是属于“配置”的一部分,这些应该被放在声明里面.将index.html改为






      • 标题





      • 标题





      • 标题






      • 刷新浏览器,...什么都没有发生,因为浏览器并不知道要将这些li插入到模板的什么地方去,这时就需要用到我们的transclude了。将ngSlide.js修改为

        angular.model("ngSlide",[])
        .directive("slider",[function(){
        return{
        restrict: 'A',
        replace: true,
        transclude:true,
        template:"" +
        "

        " +
        '
          ' +
          "
          "
          }
          }])

          这里就很简单明了啦,当浏览器看到transclude声明时就会去寻找模板里带ng-transclude的地方把声明中带的标签包含进去。至此ngSlide的HTML部分就渲染完毕了。

          幻灯效果

          接下来还需要为ngSlide制作幻灯切换效果,最好的办法是用css动画自己重写一遍,因为angualr的watch机制能让你减少很多代码,不过因为想要快一点搭建完自己的UI库以及兼容IE8所以我选择了我常用的一个jquery幻灯插件SuperSlide。虽然这样会让这部分代码显得有点“脏”(原则上来说angular项目是不推荐引入jquery的)

          scope

          angular不允许在控制器中操作DOM,而幻灯动画这种事情就是赤裸裸的DOM操作了,它必须写在drective里面,通常来说我调用我的jquery插件时是这样的

          $(id).slide({mainCell:ulid});

          可以看到我需要2个参数,一个是幻灯最外层div的id,一个是ul的id,而ul是由angular自动生成的,我决定只让用户输入外层id一个参数就可以了,这时需要用到directive的scope,修改ngSlide.js代码如下

          angular.model("ngSlide",[])
          .directive("slider",[function(){
          return{
          restrict: 'A',
          replace: true,
          scope:{
          id:"@id"
          },
          transclude:true,
          template:"" +
          "

          " +
          '
            ' +
            "
            "
            }
            }])

            id:"@id"指的是把指令中的id属性赋值给scope.id,当用户再HTML中输入以下代码时

            scope.id就会自动被复制为slideid,这时需要的参数都有了,那么原则上来讲我只要在directive里面调用我的jquery插件就可以完成这个伟业了。修改ngSlide.js代码如下:

            angular.model("ngSlide",[])
            .directive("slider",[function(){
            return{
            restrict: 'A',
            replace: true,
            scope:{
            id:"@id"
            },
            transclude:true,
            template:"" +
            "

            " +
            '
              ' +
              "
              ",
              link:function(elem,scope,attr){
              var id = "#" + scope.id
              var ulid = id + "ul";
              $(id).slide({mainCell:ulid});
              }
              }
              }])

              刷新浏览器,运行,。。。。什么变化都没有,这里有一个深坑,原因我们来做一下实验,在link函数里面把elem给输出出来看一下:

              console.log(elem[0].innerHTML);

              结果如下:





              • 标题





              • 标题





              • 标题




              注意这个id="{{ulid}}",在这里ul的id数据根本就没有被渲染出来,在angular中model的渲染完成是在directive的link函数执行以后的。这可就愁白了我的头发了,如果使用$timeout的话因为用户的网速不一致我并不知道要延迟多久再加载这段代码,而angular偏偏没有提供directive加载完成的事件,这个问题足足困扰了我3天。

              解决方案

              这个问题的正解是将jquery插件用一个不设定参数的$timeout给包裹起来,这样就一定会在id值被渲染出来以后才执行它,造成这种情况的原因是js是阻塞运行的,$timeout只会在空闲时才会执行里面的代码,修改ngSlide代码如下:

              angular.model("ngSlide",[])
              .directive("slider",['$timeout',function($timeout){
              //别忘了依赖注入
              return{
              restrict: 'A',
              replace: true,
              scope:{
              id:"@id"
              },
              transclude:true,
              template:"" +
              "

              " +
              '
                ' +
                "
                ",
                link:function(elem,scope,attr){
                $timeout(function(){
                var id = "#" + scope.id
                var ulid = id + "ul";
                $(id).slide({mainCell:ulid});
                })

                }
                }
                }])

                至此程序就能正常运行了,当然接下来还要做少许的配置,例如说插件需要向左向右的箭头该怎么办呀,这部分的代码大家可以移步我的github查看,https://github.com/RenShine/ngSlide。下一篇文章我将会介绍这个插件的SCSS部分是如何实现的

                angularJS指令实战,制作一个可复用的幻灯组件(一)

                posted @ 2014-10-15 13:53  RenShine  阅读(1794)  评论(0)    收藏  举报