H5 新增内容大全(包括Web Workers、SSE、WebSocket的详细使用代码)

简介: H5 新增内容大全(包括Web Workers、SSE、WebSocket的详细使用代码)

目录


前言

canvas和内联SVG

本地存储 localStorage与sessionStorage

requestAnimationFrame

媒体标签 video和audio

内容拖放

地理位置获取

新的语义化标签

新的input类型

新的表单元素

新的表单属性

应用程序缓存

Web Workers

Server-Sent Events(nodejs案例)

WebSocket(nodejs案例)


前言


H5内容之前一直没抽出时间整理,做个归纳使用的笔记。


记录包括一些新的标签、属性、新的api。


还有拖放drag、Web Workers、SSE与nodejs、WebSocket与nodejs的前后端详细使用案例。


canvas和内联SVG


canvas


自定义图形图表,基于js的绘图api描述 2D 图形。

逐像素进行渲染,因此一旦被渲染就不会被浏览器关注了,不过可以搭配requestAnimationFrame重新绘制制作页面动画。

<body>
    <canvas id="myCanvas" width="200" height="100" style="border:1px solid #000000;">
    </canvas>
</body>
<script>
    var c = document.getElementById("myCanvas");
    var ctx = c.getContext("2d");
    ctx.fillStyle = "#FF0000";
    ctx.fillRect(0, 0, 150, 75);
</script>

svg

  1. 是一种使用 XML 描述 2D 图形的语言。
  2. 每个被绘制的图形均被视为对象。如果 SVG 对象的属性发生变化,那么浏览器能够自动重现图形。
    <svg height="190">
        <polygon points="100,10 40,180 190,60 10,60 160,180"
            style="fill:lime;stroke:purple;stroke-width:5;fill-rule:evenodd;">
    </svg>

本地存储 localStorage与sessionStorage


本地存储,缓存一些数据在浏览器。

localStorage与sessionStorage区别就是sessionStorage只在一次会话中有效,关闭浏览器再打开就失效,而localstorage除非手动清除否则仍然有效。

与cookie区别是,Storage不会传去服务端,且存储内容比较大,cookie的可存储内容是比较小的。

使用方法我单独记录过:一分钟掌握本地缓存localstorage使用方法。

requestAnimationFrame


  1. 简称raf,面试时可能会被问到。
  2. 使用方法:在声明的函数fun中调用requestAnimationFrame(fun)。
  3. 相对于setTimeout实现动画来说,raf运行时会根据浏览器的绘制频率运行,所以不会掉帧看起来很流畅。
    const test = () => {
        //...执行内容
        requestAnimationFrame(test)
    }
    test()

媒体标签 video和audio


  1. 音频与视频,h5嵌入音频与视频使用的标签,比较方便。
<video width="320" height="240" controls>
  <source src="movie.mp4" type="video/mp4">
  <source src="movie.ogg" type="video/ogg">
  您的浏览器不支持Video标签。
</video>
<audio controls>
  <source src="horse.ogg" type="audio/ogg">
  <source src="horse.mp3" type="audio/mpeg">
  您的浏览器不支持 audio 元素。
</audio>

内容拖放


被拖动的内容

  1. 添加draggable="true",表示允许被拖放。
  2. 添加ondragstart事件,表示拖放时储存的数据,可以将event作为入参,方便我们使用信息。
    <img id="drag" src="./xx.jpg" draggable="true" ondragstart="drag(event)" width="336" height="69">
  1. event.dataTransfer.setData可以储存我们拖放时内容的信息,我们可以将id存入,入参前面是key,后面是value。
    function drag(e) {
        e.dataTransfer.setData("Text", e.target.id);
    }

存放内容的容器或位置


默认是不允许被拖放的,因此我们要给ondragover和ondrop事件添加阻止默认事件。

添加ondrop事件,这个是鼠标将东西拖到该容器并松手时触发的事件,它可以用e.dataTransfer.getData读取ondragstart事件中使用event.dataTransfer.setData储存的值。

用id选中被托放的内容,让容器调用appendChild将内容添加进自己的内容区。

    <div id="box" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
    function allowDrop(e) {
        e.preventDefault();
    }
    function drop(e) {
        e.preventDefault();
        var id = e.dataTransfer.getData("Text");
        e.target.appendChild(document.getElementById(id));
    }

