惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
Netflix TechBlog - Medium
V
Vulnerabilities – Threatpost
Google Online Security Blog
Google Online Security Blog
Hugging Face - Blog
Hugging Face - Blog
L
LINUX DO - 热门话题
云风的 BLOG
云风的 BLOG
P
Proofpoint News Feed
D
Docker
C
Cyber Attacks, Cyber Crime and Cyber Security
MyScale Blog
MyScale Blog
P
Palo Alto Networks Blog
T
Tenable Blog
P
Privacy International News Feed
Google DeepMind News
Google DeepMind News
小众软件
小众软件
Cisco Talos Blog
Cisco Talos Blog
aimingoo的专栏
aimingoo的专栏
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
A
Arctic Wolf
C
Cybersecurity and Infrastructure Security Agency CISA
C
Cisco Blogs
T
Threat Research - Cisco Blogs
NISL@THU
NISL@THU
The Hacker News
The Hacker News
Project Zero
Project Zero
AWS News Blog
AWS News Blog
Simon Willison's Weblog
Simon Willison's Weblog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
Threatpost
V
Visual Studio Blog
The GitHub Blog
The GitHub Blog
The Cloudflare Blog
Last Week in AI
Last Week in AI
Jina AI
Jina AI
Cyberwarzone
Cyberwarzone
The Register - Security
The Register - Security
C
CXSECURITY Database RSS Feed - CXSecurity.com
Vercel News
Vercel News
D
Darknet – Hacking Tools, Hacker News & Cyber Security
MongoDB | Blog
MongoDB | Blog
U
Unit 42
Scott Helme
Scott Helme
A
About on SuperTechFans
WordPress大学
WordPress大学
F
Fortinet All Blogs
大猫的无限游戏
大猫的无限游戏
G
GRAHAM CLULEY
Latest news
Latest news
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
S
Schneier on Security

博客园 - shuang

heart or house? Dos for -- by 随风 - shuang C--Pointer Raid -----asp web 报表 - shuang ----[创业指南]给海归技术创业兄弟的九个忠告 --设计模式--Hibernate about avast job desc 把INT转换成2进制等 private/实现有多个相同方法的接口 使用接口改变已经装箱的值类型的字段 struct也有方法成员 virtual 集成资源文件 const -readonly- static readonly csm2 ClientScriptManager html______1
脚本---用函数模拟类
shuang · 2007-12-18 · via 博客园 - shuang

让我们先实现组件化的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>