最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JS實(shí)現(xiàn)一個(gè)可以當(dāng)鏡子照的?Button

 更新時(shí)間:2023年03月05日 09:24:26   作者:zxg_神說要有光  
這篇文章主要介紹了JS實(shí)現(xiàn)一個(gè)可以當(dāng)鏡子照的?Button的方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

正文

最近寫了一個(gè)好玩的 Button,它除了是一個(gè) Button 外,還可以當(dāng)鏡子照。

那這個(gè)好玩的 Button 是怎么實(shí)現(xiàn)的呢?

很容易想到是用到了攝像頭。

沒錯(cuò),這里要使用瀏覽器的獲取媒體設(shè)備的 api 來拿到攝像頭的視頻流,設(shè)置到 video 上,然后對 video 做下鏡像反轉(zhuǎn),加點(diǎn)模糊就好了。

button 的部分倒是很容易,主要是陰影稍微麻煩點(diǎn)。

把 video 作為 button 的子元素,加個(gè) overflow:hidden 就完成了上面的效果。

思路很容易,那我們就來實(shí)現(xiàn)下吧。

獲取攝像頭用的是 navigator.mediaDevices.getUserMedia 的 api。

mediaDevices 的介紹

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

可以用來獲取攝像頭、麥克風(fēng)、屏幕等。

它有這些 api:

getDisplayMedia 可以用來錄制屏幕,截圖。

getUserMedia 可以獲取攝像頭、麥克風(fēng)的輸入。

我們這里用到getUserMedia 的 api

它要指定音頻和視頻的參數(shù),開啟、關(guān)閉、分辨率、前后攝像頭啥的:

這里我們把 video 開啟,把 audio 關(guān)閉。

也就是這樣:

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

把獲取到的 stream 用一個(gè) 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));

就是這樣的:

通過 css 的 filter 來加點(diǎn)感覺:

比如加點(diǎn) blur:

video {
  filter: blur(10px);
}

加點(diǎn)飽和度:

video {
  filter: saturate(5)
}

或者加點(diǎn)亮度:

video: {
  filter: brightness(3);
}

filter 可以組合,調(diào)整調(diào)整達(dá)到這樣的效果就可以了:

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

然后調(diào)整下大?。?/p>

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

你會(huì)發(fā)現(xiàn)視頻的畫面沒有達(dá)到設(shè)置的寬高。

這時(shí)候通過 object-fit 的樣式來設(shè)置:

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

cover 是充滿容器,也就是這樣:

但畫面顯示的位置不大對,看不到臉。我想顯示往下一點(diǎn)的畫面怎么辦呢?

可以通過 object-position 來設(shè)置:

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

y 向下移動(dòng) 100 px ,也就是這樣的:

現(xiàn)在畫面顯示的位置就對了。

其實(shí)現(xiàn)在還有一個(gè)特別隱蔽的問題,不知道大家發(fā)現(xiàn)沒,就是方向是錯(cuò)的。照鏡子的時(shí)候應(yīng)該左右翻轉(zhuǎn)才對。

所以加一個(gè) scaleX(-1),這樣就可以繞 x 周反轉(zhuǎn)了。

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

這樣就是鏡面反射的感覺了。

然后再就是 button 部分,這個(gè)我們倒是經(jīng)常寫:

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 寫的,點(diǎn)擊的時(shí)候修改 pressed 狀態(tài),設(shè)置不同的 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 都是絕對定位來做的居中。

陰影的設(shè)置

陰影的 4 個(gè)值是 x、y、擴(kuò)散半徑、顏色。

我設(shè)置了個(gè)多重陰影:

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

再就是按下時(shí)的陰影,設(shè)置了上下位置的 1px 黑色陰影:

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

同時(shí),按下時(shí)還有個(gè) scale 的設(shè)置:

再就是文字的陰影,也是上下都設(shè)置了 1px 陰影,達(dá)到環(huán)繞的效果:

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

最后,把這個(gè) video 嵌進(jìn)去就行了。

完整代碼

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;
}

總結(jié)

瀏覽器提供了 media devices 的 api,可以獲取攝像頭、屏幕、麥克風(fēng)等的輸入。

除了常規(guī)的用途外,還可以用來做一些好玩的事情,比如今天這個(gè)的可以照鏡子的 button。