原理


只要是被拖放的内容添加了draggable="true",当它被appendChild调用添加进别的内容时,就会发生回流,让原来的被托放内容消失,就给人带来了拖放的效果。

我尝试手动添加按钮不进行拖动操作,发现只要达到了上面的条件,即便把被拖动元素的拖动事件删除,也可以实现效果,从原来的位置移动到目标容器位置。

    <button onclick="test()">点击试试</button>
    function test() {
        document.getElementById('box').appendChild(document.getElementById('drag'))
    }

完整示例

<style>
    #box {
        width: 350px;
        height: 70px;
        padding: 10px;
        border: 1px solid #aaaaaa;
    }
</style>
<body>
    <p>拖动图片到矩形框中:</p>
    <div id="box" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
    <br>
    <img loading="lazy" id="drag" src="./xxx.jpg" ondragstart="drag(event)"
        draggable="true" width="336" height="69">
    <button onclick="test()">点击试试</button>
</body>
<script>
    function allowDrop(e) {
        e.preventDefault();
    }
    function drag(e) {
        e.dataTransfer.setData("Text", e.target.id);
    }
    function drop(e) {
        e.preventDefault();
        var data = e.dataTransfer.getData("Text");
        e.target.appendChild(document.getElementById(data));
    }
    function test() {
        document.getElementById('box').appendChild(document.getElementById('drag'))
    }
</script>

地理位置获取


  1. navigator.geolocation.getCurrentPosition获取位置,入参为函数。
  2. 函数会获得一个参数position,经纬度分别为position.coords.longitude和position.coords.latitude。
<body>
  <p id="demo">点击按钮获取您当前坐标(可能需要比较长的时间获取):</p>
  <button onclick="getLocation()">点我</button>
  <script>
    var x = document.getElementById("demo");
    function getLocation() {
      if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(showPosition);
      }
      else {
        x.innerHTML = "该浏览器不支持获取地理位置。";
      }
    }
    function showPosition(position) {
      x.innerHTML = "纬度: " + position.coords.latitude +
        "<br>经度: " + position.coords.longitude;
    }
  </script>
</body>

新的语义化标签



header,section, footer, aside, nav, main, article, figure


新的input类型



color,date,datetime,datetime-local,email,month,number,range,search,tel,time,url,week


新的表单元素



datalist


将input的list属性与datalist的id设置为相同的即可给input绑定一个待输入内容框,list属性也是h5新的表单属性。

    <input list="listName">
    <datalist id="listName">
        <option value="value1">
        <option value="value2">
        <option value="value3">
        <option value="value4">
        <option value="value5">
    </datalist>

image.png

output

  1. 用于不同类型的输出,比如计算或脚本输出
<form oninput="x.value=parseInt(a.value)+parseInt(b.value)">0
<input type="range" id="a" value="50">100 +
<input type="number" id="b" value="50">=
<output name="x" for="a b"></output>
</form>

image.png

新的表单属性


(已经常见的)


常见于number:min、max、step。

常见于file:multiple 。

与datalist有关:list。

其他:autofocus、multiple 、placeholder 、required、pattern、height 、width。

(不常见与不常用)


autocomplete


form与input中可以添加该属性,决定是否自动完成,form添加了true所有input都会自动完成,不过input可以单独添加false,会以input单独添加的优先。

自动完成效果就是进行过提交的输入数据,再次输入该表单时可能会显示过去输入过的提示。

有些浏览器会自动存在该功能,有些需要自己手动添加。

<form action="demo" autocomplete="on">
  name:<input type="text" name="fname"><br>
  E-mail: <input type="email" name="email" autocomplete="off"><br>
  <input type="submit">
</form>

image.png

novalidate

  1. form添加该属性将不再input进行过滤,比如type="email"的input也允许随意输入。
<form action="demo" novalidate>
  E-mail: <input type="email" name="user_email">
  <input type="submit">
</form>

其他


还有一些关于覆盖表单属性的属性,个人并不常用,有兴趣自己查询:form 、formaction 、formenctype 、formmethod、formnovalidate 、formtarget 。


应用程序缓存


