【5+】跨webview多页面 触发事宜(二)

上一章我们相识到经由过程webview evalJS的要领来跨页面关照事宜,然则在个中照样有须要优化的处所,接下来我们逐步的来剖析。

上节回忆:【5+】跨webview多页面 触发事宜(一)
代码:

//页面关照

class Broadcast{
    /**
     * 组织器函数
     */
    constructor(){
        
    }
    
    /**
     * 事宜监听
     * @param {String} eventName 事宜称号
     * @param {Function} callback 事宜触发后实行的回调函数
     * @return {Broadcast} this
     */
    on(eventName, callback){
        document.addEventListener(eventName, e => {
            callback.call(e, e.detail)
        })
        return this
    }
    
    /**
     * 事宜触发
     * @param {String} eventName 事宜称号
     * @param {Object} data 参数
     * @return {Broadcast} this
     */
    emit(eventName, data){
        // 猎取一切的webview
        var all = plus.webview.all()
        // 遍历悉数页面
        for(var w in all){
            // 挨个来evalJS
            all[w].evalJS(`document.dispatchEvent(new CustomEvent('${eventName}', {
                detail:JSON.parse('${JSON.stringify(data)}'),
                bubbles: true,
                cancelable: true
            }));`)
        }
        return this
    }
    
    
}

自定义须要关照页面

能够看到,之前我们emit发送关照时,是对一切的webview举行猎取关照,然则有时刻我们并不想关照一切的页面,而且关照他人的时刻也不想关照本身啊,怎么办,在这里我们在emit要领参数多加一个设置项

    /**
     * 事宜触发
     * @param {String} eventName 事宜称号
     * @param {Object} data 传参参数值
     * @param {Object} options 别的设置参数
     */
    emit(eventName, data, {
        self = false, // 是不是关照本身,默许不关照
        views = [], // 为空数组时,默许关照悉数,为string数组时,认为是id,为object时,认为是webview对象
    } = {}) {
        //code...
    }

然后我们针对传进来的拓展参数,举行逻辑推断,获得终究我们须要关照的webview list

    /**
     * 事宜触发
     * @param {String} eventName 事宜称号
     * @param {Object} data 传参参数值
     * @param {Object} options 别的设置参数
     */
    emit(eventName, data, {
        self = false, // 是不是关照本身,默许不关照
        views = [], // 为空数组时,默许关照悉数,为string数组时,认为是id,为object时,认为是webview对象
    } = {}) {
        let all = []
        // 猎取 特定 webview 数组
        if(views.length > 0) {
            // 假如是string 范例,则一致处置惩罚猎取为 webview对象
            all.map(item => typeof item === 'string' ? plus.webview.getWebviewById(item) : item)
        } else {
            // 不特定关照的webview数组时,直接猎取悉数已存在的webview
            all = plus.webview.all()
        }
        // 假如不须要关照到当前webview 则过滤
        if(!self) {
            let v =  plus.webview.currentWebview()
            all = all.filter(item => item.id !== v.id)
        }
        // 遍历一切须要关照的页面
        for(let v of all) {
            v.evalJS(`document.dispatchEvent(new CustomEvent('${eventName}', {
                detail:JSON.parse('${JSON.stringify(data)}'),
                bubbles: true,
                cancelable: true
            }));`)
        }
    }
    

怎样挪用

new Broadcast().emit('say',{
    name: 'newsning',
    age: 26
},{
    self: true, // 关照当前页面 默许不关照
    views: ['A.html','C.html'] // 默许关照一切页面,但不包含当前页面
})
// 如上代码就只关照到了3个页面, 当前页面, A页面, C页面

事宜 – [ 定阅 | 宣布 | 作废 ]

假如你碰到那种还须要移除监听事宜,亦或许Once只监听一次的事宜,再或是你看个代码不爽
《【5+】跨webview多页面 触发事宜(二)》

ok!我们来撸一套简朴的 守望前锋形式,哦不,是观察者形式

事宜定阅

瞧瞧我们之前的代码,on要领是直接把传进来的函数作为挪用,这模样在外部挪用时移除事宜就没门路了,包含Once也非常蛋疼

    /**
     * 事宜监听
     * @param {String} eventName 事宜称号
     * @param {Function} callback 事宜触发后实行的回调函数
     * @return {Broadcast} this
     */
    on(eventName, callback){
        document.addEventListener(eventName, e => {
            callback.call(e, e.detail)
        })
        return this
    }

我们先来定义好2个特地安排事宜的存储对象,碧如 :

    // 事宜列表
    const events = {
        // 事宜称号 : 事宜要领数组    
    },
    // 单次事宜列表
    events_one = {

    }

