当前位置: 首页 > news >正文

事件模型

事件模型

在我们前端领域,事件模型使用最多与最常见的就是 DOM 事件模型。听说最多的就是“事件监听”, “事件代理”这名词。

它能避免对多个 DOM 节点添加相同的事件、避免通过 JS 添加的 DOM 节点也可触发相关事件等等。

DOM事件模型(冒泡、捕获)

在对 DOM 操作时,可给对应的 DOM 节点添加 Click 等事件。在 DOM 事件模型中,分为“冒泡”与“捕获”两个方式。默认为“冒泡”。

以下都以“冒泡”为主要操作方向。“捕获”不做更多解释。

“捕获”与“冒泡”的生命周期

 

在该 DOM 树结构中,以click来解释为。当我们对最底层的 div 发生一个 click 事件时,“捕获”流程开始,会依次由 window 顶层节点开始依次往下寻找直到触发事件的 div 节点,"捕获"的生命周期结束。接着“冒泡”的生命周期开始。会根据 DOM 树往上传递,一直到 window “冒泡”生命周期结束。

这两种形式在代码层面如下

//click 事件回调

var clickFn = function(e){

    // e 为事件对象,内部拥有触发该事件时,鼠标相对于屏幕的X、Y值,触发事件的 DOM 对象。

    // 更详细的信息可通过打印该对象进行阅读。

    console.log(e);

 

    // 针对某节点名称进行控制

    if(e.target.tagName.toLocaleLowerCase() === 'div'){

        console.log('点击的是 DIV 节点')

    }

 

    // 针对 class 名称进行控制

    if(e.target.className.indexOf('className') >= 0) {

        console.log('点击的是 className');

    }

};

 

document

    .getElementsByTagName('body')[0]

    .addEventListener('click', clickFn, false) //启用冒泡

 

 

document

    .getElementsByTagName('body')[0]

    .addEventListener('click', clickFn, true) //启用捕获

JQuery code

var clickFn = function(e){

    // 可将 e 对象数据打印出来,查看具体信息

    console.log(e);

}

 

$('body').on('click', 'JQuery select', clickFn);

鉴于冒泡的特性,我们可在最外层的 DOM 节点添加相关的事件,

因此我们可以基于以上理论实现一个比较常规的样式操作方法。具体实现效果操作如图

 

//style code

 

ul {

    display: flex;

    height: 50px;

}

 

ul li {

    flex: 1;

    height: inherit;

}

 

ul li.active {

    color: #ff6900;

    border-bottom: 1px solid #ff6900;

    box-sizing: border-box;

    text-align: center;

}

 

// HTML code

<ul>

    <li>

        <span>24小时榜单</span>

    </li>

    <li>

        <span>7天榜单</span>

    </li>

    <li>

        <span>30天榜单</span>

    </li>

</ul>

 

//js code

$('ul').on('click', 'li', function(e){

    console.log(e.target);         //span node

    console.log(e.currentTarget);  //li node

 

    $(e.currentTarget)

        .addClass('active')

        .siblings()

        .removeClass('active');

});

注意,在使用JQuery进行冒泡监听时,需要使用 e.currentTarget 该对象。e.target 为触发事件的 DOM 对象。e.currentTarget 为 on() 第二个参数所添加进入的 DOM 对象。

on(eve,[sel],[data], fn) And trigger(type,[data])

