• 脚本用函数模拟类


    让我们先实现组件化的AutoFlex脚本:

    function AutoFlex(id,maxHeight)
    {    
        
    this._id = id;
        
    this.maxHeight = maxHeight;

    }


    AutoFlex.prototype._onPropertyChange 
    = function()
    {
        
    if(this.maxHeight)
         
    {
            
    this._element.style.height =
             ( 
    this._element.scrollHeight > this.maxHeight ) ? this.maxHeight : this._element.scrollHeight + this._element.offsetHeight - this._element.clientHeight;          

        }

        
    else
         
    {
            
    this._element.style.height = this._element.scrollHeight 
                
    + ( this._element.offsetHeight - this._element.clientHeight );

        }
      

    }


    AutoFlex.prototype._getPropertyChangeHandler 
    = function(){

        
    var obj = this;

        
    return function (){

            obj._onPropertyChange.call(obj);

        }


    }


    AutoFlex.prototype.initiate 
    = function(){

        
    this._element = document.getElementById(this._id);

        
    if(this._element)
        
    {
            
    this._element.onpropertychange = this._getPropertyChangeHandler();
        }


    }



    上面这段代码我们遵循这样的代码规范:
    (1)类名使用Pascal命名法,函数使用骆驼法,这一点很重要,因为JavaScript本没有类这个概念,我们使用Function模拟类,为了区别function定义的是类的概念还是函数的概念,我们使用不同的命名法。
    (2)类的属性在构造函数中定义和初始化,类的函数中通过prototype添加。
    (3)非对外的成员名使用_开头。
    *************************************************
    这段代码需要注意以下几点:
    (1)在JavaScript中,0相当于false,null也相当于false,所以我们只需判断if(this.maxHeight)就能覆盖没有传maxHeight参数和maxHeight参数为0的两种情况。
    (2)在附加事件响应程序时,我们不是直接写this._element.onpropertychange = this._onPropertyChange而是this._element.onpropertychange = this._getPropertyChangeHandler()。这是为什么呢?原来如果我们使用前一种写法,当_onPropertyChange方法被事件触发时,它的执行上下文,也就是this指针是指向触发事件的对象或window对象,这是JavaScript中事件的一个特别需要重视的特点,如果是这样的话,_onPropertyChange()方法中的代码将不能正确执行。在后一种写法中,我们通过JavaScript的闭包特性和Function.call()方法使得_onPropertyChange()方法在执行时能得到期待的this指针。
    ***************************************************

    注:闭包——函数始终可以使用定义它时在它外围的(即它可访问到的)变量,而无论它在何时执行。如上例的_getPropertyChangeHandler()方法中的代码,我们用obj变量保存this的指针,那么接下来定义的函数始终可以访问到obj变量,即使是在被事件触发时也是如此。call——Javascript中的Function原型上有两个功能类似的方法——call和apply,它们都用来执行当前函数,但被执行函数中的this指针指向call或apply方法的第一个参数,如上例中的obj._onPropertyChange.call(obj),这个语句被事件触发时指针this本来是指向window对象的,然而我们使用call方法使得_onPropertyChange方法内部的语句访问的this指针指向obj对象

    call方法和apply方法的区别在于传递参数的方式不同,call方法把第一个参数作为被调用方法的this指针,其余参数作为被调用方法的参数,apply也把第一个参数作为被调用方法的this指针,然后用一个数组把参数打包传给被调函数。如,myFunction.call(context,arg0,arg1,arg2)和myFunction.apply(context,[arg0,arg1,arg2]);

    准备好了组件化的脚本后,控件的实现变得非常简单:
    <%@ Register TagPrefix="cc1" Namespace="ClassLibrary1" Assembly="ClassLibrary1" %> 该指令注册自定义控件

    public class AutoFlexTextArea:TextBox

        
    {

            
    bool _supportJS;

            
    const string AUTOFLEXJS = @"

        function AutoFlex(id,maxHeight){

            this._id = id;

            this.maxHeight = maxHeight;

        }

        AutoFlex.prototype._onPropertyChange = function(){

            if(this.maxHeight){

                this._element.style.height =

                 ( this._element.scrollHeight > this.maxHeight ) ? this.maxHeight : 

                    this._element.scrollHeight 

    + ( this._element.offsetHeight - this._element.clientHeight);          

            }

            else{

                this._element.style.height = this._element.scrollHeight 

                    + ( this._element.offsetHeight - this._element.clientHeight );

            }  

        }

        AutoFlex.prototype._getPropertyChangeHandler = function(){

            var obj = this;

            return function (){

                obj._onPropertyChange.call(obj);

            }

        }

        AutoFlex.prototype.initiate = function(){

            this._element = document.getElementById(this._id);

            if(this._element){

                this._element.onpropertychange = this._getPropertyChangeHandler();

            }

        }
    ";

            [DefaultValue(
    0)]

            [Category(
    "Behavior")]

            [Description(
    "最大伸展高度")]

            
    public int MaxHeight
           
    {    
                get{
                    
    if (ViewState["MaxHeight"== null)
                    {    return 0;    }

                    
    return (int)ViewState["MaxHeight"];

                }

               
    set{
                       ViewState["MaxHeight"= value;

                }


            }


            [DesignerSerializationVisibility

                        (DesignerSerializationVisibility.Hidden)]

            [Browsable(
    false)]

            [EditorBrowsable(EditorBrowsableState.Advanced)]

            
    public override TextBoxMode TextMode

            
    {

                
    get

                
    {

                    
    return TextBoxMode.MultiLine;

                }


                
    set

                
    {

                    
    throw new NotSupportedException(

    "Can not change the TextMode property");

                }


            }


            
    void DetermineJS()

            
    {

                
    if (!DesignMode)

                
    {

                    
    if (Page.Request.Browser.EcmaScriptVersion.Major > 0 

    && Page. Request.Browser.W3CDomVersion.Major > 0)

                    
    {

                        
    this._supportJS = true;

                    }


                }


            }


            

            
    protected override void OnPreRender(EventArgs e)

            
    {

                
    base.OnPreRender(e);

                DetermineJS();

                
    if (_supportJS)

                
    {

                    
    if (!Page.ClientScript.IsClientScriptBlockRegistered(

    this. GetType(),"AUTOFLEXJS"))

                    
    {

                        Page.ClientScript.RegisterClientScriptBlock(

    this.GetType(), "AUTOFLEXJS", AUTOFLEXJS, true);

                    }


                }


            }


            
    protected override void Render(HtmlTextWriter writer)

            
    {

                
    base.Render(writer);

                
    if (_supportJS)

                
    {

                    Page.ClientScript.RegisterStartupScript(

    this.GetType(), this.UniqueID,

                        
    string.Format("    var {0}_AutoFlex = 

    new AutoFlex('{0}',{1});\r\n    {0}_AutoFlex.initiate();\r\n",

                        
    this.UniqueID,this.MaxHeight.ToString()), true);

                }


            }


    这段代码非常简单,AutoFlexTextArea类从TextBox类继承。为了隐藏TextBox的TextMode属性,重写了这个属性,并且不允许用户设置TextMode属性
    此外新增了MaxHeight属性,用来指定最大扩展高度
    然后重写OnPreRender()方法,检测访问浏览器对脚本的支持能力,并输出AutoFlex组件脚本,通过IsClientScriptBlockRegistered()方法保证在同样的页面中,这段脚本只会输出一次
    最后重写Render()方法,在页面表单的最后注册初始化客户端组件所需的脚本.
    ******************************************************

    生成控件,放入页面中进行测试:

    <cc1:autoflextextarea id="AutoFlexTextArea1" runat="server"></cc1:autoflextextarea>

    <cc1:autoflextextarea id="AutoFlexTextArea2"

    runat="server" MaxHeight="200"></cc1:autoflextextarea>

    最终呈现的页面内容如下:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <html xmlns="http://www.w3.org/1999/xhtml">

    <head><title>

                        无标题页

    </title></head>

    <body>

        <form name="form1" method="post" action="TestAutoFlexTextArea.aspx" id="form1">

    <div>

    <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTEyMj U4MzUwMGRkE8+2KGaUuMKOsu+evZ76vSgAYMU=" />

    </div>

    <script type="text/javascript">

    <!--

        function AutoFlex(id,maxHeight){

            //省略AutoFlex组件代码;

        }

    // -->

    </script>

            <div>

                <textarea name="AutoFlexTextArea1" rows="2" cols="20" id="AutoFlexTextArea1"></textarea>

                <textarea name="AutoFlexTextArea2" rows="2" cols="20" id="AutoFlexTextArea2"></textarea>

            </div>

       

    <div>

                <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="/wEWAwL/88OJCQKmoPGEDAKloPGEDNkP9kNJ1Pg3kQ7qvP+7/kqXZYV0" />

    </div>

    <script type="text/javascript">

    <!--

        var AutoFlexTextArea1_AutoFlex = new AutoFlex('AutoFlexTextArea1',0);

        AutoFlexTextArea1_AutoFlex.initiate();

        var AutoFlexTextArea2_AutoFlex = new AutoFlex('AutoFlexTextArea2',200);

        AutoFlexTextArea2_AutoFlex.initiate();

    // -->

    </script>

    </form>

    </body>

    </html>

  • 相关阅读:
    JDBC 连接 MySQL 数据库
    通过java类的反射机制获取类的属性类型
    反射机制实例化类,并获取类中的属性、方法、和构造器
    java8u162反射机制的一个BUG
    Java反射关于getDeclaredMethods()和getMethods()的区别
    Java反射
    30天C#基础巩固------了解委托,string练习
    30天C#基础巩固------读写流(StreamWrite/StreamReader)
    30天C#基础巩固------集合,File(文件操作 ),Encoding处理字符集
    30天C#基础巩固------面向鸭子编程,关于string和File的练习
  • 原文地址:https://www.cnblogs.com/shuang/p/1004315.html
Copyright © 2020-2023  润新知