以后我们修正一下on要领,并新增一个once要领

    /**
     * 事宜监听
     * @param {String} eventName 事宜称号
     * @param {Function} callback 事宜触发后实行的回调函数
     */
    on(eventName, callback) {
        // 猎取已存在的事宜列表
        if(!events[eventName]) {
            events[eventName] = []
        }
        // 增加至数组
        events[eventName].push(callback)
    }

    /**
     * 事宜监听 (单次)
     * @param {String} eventName 事宜称号
     * @param {Function} callback 事宜触发后实行的回调函数
     */
    once(eventName, callback) {
        // 猎取已存在的单次事宜列表
        if(!events_one[eventName]) {
            events_one[eventName] = []
        }
        // 增加至数组
        events_one[eventName].push(callback)
    }

酱紫,每次增加事宜时,都邑放入我们的事宜列表中,然则!我们并没有给任何dom增加事宜,而仅仅是放入所对应的事宜列表中,奇怪了,看看我们之前的增加事宜要领

《【5+】跨webview多页面 触发事宜(二)》

给document监听一个事宜

《【5+】跨webview多页面 触发事宜(二)》

触发document事宜

nonono , 我们不这么借助document亦或许别的dom的事宜监听,还记得上一章的 evalJS(‘faqme()’)么?我们就用亲热的函数来触发事宜

事宜宣布

在事宜定阅当中,我们仅仅只是把事宜放入了事宜列表中,我们该怎样触发?

编写一个静态要领,用来触发当前页面的事宜, 然后经由过程

    static _emitSelf(eventName, data) {
        if(typeof data === 'string') {
            data = JSON.parse(data)
        }
        // 猎取悉数事宜列表 和 单次事宜列表,而且兼并
        let es = [...(events[eventName] || []), ...(events_one[eventName] || [])]
        // 遍历触发
        for(let f of es) {
            f && f.call(f, data)
        }
        // 单次事宜清空
        events_one[eventName] = []
    }

再合营修正一下 emit 内里的 evalJS

    /**
     * 事宜触发
     * @param {String} eventName 事宜称号
     * @param {Object} data 传参参数值
     * @param {Object} options 别的设置参数
     */
    emit(eventName, data, {
        self = false, // 是不是关照本身,默许不关照
        views = [], // 为空数组时,默许关照悉数,为string数组时,认为是id,为object时,认为是webview对象
    } = {}) {
        let all = []
        // 猎取 特定 webview 数组
        if(views.length > 0) {
            // 假如是string 范例,则一致处置惩罚猎取为 webview对象
            all.map(item => typeof item === 'string' ? plus.webview.getWebviewById(item) : item)
        } else {
            // 不特定关照的webview数组时,直接猎取悉数已存在的webview
            all = plus.webview.all()
        }
        // 假如不须要关照到当前webview 则过滤
        if(!self) {
            let v =  plus.webview.currentWebview()
            all = all.filter(item => item.id !== v.id)
        }
        // 遍历一切须要关照的页面
        for(let v of all) {
            /////////////////////////
            ////////////////这里是重点, 挪用Broadcast的静态要领
            /////////////////////////
            v.evalJS(`Broadcast && Broadcast._emitSelf && Broadcast._emitSelf('${eventName}', '${JSON.stringify(data)}')`)
        }
    }
    

这模样,就奇妙的触发了每一个webview页面 相对应的事宜,而且单次事宜也获得了消灭

事宜移除

我们晓得前面的事宜定阅只是将事宜存起来了,事宜移除响应的就是把事宜列表清空

    static _offSelf(eventName) {
        //清空事宜列表
        events[eventName] = []
        events_one[eventName] = []
    }

末了扫尾

所定义的2个静态要领,触发 和 移除 事宜,我们在内部代办2个响应的要领

    /**
     * 当前页面事宜触发 
     * @param {String} eventName 事宜称号
     * @param {Object} data 传参参数值
     */
    emitSelf(eventName) {
        Broadcast._emitSelf(eventName, data)
    }
    
    /**
     * 清空当前页面事宜 
     * @param {String} eventName 事宜称号
     */
    offSelf(eventName) {
        Broadcast._offSelf(eventName)
    }

末了,效果已涌现

A.html

            var b = new Broadcast()
            
            b.on('say', function(data){
                alert(JSON.stringify(data))
                
                // 删除本页面say事宜
                //b.offSelf('say')
            })
            
            b.once('say', function(data){
                //单次
                alert('单次:'+JSON.stringify(data))
            })

B.html

            new Broadcast().emit('say', {
                from: '我是B啊',
                id: 666
            })

末了附上源码:

/**
 * 5+ Broadcast.js by NewsNing 宁大大 
 */