给html标签添加manifest="demo.appcache",并在html同源创建demo.appcacheManifest文件就可以进行缓存,访问过的页面,离线了再次访问仍然可以访问。

通过Manifest文件配置要缓存的内容,添加版本为了可以更好的更新缓存,底下列出来的就是要缓存的同源文件。

缓存容量存在限制。

demo.appcache

CACHE MANIFEST
#v0.0.1
/index.html
/...
/...

Web Workers


  1. 运行在后台的js,不影响页面性能。
  2. 检测用户浏览器是否支持。
    if (typeof (Worker) !== undefined) {
        console.log('支持Web worker')
    }
  1. 在外部编写要运行的js文件,也就是web worker 文件。

test.js

let i = 0
setInterval(() => {
  i++
  //postMessage传递数据
  postMessage(i)
}, 1000)
  1. 在html页面接收,onmessage监听web worker 文件的postMessage事件,onmessage参数event中有一个data属性就是从postMessage传来的。
    let w
    if (typeof (Worker) !== undefined) {
        w = new Worker("/test.js")
    }
    w.onmessage = (event) => {
        console.log(event.data)//1...2...3.....
    }
  1. w.terminate()终止Web Worker
<body>
    <button onclick="start()">使用Web Worker</button>
    <button onclick="stop()">终止Web Worker</button>
</body>
<script>
    let w
    const start = () => {
        if (typeof (Worker) !== undefined) {
            w = new Worker("/test.js")
        }
        w.onmessage = (e) => {
            console.log(e.data)
        }
    }
    const stop = () => {
        w.terminate();
    }
</script>

注意html用本地文件打开不支持Web Worker,最好部署一下,比如用nginx代理一下静态页面。

Server-Sent Events(nodejs案例)


简称SEE,服务器发送事件,网页自动获取来自服务器的更新,单向消息传递。

编写nodejs服务端


创建一个服务放在8844端口,我这里命名为/stream,我用的express,不喜欢的话用http也行。


res.set请求头的设置很关键,'Content-Type': 'text/event-stream'这种是sse必须的类型,'Access-Control-Allow-Origin': '*'解决跨域方便测试。


res.write进行消息推送,因为要保持连接,所以肯定不能用send。

import express from 'express'
const app = new express()
app.use(express.json())
app.get('/stream', (req, res) => {
  res.set({
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    Connection: 'keep-alive',
    'Access-Control-Allow-Origin': '*',
  })
  res.write('retry: 10000\n')
  res.write('event: connecttime\n')
  res.write('data: ' + new Date() + '\n\n')
  res.write('data: ' + new Date() + '\n\n')
  let interval = setInterval(function () {
    res.write('data: ' + new Date() + '\n\n')
  }, 1000)
  req.connection.addListener(
    'close',
    function () {
      clearInterval(interval)
    },
    false
  )
})
app.listen(8844, () => {
  console.log('开启')
})
// 以下是使用http的方案,同理
// import http from 'http'
// http
//   .createServer(function (req, res) {
//     var fileName = '.' + req.url
//     if (fileName === './stream') {
//       res.writeHead(200, {
//         'Content-Type': 'text/event-stream',
//         'Cache-Control': 'no-cache',
//         Connection: 'keep-alive',
//         'Access-Control-Allow-Origin': '*',
//       })
//       res.write('retry: 10000\n')
//       res.write('event: connecttime\n')
//       res.write('data: ' + new Date() + '\n\n')
//       res.write('data: ' + new Date() + '\n\n')
//       let interval = setInterval(function () {
//         res.write('data: ' + new Date() + '\n\n')
//       }, 1000)
//       req.connection.addListener(
//         'close',
//         function () {
//           clearInterval(interval)
//         },
//         false
//       )
//     }
//   })
//   .listen(8844, '127.0.0.1')

前端html页面

  1. new EventSource('http://127.0.0.1:8844/stream')请求对应的的服务。
  2. 添加几个监听,获取服务器推送的消息。
<body>
  <div id="example"></div>
