1. 程式人生 > 其它 >關於新開頁面的傳值問題

關於新開頁面的傳值問題

歡迎大家訪問我的部落格dreamITGirl,不要吝嗇你們的小星星,點個star~ 有問題的話,你可以將問題在 GitHub問我.

新開瀏覽器頁籤的傳值問題

1. 業務背景

在新建/修改/詳情等二級或者三級新開啟的頁籤中,需要實現傳遞引數的功能,並同時重新整理上一級頁面

2. 思考方式:

  1. 使用 localStorage 的方式
    這種方式的最大的弊端是當專案較大的時候儲存的資訊量極易超過瀏覽器中要求的儲存空間。所以我們在第一次迭代時放棄了這種方式。
  2. 使用window.postMessage
    這種方式在列表頁面中開啟一個新建頁面時是沒有問題的,但是當開啟多個新建頁面,這個傳的值就會發生問題。導致資訊接收失敗。在調研這個方式後也放棄了這種思路
  3. 自封裝外掛
    思路:採用了JS開啟頁面的初始化事件,利用H5的新特性history來實現的。

3. 程式碼解析

主要是利用了history中的pushStatereplaceState這兩個API,通過監聽頁面的渲染順序,將函式設計成釋出/訂閱者模式,從而達到想要的效果

function parseConfig (config) { // 將傳遞的引數String化
    let str = ''
    for (let key in config) {
        if (config[key] !== null) {
            str+=`${key}=${config[key]},`
        }
    }
    return str
}

const _historyWrap = function(type) { 
    const orig = history[type];
    const e = new Event(type);
    return function() {
        const rv = orig.apply(this, arguments);
        e.arguments = arguments;
        window.dispatchEvent(e); // 向一個指定的事件目標派發一個事件,  並以合適的順序同步呼叫目標元素相關的事件處理函式
        return rv;
    }
};

history.pushState = _historyWrap('pushState');
history.replaceState = _historyWrap('replaceState');

class Win {
    constructor (url, config) {
        config = config || {}
        if (!url) {
            throw Error('url is not defined!')
        }
        let name = '_'+Date.now() // 確保name的唯一性
        this.win = window.open(url, name, parseConfig(config))
        window.addEventListener('beforeunload', ()=>{this.win.close()}) // 監聽window,document 及其資源即將被載。
        window.addEventListener('pushState', ()=>{this.win.close()}); // history在會話歷史堆疊頂部插入一條記錄
        window.addEventListener('replaceState', ()=>{this.win.close()}); // history更新會話歷史堆疊頂部記錄資訊
        window.addEventListener('popstate', ()=>{this.win.close()}); //history在會話歷史堆疊頂部彈出一條記錄
        if (this.win === null) {
            alert('請將“彈出式視窗和重定向”設定為允許')
            throw Error('新視窗建立失敗,視窗被攔截!')
        }
        return this
    }
    on(eventName, cb) {
        if (eventName === 'load') {
            this.win.onload = (ev) => {
                cb(ev, this)
            }
        }
        if (eventName === 'message') {
            let _this = this
            function closeListener() {
                setTimeout(()=>{
                    _this.win.send = function(message){
                        cb(message)
                    }
                    _this.win.addEventListener('unload', closeListener)
                })
            }
            this.win.addEventListener('unload', closeListener)
        }
    }
    close(cb) {
        cb && cb()
        window.name = 'Win_'+Date.now()
        this.win.open('',window.name)
        window.name = ''
        this.win.close()
    }
}

4. 知識點連結