Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
說到防抖,想必多數人首先想到的是相機的防抖。因為我們并不是機器人,所以拿手機拍照的時候,手都會有不易察覺的抖動,這樣的抖動會影響相片的質量。手機對這些情況做的一些補償操作,減小了手抖對成像造成的影響。
我們都知道,JavaScript 是一門編程語言,不是人類也不是機器人。那什么情況下,會產生“抖動”呢?
聯想一個平平無奇的登錄框,當用戶信息輸入完畢,點擊登錄按鈕,可能網速有點慢還是啥的,用戶等得不耐煩,不停點擊,導致鼠標患上帕金森,登錄按鈕就被一次一次地點擊,前端不停地向后臺發送重復的請求。
如下面的例子(這里點擊一次,執行 console.log('click'), 并且用 console.log('submit') 代指請求):
可以看到,短時間內連續點擊,每次點擊都會觸發請求.
這種情況,就屬于“抖動”。
服務器接收到這樣的請求,肯定是一臉懵啊,這誰頂得???
這個時候,就需要像手機相機一樣,做一些操作,減少鼠標抖動對網絡請求的影響,減輕服務器的壓力。
“抖動”情景下,多次點擊,導致發送了多次一樣的請求。函數防抖的處理方式是:先規定一個時間段,比如一秒,點擊按鈕,一秒之后再發送請求,假如一秒內又產生了一次點擊,那么重新計時,點擊過后一秒再發送請求。
這樣一來,規定時間段內的快速點擊,只會產生一次請求。不管打字多快的手速,也戰勝不了防抖的函數。
直接上代碼:
const debounce=(func, delay=200)=> { let timeout=null return function () { clearTimeout(timeout) timeout=setTimeout(()=> { func.apply(this, arguments) }, delay) } }
debounce 函數接受一個函數 func 和一個默認為 200 毫秒延遲時間 delay 作為參數。返回一個函數,觸發返回的函數,開始計時,delay 毫秒后觸發 func, 假如 delay 時間段內,再次觸發這個函數,那么重新計時,delay 毫秒后觸發 func.
debounce 首先聲明變量 timeout, 用于存放之后 setTimeout 函數返回的定時器編號。
然后返回一個函數,函數內執行 clearTimeout 來依據先前聲明的 timeout 來清除定時器。當然,一開始,傳入的 timeout 值為 null, 這時的清除操作忽略不計。
接著,執行 setTimeout, 在至少 delay 規定的毫秒后,將 setTimeout 的回調函數添加到當前事件隊列,回調內執行 func 函數。并且把返回的定時器編號賦值給 timeout , 這樣,下一次觸發 debounce 返回的函數時,就可以清除通過上面的 clearTimeout(timeout) 來清除定時器 。
注意到上面執行 func 用的是 func.apply(this, arguments), 這樣一來,就可以對 debounce 返回的那個函數傳遞參數,func 執行的時候,再把參數傳給 func.
來用一下:
const submit=()=> { console.log('submit') } const debounceSubmit=debounce(submit, 500) let btnSubmit=document.getElementById('submit') btnSubmit.addEventListener('click', ()=> { console.log('click') debounceSubmit() })
這里將 submit 函數傳入 debounce 函數,并設置延遲時間為 500 毫秒。 debounce 返回的函數賦給 debounceSubmit , 然后在提交按鈕 btnSubmit 的點擊事件回調中執行 debounceSubmit.
看下效果:
上圖中,一開始的幾次連續點擊,都不會觸發 submit ,停止點擊后,才觸發了一次 submit . 之后兩次有一定間隔時間的點擊,都觸發了 submit.
函數的防抖將一定時間內的多次操作,減少為一次,去除冗余,節約資源。
去,當我們面對交通違法記分時,往往感到頭疼和無奈。不僅是因為扣分帶來的經濟和時間成本,更是因為缺乏一個系統、便捷的方式來學習和了解交通規則,從而避免再次犯錯。然而,現在有了學法減分工具,這一切都變得簡單而高效。
這是微信公眾號
一款專為駕駛員打造的交通安全學習減分題庫,通過減分俠隨時在線刷題練習,涵蓋豐富的交通安全知識,讓學習減分更輕松!
下方附上一些測試的試題及答案
1、【35】
A.other B.big C.little D.robot
答案:C
2、“足智多謀、隨機應變”是思維的哪種品質?()
A.廣闊性 B.獨立性 C.靈活性 D.邏輯性
答案:C
3、【C20】
A.formed B.caused C.made D.fallen
答案:A
4、機上遇到特別肥胖的旅客時,乘務員要主動為該旅客提供____________________。
答案:加長安全帶
5、下列哪項不是蘇聯“休克療法”的內容?()
A.快速私有化 B.自由化 C.穩定化 D.擴張性財政政策
答案:D
6、【31】
A.keeps B.draws C.inclines D.tends
答案:B
7、Which of the following statements is true?
A.Five percent of Americans are very unhappy. B.Over fifty percent of Americans are very happy. C.Twenty percent of Americans are very unhappy. D.Sixty to seventy percent of Americans are not happy.
答案:A
8、嵐山は日本の___にあります()
A、東京 B、京都 C、奈良
答案:B
9、【C11】
A.hot-sold B.good-sold C.hot-selling D.good-selling
答案:C
10、【36】
A.similarly B.greatly C.hardly D.clearly
答案:C
11、產業結構理論是關于產業內企業結構的理論。
對 錯
答案:錯
12、【單選題】下列保險項目中只由用人單位繳納保險費的是() 答案:工傷保險
答案:工傷保險
13、【C9】
A.And B.While C.But D.Nevertheless
答案:A
14、【31】
A.some one B.one C.he D.reader
答案:B
15、【29】
A.fabulous B.frigid C.feeble D.fashionable
答案:D
coursera是面向大學生的免費在線學習APP
它與全世界最頂尖的大學和機構合作,提供任何人可學習的在線課程。
這是一個網站
:題庫全面,包含公職、消防、煤礦、國網、醫學等行業題目。支持拍照、讀屏搜題。簡單易用、一鍵開始、快速響應!
以番茄工作法為基礎的時間管理,科學方便。開啟學霸模式可以讓我們專注于自己做的事情,避免其他娛樂軟件的打擾。
這是一款提升我們的自律和專注度用的APP。
這是一個網站
涵蓋初高中/大學/專升本/考研/成人自考/各類資格證等等考試題目,同時支持截圖搜題、語音搜題,里面還有1000+考試題庫可以練習
中國大學MOOC(慕課) 是國內優質的中文MOOC學習平臺
由愛課程網攜手網易云課堂打造。平臺擁有包括985高校在內提供的千余門課程,其中首批獲得認定的國家精品在線開放課程322門
菜鳥教程是一個完全免費的編程學習軟件。
它免費提供了HTML / CSS 、JavaScript 、服務端、移動端、XML 教程、http://ASP.NET 、Web Service 、開發工具、網站建設;每類教程還細分了很多種不同的教程,例如服務端學習教程包括:PHP 教程、Python 基礎教程、Python 3 教程、Linux 教程、Java 教程、Ruby 教程、C 語言教程、C++ 教程、Go 語言教程、正則表達式等豐富的編程學習教程
這是個微信公眾號
搜索的題目全部都有詳細的提示,以及中間做題步驟、解決方法,你可以導入照片或拍照的方式輸入數學問題,它還支持將重點題目進行收集整理,非常方便大家用來復習。
微信讀書是騰訊官方出品的一款在線小說閱讀APP,它的書庫儲量非常豐富,我們可以直接通過搜索獲取到想要閱讀的書籍,喜歡閱讀古今中外名著書籍的小伙伴值得嘗試。
我們可以將想要閱讀的書籍加入書架,還能夠設置虛擬書架,這樣你的好友就不知道你在讀什么書了。
祝愿每一位大學生都能夠充分利用這些日常學習工具,成為自己學業道路上的強者。
近刷臉支付很火,老板們當然要追趕時代潮流,于是就有了刷臉支付這個項目。前端實現關鍵的技術是攝像頭錄像,拍照和人臉比對,本文來探討一下如何在html5環境中如何實現刷臉支付以及開發過程中遇到的問題。
html5中獲取手機上的圖片,有兩種方式,使用input,如下可以打開攝像頭拍照:
<input type="file" capture="camera" accept="image/*"/>
另外如果想打開相冊,可以這樣:
<input type="file" accept="img/*">
但是這兩種方式都會有兼容性問題,用過的同學可能都知道。
getUserMedia是html5一個新的api,官方一點的定義是:
MediaDevices.getUserMedia() 會提示用戶給予使用媒體輸入的許可,媒體輸入會產生一個MediaStream,里面包含了請求的媒體類型的軌道。此流可以包含一個視頻軌道(來自硬件或者虛擬視頻源,比如相機、視頻采集設備和屏幕共享服務等等)、一個音頻軌道(同樣來自硬件或虛擬音頻源,比如麥克風、A/D轉換器等等),也可能是其它軌道類型。
簡單一點說就是可以獲取到用戶攝像頭。
同上面input一樣,這種方式也有兼容性問題,不過可以使用其他方式解決,這里可以參考MediaDevices.getUserMedia(),文檔中有介紹"在舊的瀏覽器中使用新的API"。我這里在網上也找了一些參考,總結出一個相對全面的getUserMedia版本,代碼如下:
// 訪問用戶媒體設備
getUserMedia(constrains, success, error) {
if (navigator.mediaDevices.getUserMedia) {
//最新標準API
navigator.mediaDevices.getUserMedia(constrains).then(success).catch(error);
} else if (navigator.webkitGetUserMedia) {
//webkit內核瀏覽器
navigator.webkitGetUserMedia(constrains).then(success).catch(error);
} else if (navigator.mozGetUserMedia) {
//Firefox瀏覽器
navagator.mozGetUserMedia(constrains).then(success).catch(error);
} else if (navigator.getUserMedia) {
//舊版API
navigator.getUserMedia(constrains).then(success).catch(error);
} else {
this.scanTip="你的瀏覽器不支持訪問用戶媒體設備"
}
}
獲取設備方法有兩個回調函數,一個是成功,一個是失敗。成功了就開始播放視頻,播放視屏其實就是給video設置一個url,并調用play方法,這里設置url要考慮不同瀏覽器兼容性,代碼如下:
success(stream) {
this.streamIns=stream
// 設置播放地址,webkit內核瀏覽器
this.URL=window.URL || window.webkitURL
if ("srcObject" in this.$refs.refVideo) {
this.$refs.refVideo.srcObject=stream
} else {
this.$refs.refVideo.src=this.URL.createObjectURL(stream)
}
this.$refs.refVideo.onloadedmetadata=e=> {
// 播放視頻
this.$refs.refVideo.play()
this.initTracker()
}
},
error(e) {
this.scanTip="訪問用戶媒體失敗" + e.name + "," + e.message
}
注意:
視屏在video中播放成功之后就開始識別人臉了,這里使用到一個第三方的功能tracking.js,是國外的大神寫的JavaScript圖像識別插件。關鍵代碼如下:
// 人臉捕捉
initTracker() {
this.context=this.$refs.refCanvas.getContext("2d") // 畫布
this.tracker=new tracking.ObjectTracker(['face']) // tracker實例
this.tracker.setStepSize(1.7) // 設置步長
this.tracker.on('track', this.handleTracked) // 綁定監聽方法
try {
tracking.track('#video', this.tracker) // 開始追蹤
} catch (e) {
this.scanTip="訪問用戶媒體失敗,請重試"
}
}
捕獲到人臉之后,可以在頁面上用一個小方框標注出來,這樣有點交互效果。
// 追蹤事件
handleTracked(e) {
if (e.data.length===0) {
this.scanTip='未檢測到人臉'
} else {
if (!this.tipFlag) {
this.scanTip='檢測成功,正在拍照,請保持不動2秒'
}
// 1秒后拍照,僅拍一次
if (!this.flag) {
this.scanTip='拍照中...'
this.flag=true
this.removePhotoID=setTimeout(()=> {
this.tackPhoto()
this.tipFlag=true
}, 2000)
}
e.data.forEach(this.plot)
}
}
在頁面中畫一些方框,標識出人臉:
<div class="rect" v-for="item in profile"
:style="{ width: item.width + 'px', height: item.height + 'px', left: item.left + 'px', top: item.top + 'px'}"></div>
// 繪制跟蹤框
plot({x, y, width: w, height: h}) {
// 創建框對象
this.profile.push({ width: w, height: h, left: x, top: y })
}
拍照,就是使用video作為圖片源,在canvas中保存一張圖片下來,注意這里使用toDataURL方法的時候可以設置第二個參數quality,從0到1,0表示圖片比較粗糙,但是文件比較小,1表示品質最好。
// 拍照
tackPhoto() {
this.context.drawImage(this.$refs.refVideo, 0, 0, this.screenSize.width, this.screenSize.height)
// 保存為base64格式
this.imgUrl=this.saveAsPNG(this.$refs.refCanvas)
// this.compare(imgUrl)
this.close()
},
// Base64轉文件
getBlobBydataURI(dataURI, type) {
var binary=window.atob(dataURI.split(',')[1]);
var array=[];
for(var i=0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {
type: type
});
},
// 保存為png,base64格式圖片
saveAsPNG(c) {
return c.toDataURL('image/png', 0.3)
}
拍照完成之后就可以把文件發送給后端,讓后端進行對比驗證,這里后端使用的是阿里云的接口。
最后,demo我已經放在github上了,感興趣可以打開看一下。
效果如下:
最后放在項目中,無非就是最后一個步驟,去調用接口比對,根據比對結果成功是成功還是失敗,決定是人臉支付還是繼續使用原來的密碼支付,效果如下:
ps:這里人臉比對失敗了,是因為我帶著口罩,就不呲牙露臉了。
作者:Tyler Ning 出處:http://www.cnblogs.com/tylerdonet/ 本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,如有問題,可以通過以下郵箱地址344805262@qq.com 聯系我,非常感謝。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。