</body>
<script>
  if (typeof (EventSource) !== "undefined") {
    // 浏览器支持 Server-Sent
    var source = new EventSource('http://127.0.0.1:8844/stream');
    var div = document.getElementById('example');
    source.onopen = function (event) {
      div.innerHTML += '<p>Connection open ...</p>';
    };
    source.onerror = function (event) {
      div.innerHTML += '<p>Connection close.</p>';
    };
    source.addEventListener('connecttime', function (event) {
      div.innerHTML += ('<p>Start time: ' + event.data + '</p>');
    }, false);
    source.onmessage = function (event) {
      div.innerHTML += ('<p>Ping: ' + event.data + '</p>');
    };
  }
</script>

image.png

WebSocket(nodejs案例)


HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。


编写nodejs服务端


nodejs有很多支持WebSocket的包,这里使用的是nodejs-websocket。

ws.createServer创建服务,三个监听事件,close与error就不用讲了,text监听前客户端传递过来的消息。

sendText用于向客户端传递消息,实现双向通信。

import ws from 'nodejs-websocket'
console.log('开始建立连接...')
const server = ws
  .createServer(function (conn) {
    conn.on('text', function (str) {
      console.log('从客户端收到的信息:' + str)
      conn.sendText('从服务端传来的信息:收到')
    })
    conn.on('close', function (code, reason) {
      console.log('关闭连接')
    })
    conn.on('error', function (code, reason) {
      console.log('异常关闭')
    })
  })
  .listen(8001)
console.log('WebSocket建立完毕')

前端html页面

  1. new WebSocket连接ws服务端口,记得服务前加上ws:。
  2. ws.send向服务端发送消息。
  3. ws.onmessage监听,可以在这里随时等待服务端传递信息回来。
<body>
  <div id="mess">正在连接...</div>
  <div class="values">
    <div class="value" id="value1">西瓜</div>
    <div class="value" id="value2">苹果</div>
    <div class="value" id="value3">梨子</div>
  </div>
  <script>
    const mess = document.getElementById("mess");
    if (window.WebSocket) {
      const ws = new WebSocket('ws://localhost:8001');
      ws.onopen = function (e) {
        console.log("连接服务器成功");
        ws.send("瓦达西连接了服务器");
      }
      ws.onclose = function (e) {
        console.log("服务器关闭");
      }
      ws.onerror = function () {
        console.log("连接出错");
      }
      ws.onmessage = function (e) {
        mess.innerHTML = "连接成功"
        console.log(e)
      }
      document.querySelector(".values").onclick = function (e) {
        const time = new Date();
        ws.send(time + "  点击了“" + e.target.innerHTML + "”");
      }
    }
  </script>
</body>


