博客

  • 仿妙味课堂超炫导航效果

    浏览妙味官网,发现了不少绚丽的特性,尤其右侧那个菜单,简直太美了,忍不住扒下来,留着研究~有意的同学可以去妙味官网查看:http://www.miaov.com/

    菜单效果如下:

    20150206173413

    https://sdeno.com/zp/good_nav/1.html

  • AngularJS自定义指令directive()

    angular创建自定义指令使用directive()例如:

    var app = angular.module('myapp',[]);
      app.directive('helloWorld',function(){
         return {
           restrict: 'AE',  //推荐使用A
           replace: true,   //template会覆盖掉自定义标签
           template: '<h3>Hello World!</h3>' //自定义标签要显示的内容
         }
    });

    创建出来的便签推荐使用<div hello-world></div>

    第一个参数是指令的名称

    第二个参数是一个返回指令定义对象的函数。如果你的指令对额外的对象/服务(services)例如 $rootScope, $http 或者 $compile 有依赖,它们也可以在其中被注入。

     

    link函数和作用域

    link函数是负责操作DOM元素,例如:

    app.directive('helloWorld',function(){
        return {
            restrict: 'AE',   
            replace: true,
            template: '<p></p>',   
            link: function(scope,elem,attr){
                elem.bind('click',function(){
                    elem.css('background-color','white');
                scope.$apply(function(){
                    scope.color = "white";
                });
                });
                elem.bind('mouseover',function(){
                    elem.css('cursor','pointer');
                });
            }
        }
    });   

    注意到link函数被用在了指令中。它接收三个参数:

    • scope – 它代表指令被使用的作用域。在上面的例子中它等同于符控制器的作用域。
    • elem – 它代表绑定指令的元素的jQlite(jQuery的一个自己)包裹元素。如果你在AngularJS被包含之前就包括了jQuery,那么它将变成jQuery包裹元素。由于该元素已经被jQuery/jQlite包裹,我们没有必要将它包含在$()中来进行DOM操作。
    • attars – 它代表绑定指令的元素上的属性。例如,如果你在HTML元素上有一些指令形式为:<hello-world some-attribute></hello-world>,你可以在link函数内用attrs.someAttribute来引用这些属性。

    link函数主要是用来对DOM元素绑定事件监听器,监视模型属性变化,并更新DOM。在前面的指令代码中,我们绑定了两个监听器,click和mouseover。click处理函数重置了

    的背景颜色,而mouseover处理函数则将游标改变为pointer。模板中拥有表达式{{color}},它将随着父作用域中的模型color的变化而变化,从而改变了Hello World的背景色。

    Compile函数

    Compile函数主要用来在link函数运行之前进行一些DOM转化。它接收下面几个参数:

    • tElement – 指令绑定的元素
    • attrs – 元素上声明的属性

    这里要注意compile不能够访问scope,而且必须返回一个link函数。但是,如果没有compile函数以依然可以配置link函数。compile函数可以被写成下面的样子:

    app.directive('test',function(){
        return {
            compile: function(tElem,attrs){
                //在这里原则性的做一些DOM转换   
                return function(scope,elem,attrs){
                 //这里编写link函数
                }
            }
        }
    });   

    什么时候使用compile?

    大多数时候,你仅仅只需要编写link函数。这是因为大部分指令都只关心与注册事件监听器,监视器,更新DOM等等,它们在link函数中即可完成。像是ng-repeat这样的指令,需要多次克隆并重复DOM元素,就需要在link函数运行之前使用compile函数。你可能会问威慑呢么要将两个函数分别使用。为什么我们不能只编写一个函数?为了回答这个问题我们需要理解Angular是如何编译指令的!

     

    指令是如何被编译的

    当应用在启动时,Angular开始使用$compile服务解析DOM。这项服务会在标记中寻找指令然后将它们各自匹配到注册的适龄。一旦所有的指令都已经被识别完成,Angular就开始执行它们的compile函数。正如前面所提到的,compile函数返回一个link函数,该函数会被添加到稍后执行的link函数队列中。这叫做编译阶段(compile phase)。注意到即使同一个指令有几个实例存在,compile函数也只会运行一次。

    在编译阶段之后就到了链接阶段(link phase),这时link函数就一个接一个的执行。在这个阶段中模板被生成,指令被运用到正确的作用域,DOM元素上开始有了事件监听器。不像是compile函数,lin函数会对每个指令的实例都执行一次。

    改变指令的作用域

    默认情况下指令应该访问父作用域。但是我们并不像对所有情况一概而论。如果我们对指令暴露了父控制器的scope,那么指令就可以自由的修改scope属性。在一些情况下你的指令可能想要添加一些只有内部可以使用的属性和函数。如果我们都在父作用域中完成,可能会污染了父作用域。因此,我们有两种选择:

    • 一个子作用域 – 这个作用域会原型继承父作用域。
    • 一个隔离的作用域 – 一个全新的、不继承、独立存在的作用域。

    作用域可以由指令定义对象中的scope属性定义。下面的例子展示了这一点:

    app.directive('helloWorld',function(){
        return {
            scope: true, //使用一个继承父作用域的自作用域   
            restrict: 'AE',
            replace: true,
            template: '<h3>Hello World!</h3>'
        }
    });   

    上面的代码要求Angular为指令提供一个能够原型继承父作用域的子组用于。另一种情形,一个隔离作用域,代码如下所示:

    app.directive('helloWorld',function(){
        return {
            scope: {}, //使用一个全新的隔离作用域   
            restrict: 'AE',
            replace: true,
            template: '<h3>Hello World!</h3>'
        }
    });

    上面的指令使用一个不继承父作用域的全新隔离作用域。当你想要创建一个可重用的组件时隔离作用域是一个很好的选择。通过隔离作用域我们确保指令是自包含的兵可以轻松地插入到任何HTML app中。这种做法防止了父作用域被污染,由于它不可访问父作用域。在我们修改后的helloWorld指令中如果你将scope设置为{},那么代码就不会再正常运行。它将创建一个隔离的作用域然后表达式{{color}}将无法引用隔离作用域中的属性因此值变为undefined。

    隔离作用域并不意味着你一点都不能获取到父作用域中的属性。有一些技巧可以使你访问父作用域中的属性同时监听这些属性的变化。我们将在下一篇文章中提到这种高级技巧。

  • $digest循环会运行多少次?

    $digest循环不会只运行一次。在当前的一次循环结束后,它会再执行一次循环用来检查是否有models发生了变化。这就是脏检查(Dirty Checking),它用来处理在listener函数被执行时可能引起的model变化。因此,$digest循环会持续运行直到model不再发生变化,或者$digest循环的次数达到了10次。因此,尽可能地不要在listener函数中修改model。

    $digest循环最少也会运行两次,即使在listener函数中并没有改变任何model。正如上面讨论的那样,它会多运行一次来确保models没有变化。

  • $apply()解释说明

    $apply()是用来告诉并提醒angular,在model上已经有更新了也请及时更新view。
    那么我们什么时候使用$apply()?
    例如:

    angular.module('myApp',[]).controller('MessageController', function($scope) { 
     
      $scope.getMessage = function() { 
         setTimeout(function() { 
          $scope.message = 'Fetched after 3 seconds'; 
          console.log('message:'+$scope.message); 
         }, 2000); 
      } 
      $scope.getMessage(); 
    
    });

    我们使用的是setTimeout方法更新$scope.message的值,同时也希望更新的值在view也及时刷新,但是用这种方法view是不能及时更新的。因为angular并不知道$scope.message有更新。

    这时候我们就使用$apply()了,将更改的数值写在$apply()里面,这样就能让angular知道$scope.message有变化也请及时更新view。例如:

    angular.module('myApp',[]).controller('MessageController', function($scope) { 
     
       $scope.getMessage = function() { 
          setTimeout(function() { 
            $scope.$apply(function() { 
              $scope.message = 'Fetched after 3 seconds'; 
              console.log('message:' + $scope.message); 
             }); 
          }, 2000); 
       } 
     
      $scope.getMessage(); 
     
     });

    如果是需要setTimeout()功能的话,其实推荐使用$timeout,因为它可以自动调用$apply()来提醒angular告诉有model变化了。

    总结:需要记住的最重要的是AngularJS是否能检测到你对于model的修改。如果它不能检测到,那么你就需要手动地调用$apply()。

  • pace.js网站加载页面进度条效果

    css3进度条效果

    打开页面进入网站都会有等待时间,在等待时间的过程中显示加载进度是友好的用户体验告诉用户还剩多久能完成。效果就跟本站顶部进度条一样。

    加载样式和pace.js

    .pace {
     -webkit-pointer-events: none;
     pointer-events: none;
    -webkit-user-select: none;
     -moz-user-select: none;
     user-select: none;
    z-index: 2000;
     position: fixed;
     margin: auto;
     top: 0;
     left: 0;
     
     height: 5px;
     width:100%;
     background: #fff;
     border: 1px solid #2299dd;
    overflow: hidden;
    }
    .pace .pace-progress {
     -webkit-box-sizing: border-box;
     -moz-box-sizing: border-box;
     -ms-box-sizing: border-box;
     -o-box-sizing: border-box;
     box-sizing: border-box;
    -webkit-transform: translate3d(0, 0, 0);
     -moz-transform: translate3d(0, 0, 0);
     -ms-transform: translate3d(0, 0, 0);
     -o-transform: translate3d(0, 0, 0);
     transform: translate3d(0, 0, 0);
    max-width: 100%;
     position: fixed;
     z-index: 2000;
     display: block;
     position: absolute;
     top: 0;
     right: 100%;
     height: 100%;
     width: 100%;
     background: #2299dd;
    }
    .pace.pace-inactive {
     display: none;
    }
    <script src="pace.min.js"></script>

    接着简单设置配置JS

    <script>
     function load(time){
      var x = new XMLHttpRequest()
      x.open('GET', "https://sdeno.com/" + time, true); //输入你需要显示进度的网站
      x.send();
     };
     load(20);
     load(100);
     load(500);
     load(2000);
     load(3000);
    setTimeout(function(){
      Pace.ignore(function(){
       load(3100);
      });
     }, 4000);
    Pace.on('hide', function(){
      console.log('done');
     });
     </script>

    http://github.hubspot.com/pace/docs/welcome/

     

    如果你使用AMD或者requirejs来加载模块的话,你可以通过这样子来设置(例如:start):

    define(['pace'], function(pace){
      pace.start({
        document: false
      });
    });

     

     http://github.hubspot.com/pace/

    简单中文:http://itfish.net/article/49094.html