(一) -事件发布和订阅——子给父传值 & 1注册事件$on-父组件是订阅者& 2触发事件$emit-子组件是发布者& 3测试 同页面或不同组件& .call改变事件处理函数的this指向为事件对象

事件发布/订阅——理解为:子给父传值 & 1注册事件 $on—— 该父组件是订阅者 & 2触发事件 $emit——该子组件是发布者 & 3测试 可同页面也可不同组件 & .call改变事件处理函数的this指向为事件对象,不然为window

  • 观察者模式
  • 发布/订阅模式
// 监听一个自定义事件
bus.$on('事件类型', 处理函数)

// 发布事件
bus.$emit('事件类型', 参数)

代码展示:

1.注册事件时,传递参数 剩余参数 …args

2.改变handler事件函数内部的this指向 .call

<body>
    <script>
        // 发布订阅模式——子给父传值

        // 注册事件-父组件接收(订阅消息,消息就是事件)——数据变化了,就更新视图
        // bus.$on('click', fn)
        // bus.$on('click', fn1)

        // 发布事件-子组件传值(发布消息,消息就是事件)
        // bus.$emit('click', 事件参数)

        //构造函数
        function EventEmitter() {
            //对象结构:  { 'click': [fn, fn1], 'm': [fn] }
            // 定义数组或对象,用来存储注册的事件 bus.$on('click', fn)
            this.subs = {}
        }

        // 一、注册事件 $on—— 该父组件是订阅者-订阅消息,随时监听到子组件传了啥,传给我什么,我就变成什么   ——数据变化了,就更新视图
        // 1. eventType-事件类型  2. handler-事件处理函数
        EventEmitter.prototype.$on = function(eventType, handler) {
            // 第一种情况:注册事件 { 'click': [fn] }
            // if (this.subs[eventType]) {
            //   // 如果有值  -->值为: [fn] ,this.subs[eventType] 对应数组 [fn]
            //subs 是对象 ,   [eventType] 变量作为属性,不能用  .  ,要用中括号  ;push() 方法可向数组的末尾添加一个或多个元素,并返回新的长度。
            // this.subs[eventType].push(handler)
            // } else {
            //   // 第二种情况:  {}
            //   // 没有值  ,把值添加进去
            //   this.subs[eventType] = []
            //   this.subs[eventType].push(handler)
            // }

            // 上面两种情况,等价如下    释义:如果有值,等于自己;如果无值,等于空数组
            this.subs[eventType] = this.subs[eventType] || []
                // 数组OK,直接调用
            this.subs[eventType].push(handler)
        }

        // 二、触发事件 $emit——该子组件是发布者-发布消息,用$emit把数据传给父组件
        // 在function (eventType, ...args) 此时的args是剩余参数
        //...args 指剩余参数, 剩余参数在参数列表的最后,args是数组
        EventEmitter.prototype.$emit = function(eventType, ...args) {
            if (this.subs[eventType]) {
                //事件函数 [fn, fn1] ,  this.subs[eventType] 存储了事件函数
                this.subs[eventType].forEach(handler => {
                    // 此时的...args 是展开运算符 -显示函数中的参数 a, b, c
                    // 此时的this就是em对象
                    //  handle函数 指的就是$on注册的function()事件函数 ,
                    //call-用来改变this   不加 .call ,this指-window全局变量——handler(...args)

                    handler.call(this, ...args)

                    //逻辑:箭头函数handler没有自己的this——>上找:.$emit存入的函数function——>.$emit在触发事件时调用 em.$emit ——>$emit()方法里面的this是em对象
                })
            }
        }

        // 三、测试
        var em = new EventEmitter()

        // 1.先注册事件
        em.$on('click', function(a, b, c) { // 接收也要是三个参数
            console.log(this) //此时的this就是em对象      若不加 .call ,this指-window全局变量——handler(...args)
            console.log(a + b + c) // II 显示为 10
            console.log('hello') // II 显示为 hello
        })
        em.$on('click', function() {
            console.log('hello1') // II 显示为 hello1
        })
        em.$on('test', function() {
            console.log('test') // II 不显示
        })

        // 2.再触发事件  传递3个参数
        em.$emit('click', 1, 3, 6) // I 触发那哪个事件,就执行哪个;此时,test事件不执行,不显示
    </script>
</body>

控制台打印显示为:

在这里插入图片描述

示例:

function EventEmitter () {
  // 存储所有订阅的消息处理函数
  this.subs = {
    // 事件类型: [处理函数, 处理函数...]
    // a: [],
  }
}

EventEmitter.prototype.$on = function (eventType, callback) {
  this.subs[eventType] = this.subs[eventType] || []
  this.subs[eventType].push(callback)
}

// 参数中的 ... 表示函数的剩余(rest)参数
// 它会把所有参数放到一个数组中
EventEmitter.prototype.$emit = function (eventType, ...args) {
  const subs = this.subs[eventType]
  if (subs) {
    subs.forEach(callback => {
      callback(...args)
    })
  }
}
发布了199 篇原创文章 · 获赞 1 · 访问量 5475

猜你喜欢

转载自blog.csdn.net/weixin_44867717/article/details/104877590