它看起來就像我上廁所時(shí)看到的這個(gè)東西一樣??:

以上就是JS實(shí)現(xiàn)一個(gè)可以當(dāng)鏡子照的 Button的詳細(xì)內(nèi)容,更多關(guān)于JS鏡子Button的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JS輕量級函數(shù)式編程實(shí)現(xiàn)XDM一

    JS輕量級函數(shù)式編程實(shí)現(xiàn)XDM一

    這篇文章主要為大家介紹了JS輕量級函數(shù)式編程實(shí)現(xiàn)XDM示例詳解第1/3篇,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • JavaScript loader原理簡單總結(jié)示例解析

    JavaScript loader原理簡單總結(jié)示例解析

    這篇文章主要為大家介紹了JavaScript loader原理簡單總結(jié)示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • 用javascript制作qq注冊動(dòng)態(tài)頁面

    用javascript制作qq注冊動(dòng)態(tài)頁面

    這篇文章主要介紹了用javascript制作qq注冊動(dòng)態(tài)頁面,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2021-04-04
  • 前端JavaScript之Promise

    前端JavaScript之Promise

    這篇文章主要介紹關(guān)于前端JavaScript的Promise,Promise 是異步編程的一種解決方案,下面文章我們就來看看Promise的基本用法及各種方法,需要的朋友可以參考一下,希望對你有所幫助
    2021-10-10
  • 詳解HTML5 使用video標(biāo)簽實(shí)現(xiàn)選擇攝像頭功能

    詳解HTML5 使用video標(biāo)簽實(shí)現(xiàn)選擇攝像頭功能

    這篇文章主要介紹了詳解HTML5 使用video標(biāo)簽實(shí)現(xiàn)選擇攝像頭功能的相關(guān)資料,希望通過本文能幫助到大家,實(shí)現(xiàn)這樣的功能,需要的朋友可以參考下
    2017-10-10
  • JS 基本概念詳細(xì)介紹

    JS 基本概念詳細(xì)介紹

    這篇文章主要介紹JS 基本概念,對于初學(xué)者來說,Javascript 乍一看似乎很容易,因?yàn)樗念愃朴?C 的語法,但不管它的運(yùn)行方式如何,對語言 (ESNext) 及其框架所做的不斷變化可能會(huì)讓初學(xué)者不知所措。下面我們就來看JS 初學(xué)者怎么入門吧
    2021-10-10
  • You-Dont-Know-JS詞法作用域及兩種常見的模型學(xué)習(xí)文檔

    You-Dont-Know-JS詞法作用域及兩種常見的模型學(xué)習(xí)文檔

    這篇文章主要為大家介紹了JS?詞法作用域及兩種常見的模型詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • 微信小程序 實(shí)戰(zhàn)實(shí)例開發(fā)流程詳細(xì)介紹

    微信小程序 實(shí)戰(zhàn)實(shí)例開發(fā)流程詳細(xì)介紹

    這篇文章主要介紹了微信小程序 實(shí)戰(zhàn)實(shí)例開發(fā)流程詳細(xì)介紹的相關(guān)資料,這里主要介紹微信小程序的開發(fā)流程和簡單實(shí)例,需要的朋友可以參考下
    2017-01-01
  • CheckBox 如何實(shí)現(xiàn)全選?

    CheckBox 如何實(shí)現(xiàn)全選?

    CheckBox 如何實(shí)現(xiàn)全選?...
    2006-06-06
  • 前端取消請求及取消重復(fù)請求方式

    前端取消請求及取消重復(fù)請求方式

    這篇文章主要為大家介紹了前端取消請求及取消重復(fù)請求方式,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07

最新評論

比如县| 杭锦后旗| 唐河县| 七台河市| 思茅市| 娄烦县| 高邮市| 祁东县| 南江县| 诸暨市| 萍乡市| 潍坊市| 米易县| 金沙县| 旺苍县| 泰宁县| 朔州市| 河西区| 孟村| 布尔津县| 宜川县| 德格县| 江源县| 老河口市| 项城市| 太白县| 西畴县| 云安县| 嘉善县| 呼图壁县| 宁海县| 敖汉旗| 安溪县| 怀集县| 海林市| 吴堡县| 廉江市| 抚松县| 湖口县| 拉孜县| 辉南县|