如何理解事件委托?事件委托的优缺点有哪些?

如何理解事件委托?事件委托的优缺点有哪些?,第1张

JavaScript事件代理则是一种简单的技巧,通过它你可以把事件处理器添加到一个上级元素上,这样就避免了把事件处理器添加到多个子级元素上。当我们需要对很多元素添加事件的时候,可以通过将事件添加到它们的上级元素而将事件委托给上级元素来触发处理函数。这主要得益于浏览器的事件冒泡机制。事件代理用到了两个在JavaSciprt事件中常被忽略的特性:事件冒泡以及目标元素。

事件委托优点:

1、减少事件注册,节省内存。比如,

2、在table上代理所有td的click事件。

3、在ul上代理所有li的click事件。

4、简化了dom节点更新时,相应事件的更新。比如

5、不用在新添加的li上绑定click事件。

6、当删除某个li时,不用移解绑上面的click事件。

事件委托缺点:

1、事件委托基于冒泡,对于不冒泡的事件不支持

2、层级过多,冒泡过程中,可能会被某层阻止掉。

3、理论上委托会导致浏览器频繁调用处理函数,虽然很可能不需要处理。所以建议就近委托,比如在table上代理td,而不是在document上代理td。

4、把所有事件都用代理就可能会出现事件误判。比如,在document中代理了所有button的click事件,另外的人在引用改js时,可能不知道,造成单击button触发了两个click事件。

Delegate类简介

------------------------

命名空间:System

程序集:mscorlib(在 mscorlibdll 中)

委托(Delegate)类是一种数据结构,通过它可引用静态方法或引用类实例及该类的实例方法。

以往的界面编程中我们应该都接触过各种类型的事件驱动(event driven)的处理模式,

在这种模式里,我们定义相应事件触发的函数。

例如:

Button1 的 Click事件,我们可以编写Button1_Click 或 Btn1Clicked等函数来做相应的驱动处理。

而事件与驱动函数的对应关系就是通过委托(Delegate)类来关联的。

其实委托(Delegate)类这种数据结构有些类似于之前C/C++中的函数指针。

Delegate类一个简单应用

------------------------

1定义一个Delegate函数数据结构

2定义Delegate将引用的静态方法或引用类实例及该类的实例方法

3Delegate数据变量指向实例方法

4通过Delegate数据变量执行实例方法

A very basic example (TestClasscs):

using System;

namespace MySample

{

class TestClass

{

//1定义一个Delegate函数数据结构

public delegate void GoDelegate();

[STAThread]

static void Main(string[] args)

{

//3Delegate数据变量指向实例方法

GoDelegate goDelegate = new GoDelegate( MyDelegateFunc);

//4通过Delegate数据变量执行实例方法

goDelegate();

return;

}

//2定义Delegate将引用的静态方法或引用类实例及该类的实例方法

public static void MyDelegateFunc()

{

ConsoleWriteLine("delegate function");

}

}

}

编译执行结果:

# TestClassexe

delegate function

使用Delegate类和Override实现多态的比较

-----------------------------------------------

1使用Delegate类的时候,下面的例子可以很清楚的说明。

11 首先定义一个动物基类(MyAnimalDelegateClass), 基类中有显示属性的(ShowAnimalType)的public方法。

并且在ShowAnimalType方法中调用Delegate引用的实例方法

12 定义狮子(LionDelegateClass)和马(HorseDelegateClass)两个子类。Delegate与各自的实例方法绑定

实现不同的属性显示(ShowAnimalType)方法。

////Delegate example (TestClasscs):

using System;

namespace MySample

{

class TestClass

{

[STAThread]

static void Main(string[] args)

{

//狮子(LionDelegateClass)的属性显示(ShowAnimalType)方法调用

LionDelegateClass lionDelegate = new LionDelegateClass();

lionDelegateShowAnimalType("MySample");

//马(HorseDelegateClass)的属性显示(ShowAnimalType)方法调用

HorseDelegateClass horseDelegate = new HorseDelegateClass();

horseDelegateShowAnimalType("MySample");

}

}

//动物基类(MyAnimalDelegateClass)

public class MyAnimalDelegateClass

{

//Delegate数据结构定义

public delegate void DelegateFunction(string strFuncName);

private DelegateFunction m_delegateFunction = null;

//Delegate类型的属性

public DelegateFunction delegateFunction

{

get

{

return m_delegateFunction;

}

set

{

m_delegateFunction = value;

}

}

//属性显示(ShowAnimalType)方法

public void ShowAnimalType(string strFuncName)

{

if (delegateFunction != null)

{

object[] args = {strFuncName};

//调用Delegate引用的实例方法

delegateFunctionDynamicInvoke(args);

}

}

}

//狮子(LionDelegateClass)

public class LionDelegateClass:MyAnimalDelegateClass

{

public LionDelegateClass()

{

thisdelegateFunction = new DelegateFunction(subFunction1);

}

//狮子(LionDelegateClass)实例方法的实装

private void subFunction1(string strFuncName)

{

SystemConsoleWriteLine(

stringFormat("[{0}]This is a lion", strFuncName));

}

}

//马(HorseDelegateClass)

public class HorseDelegateClass:MyAnimalDelegateClass

{

public HorseDelegateClass()

{

thisdelegateFunction = new DelegateFunction(subFunction2);

}

//马(HorseDelegateClass)实例方法的实装

private void subFunction2(string strFuncName)

{

SystemConsoleWriteLine(

stringFormat("[{0}]This is a horse", strFuncName));

}

}

}

