1.2.10 • Published 2 years ago

iframe-channel v1.2.10

Weekly downloads
3
License
MIT
Repository
github
Last release
2 years ago

iframe-channel

A channel used to communicate between iframe and parent. Support post function.

framework

Install

npm install iframe-channel --save

Demo

Local Demo

Online Demo

Code Examples

Say we have a page, which url is 'http://localhost:9876'. There is an iframe embedded within this page, which url is 'http://localhost:3000'. As follows:

use-case

We'll discuss how to conmmunicate between these two page over iframe-channel.

Child request connect

Parent Page

const testIframe = document.createElement('iframe')
testIframe.id = 'test-iframe'

const channel = new Channel({
  targetOrigin: 'http://localhost:3000'
})

channel.subscribe('connect', () => {
  // have connected
  // now send a message, whose type is 'xx' and data is 'hello'
  channel.postMessage('xx', 'hello').then((data) => {
    // will receive 'hello_hi' from child
    expect(data).to.be.equal('hello_hi')

    // destroy channel
    // Each Channel instance will add 'message' and 'beforeunload' event listener to window
    // object. So make sure destroy the instance once it's unused.
    channel.destroy()
    // destroy iframe
    testIframe.parentNode.removeChild(testIframe)
    done()
  })
})

testIframe.src = 'http://localhost:3000?type=demo_child_request_connect'
document.body.appendChild(testIframe)

Child Iframe

const channel = new Channel({
  targetOrigin: 'http://localhost:9876', // only accept targetOrigin's message
  target: window.parent // parent window
})
channel.subscribe('xx', (data, message, event) => {
  // data === 'hello'
  // message == { type: 'xx', data: 'hello' }
  return `${data}_hi`
})
channel.connect()

Parent request connect

Parent Page

import Channel from 'iframe-channel'

const testIframe = document.createElement('iframe')
testIframe.id = 'test-iframe'

testIframe.onload = () => {
  const channel = new Channel({
    targetOrigin: 'http://localhost:3000', // only accept targetOrigin's message.
    target: testIframe && testIframe.contentWindow
  })
  channel.connect().then(() => {
    // have connected
    // now send a message, whose type is 'xx' and data is 'hello'
    channel.postMessage('xx', 'hello').then((data) => {
      // will receive 'hello_hi' from child
      expect(data).to.be.equal('hello_hi')

      // destroy channel
      // Each Channel instance will add 'message' and 'beforeunload' event listener to window
      // object. So make sure destroy the instance once it's unused.
      channel.destroy()
      // destroy iframe
      testIframe.parentNode.removeChild(testIframe)
      done()
    })
  })
}

testIframe.src = 'http://localhost:3000?type=demo_parent_request_connect'
document.body.appendChild(testIframe)

Child Iframe

import Channel from 'iframe-channel'

const channel = new Channel({
  targetOrigin: 'http://localhost:9876' // only accept targetOrigin's message
})
channel.subscribe('xx', (data, message, event) => {
  // data === 'hello'
  // message == { type: 'xx', data: 'hello' }
  return `${data}_hi`
})

Post message before connect

iframe-channel support post message before connect. It will cache all postMessage requests. Then send these requests once the connection is established.

Parent Page

import Channel from 'iframe-channel'

const testIframe = document.createElement('iframe')
testIframe.id = 'test-iframe'

testIframe.onload = () => {
  const channel = new Channel({
    targetOrigin: 'http://localhost:3000', // only accept targetOrigin's message.
    target: testIframe && testIframe.contentWindow
  })
  // not connect yet
  // now send a message, whose type is 'xx' and data is 'hello'
  channel.postMessage('xx', 'hello').then((data) => {
    // will receive 'hello_hi' from child
    expect(data).to.be.equal('hello_hi')

    // destroy channel
    // Each Channel instance will add 'message' and 'beforeunload' event listener to window
    // object. So make sure destroy the instance once it's unused.
    channel.destroy()
    // destroy iframe
    testIframe.parentNode.removeChild(testIframe)
    done()
  })
  channel.connect()
}

testIframe.src = 'http://localhost:3000?type=demo_post_message_before_connect'
document.body.appendChild(testIframe)

Child Iframe

import Channel from 'iframe-channel'

const channel = new Channel({
  targetOrigin: 'http://localhost:9876' // only accept targetOrigin's message
})
channel.subscribe('xx', (data, message, event) => {
  // data === 'hello'
  // message == { type: 'xx', data: 'hello' }
  return `${data}_hi`
})