// 猎取当前webview
const getIndexView = (() => {
        // 缓存
        let indexView = null
        return(update = false) => {
            if(update || indexView === null) {
                indexView = plus.webview.currentWebview()
            }
            return indexView
        }
    })(),
    // 猎取悉数webview 
    getAllWebview = (() => {
        // 缓存
        let allView = null
        return(update = false) => {
            if(update || allView === null) {
                allView = plus.webview.all()
            }
            return allView
        }
    })()

// 事宜列表
const events = {

    },
    // 单次事宜列表
    events_one = {

    }

//页面关照类
class Broadcast {
    /**
     * 组织器函数
     */
    constructor() {

    }

    /**
     * 事宜监听
     * @param {String} eventName 事宜称号
     * @param {Function} callback 事宜触发后实行的回调函数
     */
    on(eventName, callback) {
        // 猎取已存在的事宜列表
        if(!events[eventName]) {
            events[eventName] = []
        }
        // 增加至数组
        events[eventName].push(callback)
    }

    /**
     * 事宜监听 (单次)
     * @param {String} eventName 事宜称号
     * @param {Function} callback 事宜触发后实行的回调函数
     */
    once(eventName, callback) {
        // 猎取已存在的单次事宜列表
        if(!events_one[eventName]) {
            events_one[eventName] = []
        }
        // 增加至数组
        events_one[eventName].push(callback)
    }

    /**
     * 事宜触发
     * @param {String} eventName 事宜称号
     * @param {Object} data 传参参数值
     * @param {Object} options 别的设置参数
     */
    emit(eventName, data, {
        self = false, // 是不是关照本身,默许不关照
        views = [], // 为空数组时,默许关照悉数,为string数组时,认为是id,为object时,认为是webview对象
    } = {}) {
        let jsstr = `Broadcast && Broadcast._emitSelf && Broadcast._emitSelf('${eventName}', '${JSON.stringify(data)}')`
        this._sendMessage(jsstr, self, views)
    }

    /**
     * 当前页面事宜触发 
     * @param {String} eventName 事宜称号
     * @param {Object} data 传参参数值
     */
    emitSelf(eventName) {
        Broadcast._emitSelf(eventName, data)
    }

    /**
     * 事宜封闭移除
     * @param {String} eventName 事宜称号
     * @param {Object} options 别的设置参数
     */
    off(eventName, {
        self = false, // 是不是关照本身,默许不关照
        views = [] // 为空数组时,默许关照悉数,为string数组时,认为是id,为object时,认为是webview对象
    } = {}) {
        let jsstr = `Broadcast && Broadcast._offSelf && Broadcast._offSelf('${eventName}')`
        this._sendMessage(jsstr, self, views)
    }

    /**
     * 清空当前页面事宜  
     * @param {String} eventName 事宜称号
     */
    offSelf(eventName) {
        Broadcast._offSelf(eventName)
    }

    /**
     * 页面关照
     * @param {String} jsstr 须要运转的js代码
     * @param {Boolean} self 是不是关照本身,默许不关照
     * @param {Array} views 为空数组时,默许关照悉数,为string数组时,认为是id,为object时,认为是webview对象
     */
    _sendMessage(
        jsstr = '',
        self = false,
        views = []
    ) {
        let all = []
        // 猎取 特定 webview 数组
        if(views.length > 0) {
            // 假如是string 范例,则一致处置惩罚猎取为 webview对象
            all.map(item => typeof item === 'string' ? plus.webview.getWebviewById(item) : item)
        } else {
            // 不特定关照的webview数组时,直接猎取悉数已存在的webview
            all = getAllWebview(true)
        }
        // 假如不须要关照到当前webview 则过滤
        if(!self) {
            let v = getIndexView()
            all = all.filter(item => item.id !== v.id)
        }
        // 遍历悉数页面
        for(let v of all) {
            v.evalJS(jsstr)
        }
    }

    static _emitSelf(eventName, data) {
        if(typeof data === 'string') {
            data = JSON.parse(data)
        }
        // 猎取悉数事宜列表 和 单次事宜列表,而且兼并
        let es = [...(events[eventName] || []), ...(events_one[eventName] || [])]
        // 遍历触发
        for(let f of es) {
            f && f.call(f, data)
        }
        // 单次事宜清空
        events_one[eventName] = []
    }

    static _offSelf(eventName) {
        //清空事宜列表
        events[eventName] = []
        events_one[eventName] = []
    }

}

您也能够经由过程babel在线转化成es5 在线转换地点

《【5+】跨webview多页面 触发事宜(二)》

末了您还能够在github上看到一些别的5+ Api封装的源码 5+ api整合

class Man{
    constructor(){
        this.name = 'newsning'
    }
    say(){
        console.log('天行健, 正人以发奋图强. ')
    }
}
    原文作者:newsning
    原文地址: https://segmentfault.com/a/1190000008857298
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