编译执行结果:

# TestClassexe

[MySample]This is a lion

[MySample]This is a horse

2使用Override实装的时候,参考下面的例子。

11 首先定义一个动物基类(AbstractAnimalNoDelegateClass), 基类中有显示属性的(ShowAnimalType)的public方法。

并且在ShowAnimalType方法中调用抽象方法(NoDelegateFunction)

12 定义狮子(LionNoDelegateClass)和马(HorseNoDelegateClass)两个子类。

子类中实装抽象方法(NoDelegateFunction)

实现不同的属性显示(ShowAnimalType)方法。

////Override example (TestClasscs):

using System;

namespace MySample

{

class TestClass

{

[STAThread]

static void Main(string[] args)

{

//狮子(LionNoDelegateClass )的属性显示(ShowAnimalType)方法调用

LionNoDelegateClass lionNoDelegate = new LionNoDelegateClass();

lionNoDelegateShowAnimalType("MySample");

//马(HorseNoDelegateClass )的属性显示(ShowAnimalType)方法调用

HorseNoDelegateClass horseNoDelegate = new HorseNoDelegateClass();

horseNoDelegateShowAnimalType("MySample");

}

}

//动物基类(AbstractAnimalNoDelegateClass)

public abstract class AbstractAnimalNoDelegateClass

{

public void ShowAnimalType(string strFuncName)

{

//抽象方法(NoDelegateFunction)调用

NoDelegateFunction(strFuncName);

}

//在基类中定义抽象方法(NoDelegateFunction)

protected abstract void NoDelegateFunction(string strFuncName);

}

//狮子(LionNoDelegateClass )

public class LionNoDelegateClass:AbstractAnimalNoDelegateClass

{

// 子类中实装抽象方法(NoDelegateFunction)

protected override void NoDelegateFunction(string strFuncName)

{

SystemConsoleWriteLine(

stringFormat("[{0}]This is a lion", strFuncName));

}

}

//马(HorseNoDelegateClass )

public class HorseNoDelegateClass:AbstractAnimalNoDelegateClass

{

// 子类中实装抽象方法(NoDelegateFunction)

protected override void NoDelegateFunction(string strFuncName)

{

SystemConsoleWriteLine(

stringFormat("[{0}]This is a horse", strFuncName));

}

}

}

编译执行结果:

# TestClassexe

[MySample]This is a lion

[MySample]This is a horse

3比较Delegate和Override实装方式

可以看出Delegate实装方式中,相当于定义一个函数指针的成员变量。

通过把实装函数的地址赋给该成员变量,实现同样的方法,处理方式的不同。

而Override方式中,则是在父类中预先定义好接口,通过实装的不同,

来实现同样的方法,处理方式的不同。

Delegate实装方式比较灵活,适合设计不是很完善的场合,便于修改。

Override方式封装性好,相对比较安全。

MulticastDelegate 类的应用

---------------------------------

在C#中,委托(Delegate)类是多路委托,这就说可以同时指向多个处理函数,

并且可以按照委托的先后顺序,执行相应的函数。

如下例:

using System;

namespace MySample

{

class TestClass

{

[STAThread]

static void Main(string[] args)

{

DogDelegateClass dogDelegate = new DogDelegateClass();

dogDelegateShowAnimalType("MySample");

}

public class MyAnimalDelegateClass

{

public delegate void DelegateFunction(string strFuncName);

private DelegateFunction m_delegateFunction = null;

public DelegateFunction delegateFunction

{

get

{

return m_delegateFunction;

}

set

{

m_delegateFunction = value;

}

}

public void ShowAnimalType(string strFuncName)

{

if (delegateFunction != null)

{

object[] args = {strFuncName};

delegateFunctionDynamicInvoke(args);

}

}

}

public class DogDelegateClass:MyAnimalDelegateClass

{

public DogDelegateClass()

{

//多路委托函数 设定

thisdelegateFunction = new DelegateFunction(subFunction31);

thisdelegateFunction += new DelegateFunction(subFunction32);

}

//委托函数1

private void subFunction31(string strFuncName)

{

SystemConsoleWriteLine(

stringFormat("[{0}]This is a dog", strFuncName));

}

//委托函数2

private void subFunction32(string strFuncName)

{

SystemConsoleWriteLine(

stringFormat("[{0}]This is a nice dog", strFuncName));

}

}

}

编译执行结果:

# TestClassexe

[MySample]This is a dog

[MySample]This is a nice dog

事件是由对象监听的,本质上是C#中的代理,或者叫做委托,button1Click += new EventHandler(button1_Click);中,Click是一个委托,该委托在Click行为发生的时候会广播,对于广播链中的函数,亦即事件处理函数,则采取相应的 *** 作。你这里的就是事件处理函数,该函数带两个参数,一个是类型为object的形参sender,相当于是这个函数的发出者,因为事件处理函数可能被多个事件注册,例如有多个Button按钮都注册了该事件处理函数,因此,你可以在代码中使用:

Button btn=(Button)sender;

将其转化为Button,再执行一些其他的 *** 作,确定事件的发出者是谁。

而EventArgs则是事件参数的意思,即Event Arguments的缩写,e相当于是携带了这个事件的一些消息。对于一些事件,例如MouseDown、KeyPress等,其中携带有光标的坐标或者按下的键值等。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/12181806.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-21
下一篇 2023-05-21

发表评论

登录后才能评论

评论列表(0条)

保存