JerryMissTom / ionic3-handbook

手摸手带你入门ionic3
34 stars 9 forks source link

9、Events广播 #9

Open JerryMissTom opened 6 years ago

JerryMissTom commented 6 years ago

当项目大了之后,我们肯定会遇到这样的需求,在某一界面发生了特定的事件,比如说修改了某个数据,执行了某个操作,希望其他界面可以接收到我们这个事件,说白了就是我们常见的发布者和订阅者模式。ionic也对其进行了封装,提供了Events这个好用的模块。

我们来模拟发布和订阅的场景,在懒加载界面中添加一个按钮,当点击此按钮,会发送一个名为changeTitle的事件,同时传递一个ionic字符串出去,在主页中,我们订阅此事件,当接收到此事件信息时,改变此界面中title变量,观察界面的变化。

下面我们用代码来实现此需求,首先,在lazyload.html界面中添加点击按钮,如下:

lazyload.html

...
<button (click)="sendEvent()">发送事件</button>

然后在lazyload.ts中添加对应的方法,如下:

lazyload.ts

import { IonicPage, NavController, NavParams, Events } from 'ionic-angular';
...
export class LazyLoadPage {

  ...

  constructor(public navCtrl: NavController, public navParams: NavParams, public events:Events) {
  ...
  }

  sendEvent(){
    this.events.publish('changeTitle','ionic');
  }

}

代码中我只把改动的地方写出来,其他的地方不需要任何的改动。值得注意的一点是Eventsionic提供的一个Service(Angular中的概念),所以需要在constructor中注入进来。关于Service,我希望大家可以自己去看相关的内容,这里面就不赘述,可能以后会开一篇进行讲解。

Events.publish(topic:string,...args: any[])中第一个参数是所要发送事件的名称,一定是个string类型,后面是所要发送的数据,是一个数组,我们同时可以发送多个数据,例如:this.events.publish('changeTitle', 'ionic', 13, {time: Date().now})

接着处理下订阅事件。home.ts中修改代码如下:

home.ts
...
import { NavController, Events } from 'ionic-angular';
...
export class HomePage {

  title : string = '';

  constructor(public navCtrl : NavController, public events:Events) {
    console.log("HomePage constructor");
  }

  ...
  ionViewDidLoad() {
    console.log('HomePage ionViewDidLoad');
    this.events.subscribe('changeTitle',(title)=>{
      this.title=title;
    });
  }

  ionViewWillUnload() {
    console.log('HomePage ionViewWillUnload');
    this.events.unsubscribe('changeTitle',()=>{
       console.log('取消订阅changeTitle事件');
    });
  }
}

同样只列出改动的部分,就像我们在声明周期这篇讲的,我们在ionViewDidLoad中订阅此事件,ionViewWillUnload取消订阅,记住,一定要取消,不然会造成多次订阅,导致事件混乱。

ionic serve运行我们的项目,从主页进入懒加载界面,点击按钮,返回主页,查看下我们的输入框是不是有ionic这个单词了。看下效果: events

发布订阅系统

其实Evnents我们自己也可以写一个,这人就贴一下ionic实现的代码,大家可以揣摩下。

var Events = (function () {
    function Events() {
        this._channels = [];
    }

    Events.prototype.subscribe = function (topic) {
        var _this = this;
        var handlers = [];
        for (var _i = 1; _i < arguments.length; _i++) {
            handlers[_i - 1] = arguments[_i];
        }
        if (!this._channels[topic]) {
            this._channels[topic] = [];
        }
        handlers.forEach(function (handler) {
            _this._channels[topic].push(handler);
        });
    };

    Events.prototype.unsubscribe = function (topic, handler) {
        if (handler === void 0) { handler = null; }
        var t = this._channels[topic];
        if (!t) {
            // Wasn't found, wasn't removed
            return false;
        }
        if (!handler) {
            // Remove all handlers for this topic
            delete this._channels[topic];
            return true;
        }
        // We need to find and remove a specific handler
        var i = t.indexOf(handler);
        if (i < 0) {
            // Wasn't found, wasn't removed
            return false;
        }
        t.splice(i, 1);
        // If the channel is empty now, remove it from the channel map
        if (!t.length) {
            delete this._channels[topic];
        }
        return true;
    };

    Events.prototype.publish = function (topic) {
        var args = [];
        for (var _i = 1; _i < arguments.length; _i++) {
            args[_i - 1] = arguments[_i];
        }
        var t = this._channels[topic];
        if (!t) {
            return null;
        }
        var responses = [];
        t.forEach(function (handler) {
            responses.push(handler.apply(void 0, args));
        });
        return responses;
    };
    return Events;
}());
export { Events };