代码之家  ›  专栏  ›  技术社区  ›  Jayd

ServiceWorker在生命周期后期声明要使用客户端.navigate在notificationclick事件处理程序中

  •  1
  • Jayd  · 技术社区  · 8 年前

    /* eslint-env worker */
    /* eslint no-restricted-globals: 1 */
    /* global firebase */
    /* global clients */
    
    import config from './config'
    
    importScripts('https://www.gstatic.com/firebasejs/4.8.1/firebase-app.js')
    importScripts('https://www.gstatic.com/firebasejs/4.8.1/firebase-messaging.js')
    
    const { FIREBASE_MESSAGING_SENDER_ID } = config
    
    firebase.initializeApp({ messagingSenderId: FIREBASE_MESSAGING_SENDER_ID })
    const messaging = firebase.messaging()
    
    messaging.setBackgroundMessageHandler(payload => {
      const title = payload.data.title
      const options = {
        body: payload.data.body,
        icon: payload.data.icon,
        data: payload.data,
      }
    
      clients.matchAll({ includeUncontrolled: true }).then(clientz => {
        clientz.forEach(client => {
          sendMessageToClient(client, 'NEW_USER_NOTIFICATON')
        })
      })
      return self.registration.showNotification(title, options)
    })
    
    const sendMessageToClient = (client, message) => {
      const messageChannel = new MessageChannel()
      client.postMessage(message, [messageChannel.port2])
    }
    

    我想做的是有一个click函数,它关注于正确的窗口/选项卡,并导航到传递给它的链接。或者,如果选项卡未打开,请打开一个新窗口并转到链接。

    这是我到目前为止添加到上述文件中的代码。

    self.addEventListener('notificationclick', event => {
      const clickedNotification = event.notification
      const link = clickedNotification.data.link
      clickedNotification.close()
      const promiseChain = self.clients.claim()
        .then(() => self.clients
          .matchAll({
            type: 'window',
          })
        )
        .then(windowClients => {
          let matchingClient = null
          windowClients.forEach(client => {
            if (client.url.includes(matching_url)) {
              matchingClient = client
            }
          })
          if (matchingClient) {
            return matchingClient.navigate(link)
              .then(() => matchingClient.focus())
          }
          return clients.openWindow(link)
        })
    
      event.waitUntil(promiseChain)
    })
    

    所以,我意识到 navigate 和 focus 内部 then 这可能是不好的做法,但现在,我只是想让它发挥作用。然后我会想出一个聪明的解决办法。

    所以我的代码的问题是 clients.claim() 好像没用。这个 matchAll 然后

    includeUncontrolled: true 选择 匹配 导航

    如果我尝试经常引用的 Google example 对于声明和导航,它很好:

    self.addEventListener('activate', event => {
      event.waitUntil(self.clients.claim().then(() => {
        // See https://developer.mozilla.org/en-US/docs/Web/API/Clients/matchAll
        return self.clients.matchAll({type: 'window'});
      }).then(clients => {
        return clients.map(client => {
          // Check to make sure WindowClient.navigate() is supported.
          if ('navigate' in client) {
            return client.navigate('activated.html');
          }
        });
      }));
    });
    

    所以我被卡住了。

    我是不是爱上了一个随机应变的军人? 只能在处理激活事件时使用和导航到该声明吗?

    干杯

    1 回复  |  直到 8 年前
        1
  •  0
  •   Jayd    8 年前

    我没法让它发挥作用。

    但我认为值得记录我的解决方法。

    client.navigate 在 notificationclick 事件处理程序。

    postMessage 包含要在我的应用程序中拾取以触发重定向的URL,而没有任何客户端在任何地方声明。

    self.addEventListener('notificationclick', event => {
      const clickedNotification = event.notification
      const link = clickedNotification.data.link
      clickedNotification.close()
      const promiseChain = self.clients.matchAll({
          type: 'window',
          includeUncontrolled: true,
        })
        .then(windowClients => {
          let matchingClient = null
          windowClients.forEach(client => {
            if (client.url.includes(matching_url)) {
              matchingClient = client
            }
          })
          if (matchingClient) {
            sendMessageToClient(matchingClient, { type: 'USER_NOTIFICATION_CLICKED', link })
            return matchingClient.focus()
          }
          return clients.openWindow(link)
        })
    
      event.waitUntil(promiseChain)
    })
    
    const sendMessageToClient = (client, message) => {
      const messageChannel = new MessageChannel()
      client.postMessage(message, [messageChannel.port2])
    }