相关文章
|
10天前
|
XML JSON 安全
Web安全-代码注入
Web安全-代码注入
16 6
|
19天前
|
机器学习/深度学习 自然语言处理 网络协议
为什么ChatGPT采用SSE协议而不是WebSocket?
在探讨大型语言模型ChatGPT的技术实现时,一个引人注目的细节是其选择使用SSE(Server-Sent Events)协议而非WebSocket来实现数据的实时推送。这一选择背后,蕴含着对技术特性、应用场景及资源效率的深思熟虑。本文将深入探讨ChatGPT为何偏爱SSE,以及这一决策背后的技术逻辑。
38 2
|
20天前
|
中间件 API 开发者
Bottle框架探秘:如何用几行代码搅动Web开发江湖?
【8月更文挑战第31天】Bottle是一个仅依赖Python标准库的轻量级Web开发微框架,无需额外依赖,简化部署与维护。它以简洁高效著称,适合快速构建Web应用。通过简单的示例即可上手,如用几行代码实现“Hello World”应用。除基础功能外,Bottle还支持模板渲染、会话管理和表单处理等,适用于学习及小型项目,也能在高性能要求的应用中展现价值。无论是新手还是有经验的开发者,Bottle都是高效Web开发的理想选择。
30 1
|
28天前
|
前端开发 JavaScript
Web 前端大揭秘!JS 数据类型检测竟如此震撼,一场惊心动魄的代码探秘之旅等你来!
【8月更文挑战第23天】在Web前端开发中,合理检测数据类型至关重要。JavaScript作为动态类型语言,变量类型可在运行时变化,因此掌握检测技巧十分必要。
22 1
|
1月前
|
前端开发 IDE Java
"揭秘前端转Java的秘径:SpringBoot Web极速入门,掌握分层解耦艺术,让你的后端代码飞起来,你敢来挑战吗?"
【8月更文挑战第19天】面向前端开发者介绍Spring Boot后端开发,通过简化Spring应用搭建,快速实现Web应用。本文以创建“Hello World”应用为例,展示项目基本结构与运行方式。进而深入探讨三层架构(Controller、Service、DAO)下的分层解耦概念,通过员工信息管理示例,演示各层如何协作及依赖注入的使用,以此提升代码灵活性与可维护性。
34 2
|
20天前
|
数据库 开发者 Java
数据战争:Hibernate的乐观与悲观锁之争,谁将主宰并发控制的王座?
【8月更文挑战第31天】在软件开发中,数据一致性至关重要,尤其是在多用户并发访问环境下。Hibernate 作为 Java 社区常用的 ORM 框架,提供了乐观锁和悲观锁机制来处理并发问题。乐观锁假设数据不易冲突,通过版本号字段 (`@Version`) 实现;悲观锁则假定数据易冲突,在读取时即加锁。选择哪种锁取决于具体场景:乐观锁适合读多写少的情况,减少锁开销;悲观锁适合写操作频繁的场景,避免数据冲突。正确应用这些机制可提升应用程序的健壮性和效率。
26 0
|
20天前
|
Java UED 自然语言处理
Struts 2 国际化竟有如此神奇魔力?快来揭开多语言支持的 Web 应用神秘面纱
【8月更文挑战第31天】在全球化背景下,Web应用需适应多种语言环境。Struts 2凭借其强大的国际化(i18n)支持,简化了多语言应用开发。通过不同语言的资源文件,它能自动匹配用户语言偏好,优化用户体验并扩展用户群。下面是一个示例:创建`messages.properties`(英语)与`messages_zh_CN.properties`(中文),并在Struts 2的Action类及JSP页面中调用`getText()`方法及Struts标签展示相应语言内容。此外,在struts.xml中指定资源文件,以确保框架正确加载对应语言包。通过这些步骤,开发者可以轻松实现应用的多语言支持。
43 0
|
20天前
|
Java 开发者 JavaScript
Struts 2 开发者的秘籍:隐藏的表单标签库功能,能否成为你下个项目的大杀器?
【8月更文挑战第31天】Struts 2表单标签库是提升Web页面交互体验的神器。它提供丰富的标签,如`&lt;s:textfield&gt;`和`&lt;s:select&gt;`,简化表单元素创建与管理,支持数据验证和动态选项展示。结合示例代码,如创建文本输入框并与Action类属性绑定,显著提升开发效率和用户体验。通过自定义按钮样式等功能,Struts 2表单标签库让开发者更专注于业务逻辑实现。
38 0
|
20天前
|
iOS开发 Android开发 MacOS
从零到全能开发者:解锁Uno Platform,一键跨越多平台应用开发的神奇之旅,让你的代码飞遍Windows、iOS、Android、macOS及Web,技术小白也能秒变跨平台大神!
【8月更文挑战第31天】从零开始,踏上使用Uno Platform开发跨平台应用的旅程。只需编写一次代码,即可轻松部署到Windows、iOS、macOS、Android及Web(通过WASM)等多个平台。Uno Platform为.NET生态带来前所未有的灵活性和效率,简化跨平台开发。首先确保安装了Visual Studio或VS Code及.NET SDK,然后选择合适的项目模板创建新项目。项目结构类似传统.NET MAUI或WPF项目,包含核心NuGet包。通过简单的按钮示例,你可以快速上手并构建应用。Uno Platform让你的技术探索之旅充满无限可能。
23 0
|
20天前
|
前端开发 开发者 Apache
揭秘Apache Wicket项目结构:如何打造Web应用的钢铁长城,告别混乱代码!
【8月更文挑战第31天】Apache Wicket凭借其组件化设计深受Java Web开发者青睐。本文详细解析了Wicket项目结构,帮助你构建可维护的大型Web应用。通过示例展示了如何使用Maven管理依赖,并组织页面、组件及业务逻辑,确保代码清晰易懂。Wicket提供的页面继承、组件重用等功能进一步增强了项目的可维护性和扩展性。掌握这些技巧,能够显著提升开发效率,构建更稳定的Web应用。
53 0