就上一篇所说的,按道理应该先说说用三种方式(类式继承、原型式继承、掺元式继承)分别实现edit-in-place。懒得敲代码了,所以就用最常用的类式继承实现。其余两种方法就先不说了,如果大家都想看到的话,那我再修改,贴出来吧。最近需要准备实习,完善简历,大街网上得填写简历去,不知道博客园里面是否会有猎头看到这篇文章,那顺便宣传一下,大街网-搜索-哈尔滨工业大学-刘平,就可以找到我,如果大家有好的实习单位,也可以给我私信。

View Code
/**
 * @author tonylp
 */
function EditInPlaceField(id,parent,value){
    this.id = id;
    this.parentElement = parent;
    this.value = value || 'default value';
    
    this.createElements(this.id);
    this.attachEvents();
};

EditInPlaceField.prototype = {
    createElements:function(id){
        this.containerElement = document.createElement('div');
        this.parentElement.appendChild(this.containerElement);
        
        this.staticElement = document.createElement('span');
        this.containerElement.appendChild(this.staticElement);
        this.staticElement.innerHTML = this.value;
        
        this.fieldElement = document.createElement('input');
        this.fieldElement.type = 'text';
        this.fieldElement.value = this.value;
        this.containerElement.appendChild(this.fieldElement);
        
        this.saveButton = document.createElement('input');
        this.saveButton.type = 'button';
        this.saveButton.value = 'Save';
        this.containerElement.appendChild(this.saveButton);
        
        this.cancelButton = document.createElement('input');
        this.cancelButton.type = 'button';
        this.cancelButton.value = 'Cancel';
        this.containerElement.appendChild(this.cancelButton);
        this.convertToText();
    },
    attachEvents:function(){
        var that = this;
        addEvent(this.staticElement,'click',function(){that.convertToEditable();});
        addEvent(this.saveButton,'click',function(){that.save();});
        addEvent(this.cancelButton,'click',function(){that.cancel();});
    },
    convertToEditable:function(){
        this.staticElement.style.display = 'none';
        this.fieldElement.style.display = 'inline';
        this.saveButton.style.display = 'inline';
        this.cancelButton.style.display = 'inline';
        
        this.setValue(this.value);
    },
    save:function(){
        this.value = this.getValue();
        var that = this;
        var callback = {
            success:function(){that.convertToText();},
            failure:function(){alert('Error saving value.');}
        };
        ajaxRequest('get','save.php?id='+this.id+'&value='+this.value,callback);
    },
    cancel:function(){
        this.convertToText();
    },
    convertToText:function(){
        this.fieldElement.style.display = 'none';
        this.saveButton.style.display = 'none';
        this.cancelButton.style.display = 'none';
        this.staticElement.style.display = 'inline';
        
        this.setValue(this.value);
    },
    
    setValue:function(value){
        this.fieldElement.value = value;
        this.staticElement.innerHTML = value;
    },
    getValue:function(){
        return this.fieldElement.value;
    }
};

//要创建一个就地编辑域,只需要实例化这个类即可
var titleClassical = new EditInPlaceField('titleClassical',$('doc'),'Title Here');
var currentTitleText = titleClassical.getValue();

//接下来我们要创建一个使用多行文本框而不是单行文本框的类,这个EditInPlaceArea类,这个类继承了EditInPlaceField
function EditInPlaceArea(id,parent,value){
    EditInPlaceArea.superclass.constructor.call(this,id,parent,value);
};
extend(EditInPlaceArea,EditInPlaceField);
EditInPlaceArea.prototype.createElements = function(id){
        this.containerElement = document.createElement('div');
        this.parentElement.appendChild(this.containerElement);
        
        this.staticElement = document.createElement('p');
        this.containerElement.appendChild(this.staticElement);
        this.staticElement.innerHTML = this.value;
        
        this.fieldElement = document.createElement('textarea');
        this.fieldElement.type = 'text';
        this.fieldElement.value = this.value;
        this.containerElement.appendChild(this.fieldElement);
        
        this.saveButton = document.createElement('input');
        this.saveButton.type = 'button';
        this.saveButton.value = 'Save';
        this.containerElement.appendChild(this.saveButton);
        
        this.cancelButton = document.createElement('input');
        this.cancelButton.type = 'button';
        this.cancelButton.value = 'Cancel';
        this.containerElement.appendChild(this.cancelButton);
        this.convertToText();
};
EditInPlaceArea.prototype.convertToEditable = function(){
        this.staticElement.style.display = 'none';
        this.fieldElement.style.display = 'block';
        this.saveButton.style.display = 'inline';
        this.cancelButton.style.display = 'inline';
        
        this.setValue(this.value);
}
EditInPlaceArea.prototype.convertToText = function(){
        this.staticElement.style.display = 'block';
        this.fieldElement.style.display = 'block';
        this.saveButton.style.display = 'none';
        this.cancelButton.style.display = 'none';
        
        this.setValue(this.value);
}

      好了,可以进入正题了,到现在为止都还没有讲过一种特定的设计模式,那么接下来就重点探究一下这几种模式。这里一共会有单体模式、工厂模式、桥接模式、组合模式、门面模式、适配器模式、装饰者模式、享元模式、代理模式、观察者模式、命令模式、职责链模式12种模式。看情况不知道能说几种,按我的理解来说几种,如果没说完,大家可以去看看汤姆大叔的博客,我发现我现在成了他博客的推销者了。。额。。略有打广告之嫌。

     1.1 单体模式--javascript中最基本又最有用的模式之一

     通过确保单体对象只存在一份实例,你就可以确信自己的所有代码使用的都是同样的全局资源

     用途:划分命名空间,减少网页中全局变量的数目,利用分支技术来封装浏览器之间的差异,组织代码,模块化。

     单体模式基本结构

