PresentationAPI使用教程(Vue3&html)

大祥子
2022-07-08 / 43 评论 / 798 阅读 / 正在检测是否收录...

 W3C在2020年12月份出台了Presentation API规范,这个api接口允许用户自由控制投放在其他屏幕上,并和投放窗口通信,查看W3C规范。演示地址:投屏演示,详细demo(Vue3/HTML)见文章末尾


 1、创建一个PresentationRequest对象,该对象将包含我们要在辅助附加显示器上显示的地址。
const presentationRequest = new PresentationRequest('receiver.html');
 2、做控制及监听事件

/*
 * @Author: lzx
 * @Date: 2022-07-08 15:34:16
 * @LastEditors: lzx
 * @LastEditTime: 2022-07-08 17:14:31
 * @Description: Fuck Bug
 * @FilePath: \test\js\index.js
 */
// 创建个投屏对象
const presentationRequest = new PresentationRequest(['https://blog.fxnws.com']); // 投屏网址
// const presentationRequest = new PresentationRequest(['test.html']);//投屏页面

// Make this presentation the default one when using the "Cast" browser menu.
navigator.presentation.defaultRequest = presentationRequest;
let presentationConnection;

//监视连接是否可用
presentationRequest.addEventListener('connectionavailable', function (event) {
  presentationConnection = event.connection;
  presentationConnection.addEventListener('close', function () {
    console.log('> Connection closed.');
  });
  presentationConnection.addEventListener('terminate', function () {
    console.log('> Connection terminated.');
  });
  presentationConnection.addEventListener('message', function (event) {
    console.log('> ' + event.data);
  });
});

//监视可用的显示器
presentationRequest.getAvailability()
  .then(availability => {
    console.log('Available presentation displays: ' + availability.value);
    availability.addEventListener('change', function () {
      console.log('> Available presentation displays: ' + availability.value);
    });
  })
  .catch(error => {
    console.log('Presentation availability not supported, ' + error.name + ': ' +
      error.message);
  });
// 开启投屏
function startProjectionScreen () {
  presentationRequest.start()
    .then(connection => {
      console.log('Connected to ' + connection.url + ', id: ' + connection.id);
    })
    .catch(error => {
      console.log(error);
    });
}

//发送消息
function sendMsg () {
  const message = '发送消息测试';
  const lang = document.body.lang || 'en-US';

  console.log('Sending "' + message + '"...');
  presentationConnection.send(JSON.stringify({ message, lang }));
}

//关闭连接,关闭连接后无法再控制弹出窗口
function closeLink () {
  console.log('Closing connection...');
  presentationConnection.close();
}
//关闭连接后,换可以重新再次连接,这里需要指定id
// presentationRequest.reconnect(presentationId);

//关闭弹窗,结束连接调用
function endLink () {
  console.log('Terminating connection...');
  presentationConnection.terminate();
}

 3、连接端页面消息的展示(搬运的官方)

/*
 * @Author: lzx
 * @Date: 2022-07-08 15:34:16
 * @LastEditors: lzx
 * @LastEditTime: 2022-07-08 15:34:30
 * @Description: Fuck Bug
 * @FilePath: \test\js\test.js
 */
let connectionIdx = 0;
let messageIdx = 0;

//如果有连接建立,则调用该函数
function addConnection (connection) {
  connection.connectionId = ++connectionIdx;
  addMessage('New connection #' + connectionIdx);
  connection.addEventListener('message', function (event) {
    messageIdx++;
    const data = JSON.parse(event.data);
    const logString = 'Message ' + messageIdx + ' from connection #' +
      connection.connectionId + ': ' + data.message;
    addMessage(logString, data.lang);
    maybeSetFruit(data.message);
    connection.send('Received message ' + messageIdx);
  });

  connection.addEventListener('close', function (event) {
    addMessage('Connection #' + connection.connectionId + ' closed, reason = ' +
      event.reason + ', message = ' + event.message);
  });
};