对 on(eve, [sel], [data], fn方法的解释官方

在选择元素上绑定一个或多个事件的事件处理函数。

对 trigger(type, [data]) 方法解释

在每一个匹配的元素上触发某类事件。

//  对 body 添加一个 click 事件

var $body = $('body').on('click', function(){console.log('this body')});

 

//手动触发 body 的 click 事件

$body.trigger('click'); //控制台会看到 'this body';

 

// 声明一个自定义 body 事件

$body.on('sayBodyName', function(){console.log('say this body')});

 

//触发自定义事件

$body.trigger('sayBodyName'); //控制台会看到 'say this body';

WEB前端领域中,我们大部分的工作都是基于用户的某些操作而响应某些事件。处于响应式、被动的场景。因而经典的设计模式 MVC 在前端领域中仅能完成通过 AJAX 获取到数据后,经过一系列的处理,最终展示到浏览器终端上。因此塔的生命周期为获取数据(M) -> 拼接数据(C) -> 展示数据(V),仅此而已。但是在实际操作中,我们还得响应用户的某些动作,而做出不同的操作,因此 MVC 在前端领域中 view 层变得很繁重,且格格不入。因而还衍生了一系列新颖的设计模式MVP、MVVM等等。基于前面我们所了解JQuery特性,我们可模拟 MVVM 模式中的 VM 部分。

现在我们使用上面所使用的 HTML 结构进重写。

//style code

 

ul {

    display: flex;

    height: 50px;

}

 

ul li {

    flex: 1;

    height: inherit;

}

 

ul li.active {

    color: #ff6900;

    border-bottom: 1px solid #ff6900;

    box-sizing: border-box;

    text-align: center;

}

 

// HTML code

<ul>

    <li>

        <span>24小时榜单</span>

    </li>

    <li>

        <span>7天榜单</span>

    </li>

    <li>

        <span>30天榜单</span>

    </li>

</ul>

 

// js code

var viewAction = {

    navClickFn: function(e){

        var $ele = $(e.currentTarget);

        var pushData = {text: $ele.text(), value: $ele.attr('data-value')};

 

        // 将 pushData 提交至新的 AJAX 请求;

 

        $ele

            .addClass('active')

            .siblings()

            .removeClass('active');

    },

    getNavList: function(){

        // ajax 获取数据 $.get('');

        var data = {list: [

                                {text: '24小时榜单', value: 1},

                                {text: '7天榜单', value: 2},

                                {text: '30天榜单', value: 3}

                            ]};

 

        navList.trigger('render', data)

    },

    renderList: function(e, data){

        var ul = $('<ul/>', {class: 'nav-list'});

        var li = $('<li/>', {class: 'nav-item'});

        var span = $('<span/>, {class: 'nav-item-text'});

 

        $.each(data.list, function(k, v){

            ul.append(

                li.clone().append(

                    span.clone().text(v.text).attr('data-value', v.value)

                )

            );

        });

 

        navList.html(ul);

    },

};

 

navList = ('nav-list')

    .on('click', '.nav-item', viewAction.navClickFn)

    .on('getNavList', viewAction.getNavList)

    .on('renderList', viewAction.renderList)

    .on('render', function(e, data){

        navList.trigger('renderList', data);

    });

以上就简单封装了一个 VM 模型。但是,通过 AJAX 获取到的数据与响应事件后的数据我们都是通过 trigger() 内部进的交互。比较难进行跟踪,所以,我们要实现一个保存数据的对象,并且可对该对象进一系列的控制。我们就将这个对象当做我们的 MVVM 中的 M 模型

// 现在我们将上面所有的数据摘取出来

 

// 声明一个 viewModule 对象;

var viewModule = {};

 

// 将 getNavList 修改为

 

viewAction.getNavList = function(){

    // ajax 获取数据 $.get('');

        viewModule.navList = {list: [

                                {text: '24小时', value: 1},

                                {text: '一周', value: 2},

                                {text: '一月', value: 3}

                            ]};

 

        navList.trigger('render')

}

 

// renderList 修改为

 

viewAction.renderList: function(e){

        var ul = $('<ul/>', {class: 'nav-list'});

        var li = $('<li/>', {class: 'nav-item'});

        var span = $('<span/>, {class: 'nav-item-text'});

 

        $.each(viewModule.navList.list, function(k, v){

            ul.append(

                li.clone().append(

                    span.clone().text(v.text).attr('data-value', v.value)

                )

            );

        });

 

        navList.html(ul);

    }

到这里,我们将使用 trigger() 进行通讯的数据摘取出来,通过外部的 viewModule 作为数据层,对需要使用数据的位置进行服务。但是这样做不太友好和安全,因为 viewModule 该对象没有做任何的保护,任何位置,任何地方都可以对它进行修改,且有时候我们还不知道我们已经修改了它。因此,我们需要对该对象进行一些封装。通过 闭包 实现对象私有化最快的方式。

var viewModule = (function(){

    var obj = {

        name: 'YangWs'

    };

 

    return {

        set: function(name){

            return obj[name];

        },

        get: function(name, value){

            obj[name] = value;

 

            reurn obj[name];

        }

    };

})();

这样,外部就无法直接操作 obj 对象,要对其进操作,只能通过 get(), set() 这两个方法。

但是,到目前为止,该模型只能进行保存值、取值的动作,而外部无法监到听内部的值是否有改变了。

对此,我们再对该 对象 添加一系列的方法扩展该对象的功能。接下来我们会使用到 订阅 与 发布的模型。

订阅(Sub

 

发布(Pub

 

他们的理论都很简单,和 JQuery 的 on 方法很像,对 DOM 对象添加一个 on/订阅 事件,当触发 on/订阅 事件时就执行通过 on/订阅 的函数,当触发时就是 trigger/发布 的过程。

更确切的来说,JQuery 通过 on 是实现 观察者模式。

接下来我们简单实现 订阅/发布 的模型

var subAndPub = function(){

    var eventList = {};

 

    return {

            on: function (name, cb) {

                if (Object.prototypt.toString.call(cb).indexOf('Function') >= 0) {

                    eventList[name] = eventList[name] ? eventList[name] : [];

 

                    eventList[name].push({

                        eventName: $.trim(name),

                        cb       : cb

                    });

                }

                return this;

            },

            trigger: function (name) {

                if (Object.prototype.toString.call(name).indexOf('String') >= 0) {

                    eventList[name] && $.each(eventList[name], function (k, v) {

                        //将触发事件方法插入eventLoop底部,等待each遍历完成后再执行函数

                        setTimeout(function () {

                            v.cb();

                        }, 0);

                    })

                }

 

                return this;

            }

        }

};

 

subAndPub

    .on('say', function(){console.log('this one say')})

    .on('say', function(){console.log('this two say')})

    .trigger('say');

这样,我们就实现了通过 on 与 trigger 进行订阅与发布的简单模型。

最终我们可以将以上的 VM、M 稍加修改后,结合起来就可家简单实现这几年前端各个框架拉新所使用的名词双向绑定

转载于:https://www.cnblogs.com/wjd2221/p/7363964.html

相关文章:

  • simulink降维观测器设计_现代控制理论线性系统入门(九)设计状态观测器
  • java nio中,HeapByteBuffer与DirectByteBuffer的区别
  • excel找到对应数据的列指标_python数据分析——医院销售数据实战案例
  • 二维数组元素的地址
  • 大话2烧法助手_大话西游2说出你自己的服务器名称,看看有没有一起玩耍的小伙伴...
  • 运行项目时报Server Tomcat v8.0 Server at localhost failed to start.
  • web安全
  • python 元组_python学习04-2:元组
  • python-day27--hashlib模块-摘要算法
  • 简述python执行原理_Python解释执行原理分析
  • 关于javascript 的reduce方法
  • python合法标识符_python合法标识符要求是什么
  • 不会英语学python_不会英语能不能学编程
  • @RequestParam @RequestBody @PathVariable 等参数绑定注解详解
  • 不同的电脑打印预览不同怎么解决_华为笔记本电脑怎么样?Matebook 14与Matebook 13的有哪些不同...
  • Effective Java 笔记(一)
  • express如何解决request entity too large问题
  • Flannel解读
  • happypack两次报错的问题
  • socket.io+express实现聊天室的思考(三)
  • spring cloud gateway 源码解析(4)跨域问题处理
  • supervisor 永不挂掉的进程 安装以及使用
  • 将回调地狱按在地上摩擦的Promise
  • 解决iview多表头动态更改列元素发生的错误
  • 开放才能进步!Angular和Wijmo一起走过的日子
  • 利用阿里云 OSS 搭建私有 Docker 仓库
  • 如何实现 font-size 的响应式
  • 深度学习入门:10门免费线上课程推荐
  • 微信小程序填坑清单
  • 原创:新手布局福音!微信小程序使用flex的一些基础样式属性(一)
  • elasticsearch-head插件安装
  • #传输# #传输数据判断#
  • ${ }的特别功能
  • (6)STL算法之转换
  • (动手学习深度学习)第13章 计算机视觉---微调
  • (二)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (二十五)admin-boot项目之集成消息队列Rabbitmq
  • (附源码)spring boot儿童教育管理系统 毕业设计 281442
  • (附源码)springboot教学评价 毕业设计 641310
  • (十一)JAVA springboot ssm b2b2c多用户商城系统源码:服务网关Zuul高级篇
  • (转)3D模板阴影原理
  • (转)编辑寄语:因为爱心,所以美丽
  • (转载)PyTorch代码规范最佳实践和样式指南
  • .bashrc在哪里,alias妙用
  • .NET : 在VS2008中计算代码度量值
  • .NET Compact Framework 多线程环境下的UI异步刷新
  • .NET Core实战项目之CMS 第十二章 开发篇-Dapper封装CURD及仓储代码生成器实现
  • .net6解除文件上传限制。Multipart body length limit 16384 exceeded
  • .NET的数据绑定
  • .net分布式压力测试工具(Beetle.DT)
  • .NET平台开源项目速览(15)文档数据库RavenDB-介绍与初体验
  • /3GB和/USERVA开关
  • /deep/和 >>>以及 ::v-deep 三者的区别
  • [ vulhub漏洞复现篇 ] struts2远程代码执行漏洞 S2-005 (CVE-2010-1870)
  • [.net]官方水晶报表的使用以演示下载