zoukankan      html  css  js  c++  java
  • JavaScript设计模式

    策略模式: 定义一系列算法,把他们一个一个封装起来,并且使他们可以相互替换(具有相同的目标和意图)
    示例
    我是 div

    策略模式指的是定义一些列的算法,把他们一个个封装起来,目的就是将算法的使用与算法的实现分离开来。
    以策略模式的思路实现上边例子的效果的js代码:
    1. 首先封装移动节点的缓动算法
     1 /*
     2  * 缓动算法: 接收4个参数,分别表示: 动画已消失的时间, 小球原始位置, 小球目标位置, 动画持续的总时间
     3  */
     4 var tween = {
     5     linear: function(t, b, c, d){
     6         return c*t/d + b;
     7     },
     8     easeIn: function(t, b, c, d){
     9         return c * ( t /= d ) * t + b;
    10     },
    11     strongEaseIn: function(t, b, c, d){
    12         return c * ( t /= d ) * t * t * t * t + b;
    13     },
    14     strongEaseOut: function(t, b, c, d){
    15         return c * ( ( t = t / d -1 ) * t * t * t * t + 1 ) + b;
    16     },
    17     sineaseIn: function(t, b, c, d){
    18         return c * ( t /= d ) * t * t + b;
    19     },
    20     sineaseOut: function(t, b, c, d){
    21         return c * ( ( t = t / d -1 ) * t * t + 1 ) +b;
    22     }
    23 };
    
    

      2. HTML 部分

     1     <div style="position: relative;border: 1px solid #ff0000;  560px;min-height: 30px">
     2         <div style="position:absolute;background:rgba(0,0,255,.3); 60px;line-height: 30px;" id="div">我是 div</div>
     3     </div>
     4     <div>
     5         <label><input type="radio" name="tween" value="linear" checked="checked">linear</label>
     6         <label><input type="radio" name="tween" value="easeIn">easeIn</label>
     7         <label><input type="radio" name="tween" value="strongEaseIn">strongEaseIn</label>
     8         <label><input type="radio" name="tween" value="strongEaseOut">strongEaseOut</label>
     9         <label><input type="radio" name="tween" value="sineaseIn">sineaseIn</label>
    10         <label><input type="radio" name="tween" value="sineaseOut">sineaseOut</label><br/>
    11         <input type="button" id="btnRun" value="run">
    12     </div>
    View Code
     3. 定义一个构造函数接收一个参数:即将运动起来的dom节点
     1 /*
     2  *    Animate 的构造函数接收一个参数:即将运动起来的 dom 节点。
     3  */
     4 var Animate = function( dom ){
     5     this.dom = dom; // 进行运动的 dom 节点
     6     this.startTime = 0; // 动画开始时间
     7     this.startPos = 0; // 动画开始时, dom 节点的位置,即 dom 的初始位置
     8     this.endPos = 0; //
     9     this.propertyName = null; // dom 节点需要被改变的 css 属性名
    10     this.easing = null; // 缓动算法
    11     this.duration = null; // 动画持续时间
    12 };
    
    
    
     4. 启动方法,负责启动这个动画
     1 /*
     2  * 负责启动运动动画
     3  */
     4 Animate.prototype.start = function( propertyName, endPos, duration, easing ){
     5     this.startTime = +new Date; // 启动动画的时间
     6     this.startPos = this.dom.getBoundingClientRect()[ propertyName ]; // dom 节点的初始位置
     7     this.propertyName = propertyName; // dom 节点需要被改变的 CSS 属性名
     8     this.endPos = endPos; // dom 节点的目标位置
     9     this.duration = duration; // 动画的持续时间
    10     this.easing = tween[ easing ]; // 缓动算法
    11 
    12     // 启动动画定时器
    13     var self = this;
    14     var timeId = setInterval(function(){
    15         if( self.step() === false){
    16             clearInterval(timeId);
    17         }
    18     },20);
    19 };
    
    
    
      5. 动画定时器运行的步骤,setp方法,节点运动的每一帧要做的事情
    /*
     * step 表示节点运动的每一帧要做的事情。 负责计算节点的当前位置和调整更新 CSS 属性值
     */
    Animate.prototype.step = function(){
        var t = +new Date; // 取得当前时间
        if( t >= this.startTime + this.duration){ // 如果动画结束
            this.update( this.endPos ); // 更新节点的 CSS 属性
            return false;
        }
        var pos = this.easing( t - this.startTime, this.startPos, this.endPos - this.startPos, this.duration);
        // pos 为节点当前位置
        this.update( pos ); // 更新节点的 CSS 属性
    };
    
    
    
     6. 更新节点的CSS属性值
    1 /*
    2  * 负责更新节点 CSS 属性值
    3  */
    4 Animate.prototype.update = function(pos){
    5     this.dom.style[ this.propertyName ] = pos + "px";
    6 };
    
    
    
     7. 测试运行
        /*
         * 创建要运动的节点
         */
        var div = document.getElementById("div");
        var animate = new Animate(div);
        // 设置运行事件
        var btnRun = document.getElementById("btnRun");
        var radios = document.getElementsByName("tween"); // 获取单选框
        btnRun.onclick = function(){
            for(var i= 0,lengh=radios.length;i<lengh;i++){
                // 查找被选中要执行的算法策略
                if(radios[i].checked){
                    animate.reset(); // 重置节点运动属性
                    // 设置动画的基本属性
                    animate.start( "left", 500, 1000, radios[i].value);
                    break;
                }
            }
        };
    
    
    
      8. 重置节点的CSS属性为0,reset()方法
    Animate.prototype.reset = function(){
            // 重置为 0
        this.dom.style[this.propertyName] = "0px";
    };
    
    
    
    策略模式总结:
    策略模式的优点:
      1. 策略模式利用组合、委托和多态等技术和思想,可以有效地避免多重条件选择语句
      2. 策略模式提供了对开放-封闭原则的完美支持,将算法封装在独立的 strategy 中,使得它们易于切换,易于理解,易于扩展
    策略模式的缺点:
      1. 会在程序中增加许多策略类或者策略对象,但实际上比把他们负责的逻辑堆砌在 Context 中要好
      2. 使用策略模式,必须了解所有的策略,才能更好的选择一个合适的策略

    阅读参考书籍 - << JavaScript 设计模式与开发实践 >>
    缓动算法 - javascript Tween算法及效果




  • 相关阅读:
    对List 集合中元素进行排序
    webSocket 中使用 @Autowired 注入对应为null
    警告:添加非被动事件侦听器到滚动阻塞'touchstart'事件(Added non-passive event listener to a scroll-blocking 'touchstart' event. Consider marking event han)
    在webpack中使用monaco-editor
    vue下使用Monaco Editor
    前端开发Docker快速入门(二)制作镜像并创建容器
    微信开放平台-第三方平台代小程序实现业务
    微信开放平台-第三方平台授权流程及接口概述
    MyBatis实现动态排序方法
    IDEA中下载Git项目时输错密码的解决方法
  • 原文地址:https://www.cnblogs.com/Medeor/p/5001841.html
Copyright © 2011-2022 走看看