本文作者:云初冀北

JS实现一个可以当镜子照的 Button

JS实现一个可以当镜子照的 Button摘要: 正文最近写了一个好玩的 Button,它除了是一个 Button 外,还可以当镜子照。那这个好玩的 Button 是怎么实现的呢?很容易想到是用到了摄像头。没错,这里要使用浏览器的...

?=正文

最近写了一个好玩的 Button,它除了是一个 Button 外,还可以当镜子照。

JS实现一个可以当镜子照的 Button

那这个好玩的 Button 是怎么实现的呢?

很容易想到是用到了摄像头

没错,这里要使用浏览器的获取媒体设备的 API 来拿到摄像头的视频流,设置到 vIDeo 上,然后对 video 做下镜像反转,加点模糊就好了。

button 的部分倒是很容易,主要是阴影稍微麻烦点。

把 video 作为 button 的子元素,加个 overflow:hidden 就完成了上面的效果

思路很容易,那我们就来实现下吧。

获取摄像头用的是 navigator.meDIaDevices.GetuserMedia 的 api。

mediaDevices 的介绍

在 MDN 中可以看到 mediaDevices 的介绍:

JS实现一个可以当镜子照的 Button

可以用来获取摄像头、麦克风、屏幕等。

它有这些 aPi:

JS实现一个可以当镜子照的 Button

geTDisplayMedia 可以用来录制屏幕,截图。

getUserMedia 可以获取摄像头、麦克风的输入

JS实现一个可以当镜子照的 Button

我们这里用到getUserMedia 的 api

它要指定音频和视频的参数,开启、关闭、分辨率、前后摄像头啥的:

JS实现一个可以当镜子照的 Button

这里我们把 video 开启,把 audio 关闭。

也就是这样:

