学了两年半,Yii2的jquery内置事件件知多少

安全检查中...
请打开浏览器的javascript,然后刷新浏览器
< 浏览器安全检查中...
还剩 5 秒&【Yii2事件研究】事件的解绑和级别概念 - 话题 - Yii Framework 中文社区
【Yii2事件研究】事件的解绑和级别概念
感谢你坚持读到这里,本篇是“Yii2事件研究”的最后一篇分享,我将继续在讲故事的同时轻松帮你学会事件机制的相关知识。
在这里我们先总结一下
第一篇:,其实事件并不难,我们每天用的js都是基于事件的,点击按钮后的一系列行为都是事件处理器。
第二篇:,挖根源,在进入事件前我们先学习了“观察者模式”,让你从原理上明白事件的流程,你学会了这种出镜率非常高的设计模式。
第三篇:,从一个实际有趣的例子引入,通过北哥和经理之间的博弈,让你在轻松中了解事件、学习yii事件常用方法、知道事件的运用场景等。
第四篇:,yii是很贴心的,本篇为你讲解如何寻找yii提供的41种内置事件,以及具体如何去使用它们。
第五篇:,通过这篇我们知道了事件处理器的四种类型,以及事件阻断和事件排序,你可以应对很复杂的事件了。
今天我们将学习事件的解绑和级别概念,准备开始,北哥和小x经理的对弈。
小x经理并没有停止对需求的探索,她和我说了这个“小事情”
她认为虽然烦死政府是我们的梦想,但是有一种情况要除外,就是我们开发人员登录的时候就不要发了,不但是政府,所有登陆后的事件都搞掉要,否则老板会找她谈话的。
通过对以上的学习,我们知道阻断事件是一种停止执行的方法,但是我必须要让这个阻断程序处于事件列表的第一位,这不是我想做的,因为上篇里我需要让Gov订阅者一直都前端。
没关系,我知道还有个和位置无关,且能干掉其他事件的方法,那就是解绑 。
在事件绑定之后,在触发之前,我们有机会做一些解绑工作。好吧,顺便复习下yii的事件解绑功能。
我贴一组代码,相信你一眼就能看明白解绑的使用方法。
$this-&off(User::EVENT_AFTER_LOGIN, 'function_name');// 解绑一个已经绑定的全局事件处理器
$this-&off(User::EVENT_AFTER_LOGIN, [$object, 'methodName']); // 解绑一个对象的方法
$this-&off(User::EVENT_AFTER_LOGIN, ['app\components\Bar', 'methodName']); // 解绑一个类静态犯法
$this-&off(User::EVENT_AFTER_LOGIN, $anonymousFunction); // 解绑一个匿名方法
$this-&off(User::EVENT_AFTER_LOGIN); // 解绑所有绑定在此事件上的处理器
前三种我想你很容易就明白了,这里我说明下后两种
解绑一个匿名方法
我们知道可以为一个事件绑定一个匿名函数,例如
$this-&on(User::EVENT_AFTER_LOGIN,function($event){
// 我是匿名函数,我骄傲
但是,我们不能通过
$this-&off(User::EVENT_AFTER_LOGIN,function($event){
// 我是匿名函数,我骄傲
对其进行解绑,匿名函数就像内存中的一个叫做abc的值,可能在内存中存在两块都含abc的区域,但是如果我们不指定区域的名字,靠值是无法定位的,即便他们都是abc。
那怎么办那?我们可以将匿名函数放到一个变量中,然后再解绑此变量,这是唯一一种解绑匿名函数的方法。
$fuc = function($event){
// 我是匿名函数,我骄傲
$this-&on(User::EVENT_AFTER_LOGIN,$fuc);
$this-&off(User::EVENT_AFTER_LOGIN,$fuc);
只能这样。
这个很简单,执行一个只有事件名的解绑函数,毫不客气解绑之前绑定的所有。
说到这里,我想你和我一样兴奋了,因为小x经理的个需求我们已经找到了解决方案。
思路是这样的:判断当前登陆者是否是开发人员,如果是,在触发前解绑所有。
当然,对于我们的例子会有点复杂,因为我们触发的是yii内置的User类的一个事件。一种解决方法是我们新建一个该类的子类,然后在子类里对afterLogin方法进行重写,因我们主要将事件,就不再花篇幅细说这里。
ok,到此为止北哥和小x经理的故事也完结了。
北哥和小x经理的故事覆盖了我们事件的大部分功能和使用场景,但是有一块我想还是需要给大家介绍下,那就是事件的级别。
事件的级别一共分三种
对于级别的阐述我决定复制网上广为流传的一段解释,复制的原因并非我认为他已经讲清楚了,而是北哥迄今还没有找到更贴切的例子将大家带入到级别的理解中。
如果你看懂下面的引用,那是最好的;如果没懂,没关系,在不用几天的时间内,我会单独出一篇针对于事件级别的故事,彻底解决对他们的理解。
我是引用分隔线----
实例级别也就是事件的触发、处理全部都在实例范围内。这种级别的事件用情专一,不与类的其他实例发生关系,也不与其他类、其他实例发生关系。除了实例级别的事件外,还有类级别的事件。对于Yii,由于Application是一个单例,所有的代码都可以访问这个单例。因此,有一个特殊级别的事件,全局事件。但是,本质上,他只是一个实例级别的事件。
这就好比是公司里的不同阶层。底层的码农们只能自己发发牢骚,个人的喜怒哀乐只发生在自己身上,影响不了其他人。而团队负责人如果心情不好,整个团队的所有成员今天都要战战兢兢,慎言慎行。到了公司老总那里,他今天不爽,哪个不长眼的敢上去触霉头?事件也是这样的,不同层次的事件,决定了他影响到的范围。
类级别事件
先讲讲类级别的事件。类级别事件用于响应所有类实例的事件。比如,工头需要了解所有工人的下班时间, 那么,对于数百个工人,即数百个Worker实例,工头难道要一个一个去绑定自己的handler么? 这也太低级了吧?其实,他只需要绑定一个handler到Worker类,这样每个工人下班时,他都能知道了。 与实例级别的事件不同,类级别事件的绑定需要使用 yii\base\Event::on()
Event::on(
Worker::className(),
// 第一个参数表示事件发生的类
Worker::EVENT_OFF_DUTY,
// 第二个参数表示是什么事件
function ($event) {
// 对事件的处理
echo $event-&sender . ' 下班了';
这样,每个工人下班时,会触发自己的事件处理函数,比如去打卡。之后,会触发类级别事件。 类级别事件的触发仍然是在 yii\base\Component::trigger() 中,还记得该函数的最后一个语句么:
Event::trigger($this, $name, $event);
// 触发类一级的事件
这个语句就触发了类级别的事件。类级别事件,总是在实例事件后触发。既然触发时机靠后,那么如果有一天你要早退又不想老板知道,你就可以向小煤窑老板那样,通过 $event-&handled = true ,来终止事件处理。
从 yii\base\Event::trigger() 的参数列表来看,比 yii\base\Component::trigger() 多了一个参数 $class 表示这是哪个类的事件。因此,在保存 $_event[] 数组上, yii\base\Event 也比 yii\base\Component 要多一个维度:
// Component中的$_event[] 数组
$_event[$eventName][] = [$handler, $data];
// Event中的$_event[] 数组
$_event[$eventName][$calssName][] = [$handler, $data];
那么,反过来的话,低级别的handler可以在高级别事件发生时发生作用么?这当然也是不行的。由于类级别事件不与任意的实例相关联,所以,类级别事件触发时,类的实例可能都还没有呢,怎么可能进行处理呢?
类级别事件的触发,应使用 yii\base\Event::trigger() 。这个函数不会触发实例级别的事件。值得注意的是, $event-&sender 在实例级别事件中, $event-&sender 指向触发事件的实例,而在类级别事件中, 指向的是类名。在 yii\base\Event::trigger() 代码中,有:
if (is_object($class)) {
// $class 是trigger()的第一个参数,表示类名
if ($event-&sender === null) {
$event-&sender = $
$class = get_class($class); // 传入的是一个实例,则以类名替换之
$class = ltrim($class, '\\');
这段代码会对 $evnet-&sender 进行设置,如果传入的时候,已经指定了他的值,那么这个值会保留,否则,就会替换成类名。
对于类级别事件,有一个要格外注意的地方,就是他不光会触发自身这个类的事件,这个类的所有祖先类的同一事件也会被触发。但是,自身类事件与所有祖先类的事件,视为同一级别:
// 最外面的循环遍历所有祖先类
if (!empty(self::$_events[$name][$class])) {
foreach (self::$_events[$name][$class] as $handler) {
$event-&data = $handler[1];
call_user_func($handler[0], $event);
// 所有的事件都是同一级别,可以随时终止
if ($event-&handled) {
} while (($class = get_parent_class($class)) !== false);
上面的嵌套循环的深度,或者叫时间复杂度,受两个方面影响,一是类继承结构的深度,二是 $_event[$name][$class][] 数组的元素个数,即已经绑定的handler的数量。从实践经验看,一般软件工程继承深度超过十层的就很少见,而事件绑定上,同一事件的绑定handler超过十几个也比较少见。因此,上面的嵌套循环运算数量级大约在100~1000之间,这是可以接受的。
但是,从机制上来讲,由于类级别事件会被类自身、类的实例、后代类、后代类实例所触发,所以,对于越底层的类而言,其类事件的影响范围就越大。因此,在使用类事件上要注意,尽可能往后代类安排,以控制好影响范围,尽可能不在基础类上安排类事件。
接下来再讲讲全局级别事件。上面提到过,所谓的全局事件,本质上只是一个实例事件罢了。他只是利用了Application实例在整个应用的生命周期中全局可访问的特性,来实现这个全局事件的。当然,你也可以将他绑定在任意全局可访问的的Component上。
全局事件一个最大优势在于:在任意需要的时候,都可以触发全局事件,也可以在任意必要的时候绑定,或解除一个事件:
Yii::$app-&on('bar', function ($event) {
echo get_class($event-&sender);
// 显示当前触发事件的对象的类名称
Yii::$app-&trigger('bar', new Event(['sender' =& $this]));
上面的 Yii::$app-&on() 可以在任何地方调用,就可以完成事件的绑定。而 Yii::$app-&trigger() 只要在绑定之后的任何时候调用就OK了。
^^^ 引用结束 ^^^
最后要说的话
匆匆6篇文章,感谢大家的阅读,当然仅仅6篇文章不足以覆盖“事件机制”的所有,但至少为大家起了一个敢用事件的头儿,多用多思考,这是我们理解一件事情的唯一法门。
后期对于事件的分享也会放到此专题下,但是不会像这几天一样,大篇幅,集中突击。
接下来我们要研究yii的行为模式和一些实际技法专题,比如有个专题叫“yii的所有第三方登陆”,“yii的所有支付”等等。感谢大家对工兵连的支持。
赞,感谢分享
共 2 条回复
这篇后半部分写的不是很好,后期会对 事件的级别 单独出一篇文章讲解。
感谢北哥分享,看了事件系列,由浅入深,丝般顺滑,不负老司机之名,交口称赞!
共 1 条回复
你这回复的成语太太太了。
您需要登录后才可以回复。 |403 Forbidden
Request forbidden by administrative rules.标签:至少1个,最多5个
书接上回,我将代码提交到服务器后被小X经理一顿批,她是这样说的。
小X: 你丫不知道yii2自己就有登陆后的事件么?
我:不知道啊,咋的吧?
小X:改!????,然后统计个yii2预定义事件表给我。
我:哦,好的。???
好吧,算咱技术不到家,那就赶紧改吧,先回顾下上一篇我都干了啥,我是在会员登陆后触发了一个事件,既然说有内置的,那就找找吧。
我知道登陆功能是使用yiiwebUser这个类,那应该去那里去找它们。它在@app/vendor/yiisoft/yii2/web/User.php
5分钟以后~
果然,我找到了那个事件,还用了3分钟分析了如何使用,现在把我的研究成果和大家分享下。
对于yii2系统的登陆,yiiwebUser类一共提供了4个事件,如下
const EVENT_BEFORE_LOGIN = 'beforeLogin';
const EVENT_AFTER_LOGIN = 'afterLogin';
const EVENT_BEFORE_LOGOUT = 'beforeLogout';
const EVENT_AFTER_LOGOUT = 'afterLogout';
分别是登陆前后、注销前后,我要使用的是EVENT_AFTER_LOGIN事件,那么如何去使用那?
既然是登陆,还是先看下yiiwebUser中的login方法,看看是否有蛛丝马迹
public function login(IdentityInterface $identity, $duration = 0){
if ($this-&beforeLogin($identity, false, $duration)) {
$this-&switchIdentity($identity, $duration);
$id = $identity-&getId();
$ip = Yii::$app-&getRequest()-&getUserIP();
if ($this-&enableSession) {
$log = "User '$id' logged in from $ip with duration $duration.";
$log = "User '$id' logged in from $ip. Session not enabled.";
Yii::info($log, __METHOD__);
$this-&afterLogin($identity, false, $duration);
return !$this-&getIsGuest();
我看到了 $this-&afterLogin($identity, false, $duration),似乎这个方法是登陆后做了一些事情,那就继续看吧
protected function afterLogin($identity, $cookieBased, $duration){
$this-&trigger(self::EVENT_AFTER_LOGIN, new UserEvent([
'identity' =& $identity,
'cookieBased' =& $cookieBased,
'duration' =& $duration,
OMG,真的发现了,原来这个方法触发了EVENT_AFTER_LOGIN事件,并且还很贴心的将identity等信息传递给了绑定EVENT_AFTER_LOGIN事件的每一位观察者。
于是思路来了??????
我只需要在login前绑定EVENT_AFTER_LOGIN事件,然后afterLogin会自动触发所有订阅者。
use yii\web\U
class UserController extends Controller {
public function __construct(){
$this-&on(User::EVENT_AFTER_LOGIN,['app\models\OLog','add']);
$this-&on(User::EVENT_AFTER_LOGIN,['app\models\Admin','sendMail']);
$this-&on(User::EVENT_AFTER_LOGIN,['app\models\User','notifyFirend']);
public function actionIndex(){
我之前定义的EVENT_USER_LOGIN自然可以删除了,上面看到afterLogin方法触发事件的时候已经传递了一个UserEvent,里面含有登陆的详细信息了,我上一篇自己定义的那个UserLoginEvent也就可以删除了。
使用系统自带的事件,真心省了太多代码了,感谢yii2开发团队,感谢你们八倍祖主。
对于登陆主题就重构完了,现在我还需要改下订阅者的代码,毕竟传递给订阅者的$event不一样了,拿一个订阅者举例吧
// User app\models\User.php
class User {
static public function notifyFirend($event){
$userId = $event-&userId;
echo "告诉了朋友们我登陆了";
我要对其进行小手术,diu一下,手术后的样子如下
// User app\models\User.php
class User {
static public function notifyFirend($event){
$userId = $event-&identity-&
echo "告诉了朋友们我登陆了";
ok~到此为止我们对登陆逻辑的事件处理就完成了,去掉了自定义的事件,绑定了 User::EVENT_AFTER_LOGIN 内置事件。
是的还没完,小X经理还让我提交一个yii2预定义事件表给她,我深刻体会到这个表格的重要性,有了它,便可以通晓yii所有事件,正所谓就算成功,也不一定自宫。
但是,yii2这么大,我如何一个不落的得到它们那?
看来要借助于我们的神器PHPSTORM了。
首先我们知道yii2对于事件名的命名规则,常量、大写、观察下发现内置的这些事件都是EVENT_开头的,有了这些特征,那开始吧。
方法如下:我们对vendor/yiisoft目录进行查找(find in path),找到所有const EVENT_开头的行。
是的,一共有41个。最近听说有个叫阿北的人做了一个yii速查表,我计划将这个表格分享给他也。
yii2速查表之event内置一览表
建议你背下这些事件,至少在做事件的时候查一遍速查表,能用系统的优先使用系统的。
学到了一些
很高兴完成了小x经理关于登陆事件的需求,通过这些让我对yii的事件有了一个大体了解,知道了事件是观察者模式的一种实现、知道yii2内置了很多事件,我们应该优先使用它们。
begin git。
一阵QQ震动,带着坏笑的小x经理发了一句消息给我:“来,小北同学!”
天,又咋了,下篇告诉你。
2 收藏&&|&&2
你可能感兴趣的文章
1 收藏,346
3 收藏,242
3 收藏,731
本作品采用 署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可
分享到微博?
你好!看起来你挺喜欢这个内容,但是你还没有注册帐号。 当你创建了帐号,我们能准确地追踪你关注的问题,在有新答案或内容的时候收到网页和邮件通知。还能直接向作者咨询更多细节。如果上面的内容有帮助,记得点赞 (????)? 表示感谢。
明天提醒我
我要该,理由是:}

我要回帖

更多关于 angular内置事件 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信