Post function

iframe-channel support post function, including async function.

Parent Page

const testIframe = document.createElement('iframe')
testIframe.id = 'test-iframe'

testIframe.onload = () => {
  const channel = new Channel({
    targetOrigin: 'http://localhost:3000', // only accept targetOrigin's message.
    target: testIframe && testIframe.contentWindow
  })
  channel.connect().then(() => {
    // data can be a function, or an object or an array which contains function.
    const data = {
      add: function (a, b) {
        return new Promise(resolve => {
          setTimeout(() => {
            resolve(a + b)
          }, 1000)
        })
      },
      a: [2, function (a, b) {
        return a * b
      }],
      parentData: 1
    }

    channel.postMessage('xx', data, {
      hasFunction: true,
      functionKeys: ['add', 'a[1]']
    }).then((data) => {
      // will receive 4 from child
      expect(data).to.be.equal(4)

      channel.destroy()
      testIframe.parentNode.removeChild(testIframe)
      done()
    })
  })
}
testIframe.src = 'http://localhost:3000?type=demo_post_function'
document.body.appendChild(testIframe)

Child Iframe

const channel = new Channel({
  targetOrigin: 'http://localhost:9876' // only accept targetOrigin's message
})
channel.subscribe('xx', (data, message, event) => {
  const childData = 1
  const { add, a = [], parentData } = data
  const multiply = a[1]
  return add(parentData, childData).then(res => {
    return multiply(res, a[0])
  })
})

API Documentation

Channel Class

Channel(options) => Channel

ParamTypeDescription
targetOriginstringThe channel will only accept targetOrigin's message.
targetwindowThe target window's object that the channel will connect to.
subscribersobjectThe subscribers object. Such as: { 'conncect': fun1, fun2, 'xx': fun1, fun2}. You can also use 'subscribe' function to register a subscriber after create a Channel instance.
attemptIntervalnumberThe interval between reconnect attempts. Default 1000ms.
maxAttemptsnumberThe max number of times we'll try to reconnect for. Default 10 times.

subscribe(type, fun?) => undefined

Register a function to subscribe a specific type of message.

channel.subscribe('xx', (data, message, event) => {
  // data === 'hello'
  // message == { type: 'xx', data: 'hello' }
  return `${data}_hi`
})

// fun can be a function array
channel.subscribe('xx', [fun1, fun2])
// type can be an object.
channel.subscribe({
  'xx': [fun1, fun2],
  'ff': fun3
})

unsubscribe(type?, fun?) => undefined

Remove subscribers.

// remove all
channel.unsubscribe()
// remove 'xx' type's subscribers
channel.unsubscribe('xx')
// remove 'xx' type's fun1 subscriber
channel.unsubscribe('xx', fun1)
// remove 'xx' type's fun1 and fun2 subscriber
channel.unsubscribe('xx', [fun1, fun2])
// remove 'xx' type's fun1 and 'xx1' type's fun3 and fun4 subscriber
channel.unsubscribe({
  'xx': fun1,
  'xx1': [fun3, fun4]
})

postMessage(type, data, opts?) => Promise

Post a specific type of message with data.

optsTypeDescription
hasFunctionboolDoes the data contain a function or it is a function?
functionKeysstring[]A path string array. iframe-channel will use lodash/get to fetch the function in the specific path. If hasFunction is true but functionKeys is undefined, iframe-channel will traverse the data's each field to collect functions. This may have performance issues.
channel.postMessage('xx', 'hello').then(data => {
  console.log(data)
}).catch(err => {
  console.log(err)
})

connect() => Promise

Connect to the target.

channel.connect().then(() => {
  // postMessage
}).catch(err => {
  console.log(err)
})

clearQueue() => undefined

Clear postMesasge queue. Channel will queue postMessage requests that was sent before connect.

channel.clearQueue()

destroy() => undefined

destroy a Channel instance. Including: 1. clear subscribers. 2. clear postMessage queue. 3. remove window's message event listener. 4. reset inner state.

channel.destroy()

License

MIT

Copyright (c) 2019-present Chunlin He

1.2.8

2 years ago

1.2.7

2 years ago

1.2.6

2 years ago

1.2.9

2 years ago

1.2.10

2 years ago

1.2.5

3 years ago

1.2.4

3 years ago

1.2.3

3 years ago

1.2.2

3 years ago

1.2.1

5 years ago

1.2.0

5 years ago

1.1.0

5 years ago

1.0.0

5 years ago