navigator.mediaDevices.getUserMedia({ video: true, audio: false, }) .then((stream) => { //... }).catch(e => { console.log(e) }) 

把获取到的 stream 用一个 video 来展示

navigator.mediaDevices.getUserMedia({ video: true, audio: false, }) .then((stream) => {   const video = document.getElementById('video');   video.srcobject = stream;   video.onloadedMetadata = () => { video.play();   }; }) .catch((e) => console.log(e)); 

就是这样的:

JS实现一个可以当镜子照的 Button

通过 css 的 filter 来加点感觉:

比如加点 blur:

video {   filter: blur(10px); } 

JS实现一个可以当镜子照的 Button

加点饱和度:

video {   filter: saturate(5) }  

JS实现一个可以当镜子照的 Button

或者加点亮度:

video: {   filter: brightness(3); } 

JS实现一个可以当镜子照的 Button

filter 可以组合,调整调整达到这样的效果就可以了:

video {   filter: blur(2px) saturate(0.6) brightness(1.1); } 

JS实现一个可以当镜子照的 Button

然后调整下大小:

video {   width: 300px;   height: 100px;   filter: blur(2px) saturate(0.6) brightness(1.1); } 

JS实现一个可以当镜子照的 Button

你会发现视频的画面没有达到设置的宽高。

这时候通过 object-fit 的样式来设置:

video {   width: 300px;   height: 100px;   object-fit: cover;   filter: blur(2px) saturate(0.6) brightness(1.1); } 

cover 是充满容器,也就是这样:

JS实现一个可以当镜子照的 Button

但画面显示的位置不大对,看不到脸。我想显示往下一点的画面怎么办呢?

可以通过 object-positiON 来设置:

video {   width: 300px;   height: 100px;   object-fit: cover;   filter: blur(2px) saturate(0.6) brightness(1.1);   object-position: 0 -100px; } 

y 向下移动 100 px ,也就是这样的:

JS实现一个可以当镜子照的 Button

现在画面显示的位置就对了。

其实现在还有一个特别隐蔽的问题,不知道大家发现没,就是方向是错的。照镜子的时候应该左右翻转才对。

所以加一个 scaleX(-1),这样就可以绕 x 周反转了。

video {   width: 300px;   height: 100px;   object-fit: cover;   filter: blur(2px) saturate(0.6) brightness(1.1);   object-position: 0 -100px;   transform: scaleX(-1); } 

JS实现一个可以当镜子照的 Button

这样就是镜面反射的感觉了。

然后再就是 button 部分,这个我们倒是经常写:

function Button({ children }) {   const [buttonPressed, setButtonPressed] = useState(false);    return ( <div   className={`button-wrap ${buttonPressed ? "pressed" : null}`} >   <div className={`button ${buttonPressed ? "pressed" : null}`} onPointerDown={() => setButtonPressed(true)} onPointerUp={() => setButtonPressed(false)}   >  <video/>   </div>   <div className="text">{children}</div> </div>   ); } 

这里我用 JSx 写的,点击的时候修改 pressed 状态,设置不同的 class。

样式部分

:root {   --transition: 0.1s;   --border-radius: 56px; }  .button-wrap {   width: 300px;   height: 100px;   position: relative;   transition: transfORM var(--transition), box-shadow var(--transition); }  .button-wrap.pressed {   transform: translateZ(0) scale(0.95); }  .button {   width: 100%;   height: 100%;   border: 1px solid #fff;   overflow: hidden;   border-radius: var(--border-radius);   box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.25), 0px 8px 16px rgba(0, 0, 0, 0.15), 0px 16px 32px rgba(0, 0, 0, 0.125);   transform: translateZ(0);   cursor: pointer; }  .button.pressed {   box-shadow: 0px -1px 1px rgba(0, 0, 0, 0.5), 0px 1px 1px rgba(0, 0, 0, 0.5); }  .text {   position: absolute;   left: 50%;   top: 50%;   transform: translate(-50%, -50%);   pointer-evenTS: none;   color: rgba(0, 0, 0, 0.7);   font-size: 48px;   font-weight: 500;   text-shadow:0px -1px 0px rgba(255, 255, 255, 0.5),0px 1px 0px rgba(255, 255, 255, 0.5); } 

这种 button 大家写的很多了,也就不用过多解释。

要注意的是 text 和 video 都是绝对定位来做的居中。

阴影的设置

阴影的 4 个值是 x、y、扩散半径、颜色。

我设置了个多重阴影:

JS实现一个可以当镜子照的 Button

JS实现一个可以当镜子照的 Button

然后再改成不同透明度的黑就可以了:

JS实现一个可以当镜子照的 Button

再就是按下时的阴影,设置了上下位置的 1px 黑色阴影:

.button.pressed {   box-shadow: 0px -1px 1px rgba(0, 0, 0, 0.5), 0px 1px 1px rgba(0, 0, 0, 0.5); } 

同时,按下时还有个 scale 的设置:

JS实现一个可以当镜子照的 Button

再就是文字的阴影,也是上下都设置了 1px 阴影,达到环绕的效果:

text-shadow:0px -1px 0px rgba(255, 255, 255, 0.5),0px 1px 0px rgba(255, 255, 255, 0.5); 

JS实现一个可以当镜子照的 Button

最后,把这个 video 嵌进去就了。

完整代码

import React, { useState, useEffect, useRef } from "react"; import "./button.css";  function Button({ children }) {   const reflectionRef = useRef(null);   const [buttonPressed, setButtonPressed] = useState(false);    useEffect(() => { if (!reflectionRef.current) return; navigator.mediaDevices.getUserMedia({ video: true, audio: false, }) .then((stream) => { const video = reflectionRef.current; video.srcObject = stream; video.onloadedmetadata = () => { video.play(); }; }) .catch((e) => console.log(e));   }, [reflectionRef]);    return ( <div   className={`button-wrap ${buttonPressed ? "pressed" : null}`} >   <div className={`button ${buttonPressed ? "pressed" : null}`} onPointerDown={() => setButtonPressed(true)} onPointerUp={() => setButtonPressed(false)}   > <video   className="button-reflection"   ref={reflectionRef} />   </div>   <div className="text">{children}</div> </div>   ); }  export default Button; 
body {   padding: 200px; } :root {   --transition: 0.1s;   --border-radius: 56px; }  .button-wrap {   width: 300px;   height: 100px;   position: relative;   transition: transform var(--transition), box-shadow var(--transition); }  .button-wrap.pressed {   transform: translateZ(0) scale(0.95); }  .button {   width: 100%;   height: 100%;   border: 1px solid #fff;   overflow: hidden;   border-radius: var(--border-radius);   box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.25), 0px 8px 16px rgba(0, 0, 0, 0.15), 0px 16px 32px rgba(0, 0, 0, 0.125);   transform: translateZ(0);   cursor: pointer; }  .button.pressed {   box-shadow: 0px -1px 1px rgba(0, 0, 0, 0.5), 0px 1px 1px rgba(0, 0, 0, 0.5); }  .text {   position: absolute;   left: 50%;   top: 50%;   transform: translate(-50%, -50%);   pointer-events: none;   color: rgba(0, 0, 0, 0.7);   font-size: 48px;   font-weight: 500;   text-shadow:0px -1px 0px rgba(255, 255, 255, 0.5),0px 1px 0px rgba(255, 255, 255, 0.5); }  .text::selection {   background-color: transparent; }  .button .button-reflection {   width: 100%;   height: 100%;   transform: scaleX(-1);   object-fit: cover;   opacity: 0.7;   filter: blur(2px) saturate(0.6) brightness(1.1);   object-position: 0 -100px; } 

总结

浏览器提供了 media devices 的 api,可以获取摄像头、屏幕、麦克风等的输入。

除了常规的用途外,还可以用来做一些好玩的事情,比如今天这个的可以照镜子的 button。

它看起来就像我上厕所时看到的这个东西一样😂:

JS实现一个可以当镜子照的 Button

以上就是js实现一个可以当镜子照的 Button的详细内容,更多关于JS镜子Button的资料请关注云初冀北其它相关文章!

免责声明
本站提供的资源,都来自网络,版权争议与本站无关,所有内容及软件的文章仅限用于学习和研究目的。不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负,我们不保证内容的长久可用性,通过使用本站内容随之而来的风险与本站无关,您必须在下载后的24个小时之内,从您的电脑/手机中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。侵删请致信E-mail:Goliszhou@gmail.com
$

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏

阅读
分享

发表评论

快捷回复:

评论列表 (暂无评论,151人围观)参与讨论

还没有评论,来说两句吧...