const fruitEmoji = {
  'grapes': '\u{1F347}',
  'watermelon': '\u{1F349}',
  'melon': '\u{1F348}',
  'tangerine': '\u{1F34A}',
  'lemon': '\u{1F34B}',
  'banana': '\u{1F34C}',
  'pineapple': '\u{1F34D}',
  'green apple': '\u{1F35F}',
  'apple': '\u{1F34E}',
  'pear': '\u{1F350}',
  'peach': '\u{1F351}',
  'cherries': '\u{1F352}',
  'strawberry': '\u{1F353}'
};

function addMessage (content, language) {
  const listItem = document.createElement("li");
  if (language) {
    listItem.lang = language;
  }
  listItem.textContent = content;
  document.querySelector("#message-list").appendChild(listItem);
};

function maybeSetFruit (message) {
  const fruit = message.toLowerCase();
  if (fruit in fruitEmoji) {
    document.querySelector('#main').textContent = fruitEmoji[fruit];
  }
};

//文档载入后,监听连接
document.addEventListener('DOMContentLoaded', function () {
  if (navigator.presentation.receiver) {
    navigator.presentation.receiver.connectionList.then(list => {
      list.connections.map(connection => addConnection(connection));
      list.addEventListener('connectionavailable', function (event) {
        addConnection(event.connection);
      });
    });
  }
});

 4、接收端页面构

<!--
 * @Author: lzx
 * @Date: 2022-07-08 15:34:05
 * @LastEditors: lzx
 * @LastEditTime: 2022-07-08 15:35:13
 * @Description: Fuck Bug
 * @FilePath: \test\test.html
-->
<!doctype html>
<html>

<head>
  <meta charset="utf-8">
  <title>Demo Receiver</title>
  <style type="text/css">
    html,
    body {
      height: 100%;
      margin: 0;
      font-family: sans-serif;
      background: radial-gradient(ellipse at center, #333333 0%, #000000 100%);
      color: #fff;
    }

    #main {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      text-align: center;
      font-size: 54px;
    }
  </style>
  <script type="text/javascript" src="引入3的代码块"></script>
</head>

<body>
  <div id="main">Hello World!</div>
  <ul id="message-list">
  </ul>
</body>

</html>

 5、vue3页面

<template>
  <div class="container">
    <button @click="startProjectionScreen">开启投屏</button>
    <button @click="sendMsg">发送消息</button>
    <!-- <button @click="closeLink">关闭连接</button> -->
    <button @click="endLink">结束调用</button>
  </div>
</template>

<script lang="ts">
// @ts-nocheck 不在当前文件中执行类型检查
import { toRefs, reactive, onMounted, watchEffect, onUnmounted } from 'vue'
export default {
  props: {},
  components: {},
  setup () {
    const presentationRequest = new PresentationRequest(['https://blog.fxnws.com']); // 投屏网址
    // const presentationRequest = new PresentationRequest(['test.html']); // 投屏本地页面
    navigator.presentation.defaultRequest = presentationRequest;
    let presentationConnection;
    // 传参
    const state = reactive({
    })
    const startProjectionScreen = () => {
      presentationRequest.start()
        .then(connection => {
          console.log('Connected to ' + connection.url + ', id: ' + connection.id);
        })
        .catch(error => {
          console.log(error);
        });
    }
    //发送消息
    const sendMsg = () => {
      const message = '发送消息测试';
      const lang = document.body.lang || 'en-US';

      console.log('Sending "' + message + '"...');
      presentationConnection.send(JSON.stringify({ message, lang }));
    }

    //关闭连接,关闭连接后无法再控制弹出窗口
    const closeLink = () => {
      console.log('Closing connection...');
      presentationConnection.close();
    }
    //关闭连接后,换可以重新再次连接,这里需要指定id
    // presentationRequest.reconnect(presentationId);

    //关闭弹窗,结束连接调用
    const endLink = () => {
      console.log('Terminating connection...');
      presentationConnection.terminate();
    }
    // 挂载
    onMounted(() => {
      //监视连接是否可用
      presentationRequest.addEventListener('connectionavailable', function (event) {
        presentationConnection = event.connection;
        presentationConnection.addEventListener('close', function () {
          console.log('> Connection closed.');
        });
        presentationConnection.addEventListener('terminate', function () {
          console.log('> Connection terminated.');
        });
        presentationConnection.addEventListener('message', function (event) {
          console.log('> ' + event.data);
        });
      });
      //监视可用的显示器
      presentationRequest.getAvailability()
        .then(availability => {
          console.log('Available presentation displays: ' + availability.value);
          availability.addEventListener('change', function () {
            console.log('> Available presentation displays: ' + availability.value);
          });
        })
        .catch(error => {
          console.log('Presentation availability not supported, ' + error.name + ': ' +
            error.message);
        });
    })
    // 监听
    watchEffect(() => {
      console.log('监听')
    })
    // 页面卸载
    onUnmounted(() => {
      console.log('页面卸载')
    })
    return {
      ...toRefs(state), endLink, closeLink, sendMsg, startProjectionScreen
    }
  }
}
</script>