View Code
var Signleton = {
    attribute1:true,
    attribute2:10,
    method1:function(){
        
    },
    method2:function(){
        
    }
};

   单体对象由两部分组成:包含着方法和属性成员的对象自身,以及用于访问它的变量。这个变量通常是全局性的。

   1.2 划分命名空间

View Code
// GiantGorp namespace
var GiantGorp = {};
GiantGorp.Common ={
    // a signleton with common methods used by all objects and modules
};
GiantGorp.ErrorCodes = {
    // An object literal used to store data.
};

GiantGorp.PageHandler = {
    // a signleton with page specific methods and attributes.
};

    其实最好的学习办法是去看一个javascript的开源框架或是开源插件,例如jquery,dataTables,里面会有很多命名空间和私有方法,公开方法,你就可以研究它们。

  1.3 用作特定网页专用代码的包装器的单体

在拥有许多网页的网站中,有些javascript代码是所有网页都要用到的,它们通常被存放在独立的文件中;而有些代码则是某个网页专用道德,不会被用到其他地方。下面是用来包装特定网页专用代码的单体的骨架:

View Code
Namespace.PageName = {
    
    //Page Constants
    CONSTANT_1:true,
    CONSTANT_2:10,
    
    //Page methods
    method1:function(){
        
    },
    method2:function(){
        
    },
    //Initialization method.
    init:function(){
        
    }
}
addLoadEvent(Namespace.PageName.init);

 1.4 拥有私有成员的单体

       如果大家还记得话,在javascript设计模式探究【1】中,我就讲过用两种方法实现私有成员,下面给出一段模块模式代码(module pattern)--指的是它可以把一批相关方法和属性组织委模块并起到划分命名空间的作用。

View Code
MyNamespace.singleton =(function(){
    //private member.
    var privateAttribute1 = false;
    var privateAttribute2 = [1,2,3];
    function privateMethod1(){
        ...
    }
    function privateMethod2(){
        ...
    }
    return {
        publicAttribute1:true,
        publicAttribute2:10,
        
        publicMethod1:function(){
            ...
        },
        publicMethod2:function(){
            ...
        }
    }
})();

 1.5 惰性实例化--将实例化推迟到需要使用它的时候,惰性加载,常用于那些加载大量数据的单体。

View Code
MyNamespace.singleton =(function(){
    var uniqueInstance;
    function constructor(){
        //private member.
        var privateAttribute1 = false;
        var privateAttribute2 = [1,2,3];
        function privateMethod1(){
            ...
        }
        function privateMethod2(){
            ...
        }
        return {
            publicAttribute1:true,
            publicAttribute2:10,
            
            publicMethod1:function(){
                ...
            },
            publicMethod2:function(){
                ...
            }
        }
    }
    return {
        getInstance:function(){
            if(!uniqueInstance){
                uniqueInstance = constructor();
            }
            return uniqueInstance;
        }
    }
})();

   仔细比较一下1.4中的代码和1.5中的代码的区别

   说明:惰性加载单体的特别之处在于:对它们的访问必须借助于一个静态方法,应该这样调用其方法:Singleton.getInstance().methodName();getInstance方法会检查该单体是否已经被实例化了。惰性加载单体的缺点是其代码复杂。

 1.6 分支--用来把浏览器间的差异封装到运行期间进行设置的动态方法中的技术。

View Code
MyNamespace.singleton =(function(){
    var objectA ={
        method1:function(){
            
        }
        method2:function(){
            
        }
    }
    var objectB ={
        method1:function(){
            
        }
        method2:function(){
            
        }
    }
    return (someCondition)?objectA:objectB;
})();

    上述代码中创建了两个对象字面量,它们拥有相同的一套方法,通过条件检测,确保运行的代码是该javascript环境下所需要的特性。

     分支技术并不总是更高效的选择,前面的例子中,有两个对象被创建出来并保存在内存中,但是派上用场的只有一个。

  1.7 总结

        从为代码提供命名空间和增强器模块化的角度考虑,你应该尽量多的使用单体模式,尤其是在网页中包含着五花八门的javascript代码来源。分支技术可以创建高效的方法,不需要管浏览器的兼容性。单体模式提供一种单点访问,所以它有可能导致模块的强耦合,而且也不利于单元测试。单体模式是一个基础,为后面的各种模式的一个基础。

  以上全部都属个人原创,请大家转载的时候附上原创链接: http://www.cnblogs.com/tonylp

posted on 2013-03-27 17:33  tony_lp  阅读(1069)  评论(0编辑  收藏  举报