一.主要原理
我把一些会被多个页面调用的事件放到一个集合里面,以事件名称为key,以事件及其回调函数的数组为值。大概的形式如下。
events={“event_name1”:[[o11,callback11],[o12,callback12]],"event_name2":[[o21,callback21],[o22,callback22]]}
然后其他的页面就可以从这个池子(集合)里面通过事件名称找到对应的事件元素,拿到他的callback函数,进行调用了。
二.主要代码
事件总线的主要代码如下:
1 let events = {}; 2 3 const on = function (name, self, callback) { 4 const tuple = [self, callback]; 5 const callbacks = events[name]; 6 if (Array.isArray(callbacks)) { 7 callbacks.push(tuple); 8 } 9 else { 10 events[name] = [tuple]; 11 } 12 } 13 14 const remove = function (name, self) { 15 const callbacks = events[name]; 16 if (Array.isArray(callbacks)) { 17 events[name] = callbacks.filter((tuple) => { 18 return tuple[0] != self; 19 }) 20 } 21 } 22 23 const emit = function (name, data) { 24 const callbacks = events[name]; 25 if (Array.isArray(callbacks)) { 26 callbacks.map((tuple) => { 27 const self = tuple[0]; 28 const callback = tuple[1]; 29 callback.call(self, data); 30 }) 31 } 32 } 33 34 module.exports = { 35 on: on, 36 remove: remove, 37 emit: emit 38 }
首先我们定义了一个events对象,它的结构就是我们上面所说的那样。然后我们写了三个函数,分别是on,remove,emit。分别分别代表将事件注册,事件卸载,还有调用事件。
在on方法中,我们先检查当前name所对应的事件是否已存在(通过Array.isArray方法来判断其是否是数组,因为当callbacks为[]或者undifined的时候,该方法返回false).如果不存在,则将当前的tuple置为二维数组中的第一个数组元素。
在remove方法中,我们先通过name获取到其对应的二维数组callbacks,还是先通过Array.isArray判断该二维数组是否存在,如果存在,开始遍历该二维数组,并且过滤掉第一个元素为self的数组。(这边使用到了数组的filter方法,该方法通过回调函数会保留判断为true的元素,剔除掉判断为false的元素)。然后我们把过滤后的二维数组重新赋值给events[name]。这样就实现了事件的卸载。
最重要的是emit函数,这也是我们做事件总线的主要原因:我们同样通过name来获取二维数组,然后执行该二维数组中的每一个回调函数,此处通过call方法来实现。
三.使用方法
1 onShow: function () { 2 const _this = this; 3 const key = app.config.amapkey; 4 const initAmap = new amap.AMapWX({ key: key }); 5 events.on('locationData', this, function (data) { 6 const origin = data.longitude + ',' + data.latitude; 7 const destination = app.globalData.destination; 8 initAmap.getDrivingRoute({ 9 origin: origin, 10 destination: destination, 11 success: function (data) { 12 let points = []; 13 if (data.paths && data.paths[0] && data.paths[0].steps) { 14 const steps = data.paths[0].steps; 15 for (var i = 0; i < steps.length; i++) { 16 const poLen = steps[i].polyline.split(';'); 17 for (var j = 0; j < poLen.length; j++) { 18 points.push({ 19 longitude: parseFloat(poLen[j].split(',')[0]), 20 latitude: parseFloat(poLen[j].split(',')[1]) 21 }) 22 } 23 } 24 } 25 if (data.paths[0] && data.paths[0].distance) { 26 _this.setData({ 27 distance: data.paths[0].distance + '米' 28 }); 29 } 30 _this.setData({ 31 polyline: [{ 32 points: points, 33 color: "#0091ff", 34 width: 1, 35 dottedLine: true 36 }] 37 }); 38 } 39 }) 40 console.log(destination) 41 42 const markersArray = [{ 43 iconPath: '/resources/image/yipin.png', 44 id: 'pickUpAddress', 45 longitude: parseFloat(destination.split(',')[0]), 46 latitude: parseFloat(destination.split(',')[1]), 47 width: 25, 48 height: 25, 49 title: '自提地点', 50 label: { 51 content: '厦门出口加工区\n海景东路18号2楼', 52 bgColor: '#fff', 53 padding: '5', 54 borderRadius: '3' 55 } 56 }, { 57 id: 'myLocation', 58 longitude: data.longitude, 59 latitude: data.latitude, 60 }] 61 _this.setData({ 62 markersArray, markersArray 63 }) 64 }) 65 },
上述代码的第5行,注册了一个事件,名称叫做locationData,并且传入参数this,指代当前页面的page对象,还有一个匿名回调函数。
接下来看如何调用这个事件
1 sendLocation: function () { 2 const _this = this; 3 wx.getLocation({ 4 type: 'wgs84', 5 success: function (res) { 6 events.emit('locationData', res); 7 } 8 }) 9 },
调用emit函数,传入事件名称locationData,并且参数res(对应回调函数的参数data)
事件销毁方法如下:
1 onUnload: function () { 2 const _this = this; 3 clearInterval(_this.data.locationTimer) 4 events.remove('locationData', this); 5 },