<style scoped>
</style>

 6、详细demo附件下载

2024年11月04日更新,看到评论区有部分朋友,遇到问题,我更新了相关Git完整Demo地址见下文
1、vue3+ts+vite 报错 PresentationRequest 未定义
答:应该是ts未定义的报错,我当时做这个的时候,这个功能刚推出ts支持应该不完善,我也不想去定义相关的ts就直接使用// @ts-nocheck(这个指令用于告诉TypeScript编译器不在当前文件中执行类型检查)
2、发现用ip访问不行,用127.0.0.1可以
答:直接用IP不行是因为没有https支持吧,我记得这个协议是需要https的支持的,具体要看下报错信息了,127.0.0.1是本机地址所以没事


0

评论 (43)

取消
  1. 头像
    大祥子 作者
    Windows 10 · Google Chrome

    2024年11月04日更新,看到评论区有部分朋友,遇到了些问题,文章末尾有更新,相关的Git仓库地址也附上了表情

    回复
  2. 头像
    韭菜花
    Windows 10 · Google Chrome

    secondScreen.vue:16 Uncaught (in promise) ReferenceError: PresentationRequest is not defined
    的确不行,会报这样的错,vue3.4+ts+vite5.3

    回复
    1. 头像
      大祥子 作者
      Windows 10 · Google Chrome
      @ 韭菜花

      我刚刚测试,并没有出现综上所出现的问题,我的版本信息如下
      "vue": "^3.5.12"
      "typescript": "~5.6.2",
      "vite": "^5.4.10",

      回复
    2. 头像
      大祥子 作者
      Windows 10 · Google Chrome
      @ 韭菜花

      这个得空我看看,之前也有人说过不行

      回复
    3. 头像
      韭菜花
      Windows 10 · Google Chrome
      @ 韭菜花

      发现用ip访问不行,用127.0.0.1可以

      回复
      1. 头像
        大祥子 作者
        Windows 10 · Google Chrome
        @ 韭菜花

        用IP不行是因为没有https支持吧,我记得这个协议是需要https的支持的,具体要看下报错信息了

        回复
        1. 头像
          韭菜花
          Windows 10 · Google Chrome
          @ 大祥子

          完了这个只能支持 https下使用,此功能仅在安全上下文(HTTPS)中可用表情

          回复
          1. 头像
            大祥子 作者
            Windows 10 · Google Chrome
            @ 韭菜花

            是的,所以我特别注明需要注意必须为https环境

            回复
  3. 头像
    韭菜花
    Windows 10 · Google Chrome

    表情

    回复
  4. 头像
    k
    Windows 10 · Google Chrome

    学习下

    回复
  5. 头像
    asd
    MacOS · Google Chrome

    1

    回复
  6. 头像
    春风
    Windows 10 · Google Chrome

    vue 在方法中new PresentationRequest会提示Cannot read properties of undefined (reading 'PresentationRequest')

    回复
    1. 头像
      大祥子 作者
      Windows 10 · Google Chrome
      @ 春风

      如果报错,请检查你的代码校验工具,将这个错误忽略。

      回复
  7. 头像
    陈炜祥
    Windows 10 · Google Chrome

    1

    回复
  8. 头像
    wwj5925
    MacOS · Google Chrome

    求demo 大佬

    回复
    1. 头像
      大祥子 作者
      Windows 10 · Google Chrome
      @ wwj5925

      你需要啥样的demo,我附件中是已经有原生的demo和vue3的了

      回复
  9. 头像
    飞蛾救火
    Windows 10 · Google Chrome

    是有vite打包后 提示ReferenceError: PresentationRequest is not defined 大佬知道如何解决么

    回复
    1. 头像
      大祥子 作者
      Windows 10 · Google Chrome
      @ 飞蛾救火

      文章的示例代码和示例代码文件,我都更新了,可以参考

      回复
    2. 头像
      大祥子 作者
      Windows 10 · Google Chrome
      @ 飞蛾救火

      这个是TS的报错吧,直接使用 // @ts-nocheck(这个指令用于告诉TypeScript编译器不在当前文件中执行类型检查)

      回复
  10. 头像
    飞蛾救火
    Windows 10 · Google Chrome

    vue3+ts+vite 报错 PresentationRequest 未定义 大佬知道什么问题么

    回复
  11. 头像
    kkkk
    Windows 10 · Google Chrome

    向大神学习

    回复
  12. 头像
    kk
    MacOS · Google Chrome

    学习一下

    回复
  13. 头像
    小飞
    Windows 10 · Google Chrome

    没看到vue demo啊

    回复
    1. 头像
      大祥子 作者
      Windows 10 · Google Chrome
      @ 小飞

      下载demo,里面有个vue的demo页

      回复
  14. 头像
    fh
    Windows 10 · Google Chrome

    6666

    回复
    1. 头像
      大祥子 作者
      Windows 10 · Google Chrome
      @ fh

      表情

      回复
  15. 头像
    daxigua
    MacOS · Google Chrome

    demo

    回复
    1. 头像
      大祥子 作者
      Windows 10 · Google Chrome
      @ daxigua

      文章末尾有demo可以直接下载!

      回复
  16. 头像
    安安
    Windows 10 · Google Chrome

    好东西

    回复
    1. 头像
      大祥子 作者
      Windows 10 · Google Chrome
      @ 安安

      表情

      回复
  17. 头像
    chengxun
    Windows 10 · Google Chrome

    1111

    回复
    1. 头像
      大祥子 作者
      Windows 10 · Google Chrome
      @ chengxun

      666

      回复
  18. 头像
    tset
    Windows 10 · Google Chrome

    学习一下

    回复
    1. 头像
      大祥子 作者
      Windows 10 · Google Chrome
      @ tset

      加油

      回复
  19. 头像
    12321
    Windows 10 · Google Chrome

    想试试

    回复
    1. 头像
      大祥子 作者
      Windows 10 · Google Chrome
      @ 12321

      直接下载demo尝试吧

      回复
  20. 头像
    AKouhhh
    Windows 10 · Google Chrome

    猛猛猛

    回复
  21. 头像
    aa
    Windows 10 · Google Chrome

    1

    回复
    1. 头像
      大祥子 作者
      Windows 10 · Google Chrome
      @ aa

      表情

      回复
  22. 头像
    !@
    Windows 10 · Google Chrome

    vue 报错

    回复
    1. 头像
      大祥子 作者
      Windows 10 · Google Chrome
      @ !@

      具体报啥错误,您可以看下,我的demo,之前下载链接失效了,现在更新了

      回复
  23. 头像
    大橙子
    MacOS · Google Chrome

    vue都创建不了PresentationRequest对象呀,敢问大佬如何实现的

    回复
    1. 头像
      大祥子 作者
      Windows 10 · Google Chrome
      @ 大橙子

      vue可以阿,直接new就行了,具体你可以看下我的demo,之前demo下载失效了,我现在更新了

      回复