Vue實(shí)現(xiàn)鎖屏功能的示例代碼
這兩天剛做了個(gè)新需求,要做個(gè)系統(tǒng)鎖屏(當(dāng)然鎖的是當(dāng)前的系統(tǒng)),就類似于電腦鎖屏似的。
共兩種情況下鎖屏,一種是無操作一定時(shí)間后自動(dòng)鎖屏;第二種是可以按下組合鍵(快捷鍵)主動(dòng)進(jìn)行鎖屏。下面具體來說一下該需求的想法、思路以及實(shí)現(xiàn)
然后再說下想法思路吧。首先實(shí)現(xiàn)鎖屏一般也就兩種方式:
一種是去寫個(gè)頁面,當(dāng)達(dá)到條件時(shí)要跳轉(zhuǎn)到該鎖屏頁面,但是有一些要注意的地方, 比如:如果跳轉(zhuǎn)的時(shí)候使用的$router.push,那么我是可以通過點(diǎn)擊瀏覽器的回退按鈕回到上一個(gè)頁面的,這個(gè)要做一下限制。還有一種可能是我如果直接在瀏覽器上輸入某個(gè)頁面的路徑,那么是不是也會跳轉(zhuǎn)?所以我們要有個(gè)全局的變量來記錄當(dāng)前是不是鎖屏狀態(tài),如果是鎖屏狀態(tài),我們要對其進(jìn)行限制。當(dāng)然這只是舉例的兩種情況,真實(shí)做起來或許還有其他情況,反正要考慮周全,不然后面會出現(xiàn)你意想不到的bug
第二種就是直接去寫遮罩層了,也是我當(dāng)前實(shí)現(xiàn)鎖屏的方式。這種方式相對上面來講,會比較簡單一些,也還算方便,我們只需要在達(dá)到條件后將該遮罩層顯示出來就可以了,當(dāng)然遮罩層的優(yōu)先級肯定要設(shè)置最高的,要不然怎么覆蓋掉任意當(dāng)前的頁面呢,也正是因?yàn)檫@個(gè)優(yōu)先級最高,導(dǎo)致在這個(gè)遮罩層組件中有些$message這樣的消息提示或彈窗顯示不出來。這也算是一個(gè)缺陷。不過一般鎖屏頁面也沒什么太多操作,主要是頁面有個(gè)背景圖,然后輸入解鎖密碼進(jìn)行解鎖就可以了,所以影響并不大。還有一種需要注意,就是我現(xiàn)在已經(jīng)鎖屏頁面了,我這時(shí)候打開控制臺,然后是不是可以去修改這個(gè)遮罩層的樣式呢?比如我給遮罩層加個(gè)display: none; 遮罩層是不是沒了?答案是的,所以我們要做限制! 打開控制臺的方式無非也就兩種方式,一種是F12(Fn + F12),另一種是鼠標(biāo)右鍵,然后點(diǎn)擊檢查。這樣,我們鎖屏出來的時(shí)候就監(jiān)聽鍵盤按下事件,阻止F12的按鍵,同時(shí)也阻止鼠標(biāo)右鍵行為,這樣就可以了,看上去簡單粗暴哈,但也是為了實(shí)現(xiàn)這么個(gè)需求嘛。
下面再說一下實(shí)現(xiàn)的方式。
首先我把遮罩層單獨(dú)寫了個(gè)組件,里面也都是遮罩層的樣式、邏輯。注意這是個(gè)組件,而不是個(gè)頁面,哪里用到哪里引入就可以了。
然后就是遮罩層什么時(shí)候顯示的問題了,既然是鎖屏,那么肯定是跟登錄沒有關(guān)系的,也就是我們要?jiǎng)傄贿M(jìn)系統(tǒng)就開始計(jì)時(shí)了,比如我們的需求是一分鐘無操作后就要鎖屏,那么我們只需要這個(gè)計(jì)時(shí)無操作的時(shí)間就可以了,什么算是操作了?什么算是無操作,鼠標(biāo)點(diǎn)擊就是操作了,鼠標(biāo)雙擊是操作了,鼠標(biāo)右鍵是操作了,鼠標(biāo)移動(dòng)是操作了,鼠標(biāo)滾輪是操作了,鍵盤按下是操作了,基本就這些事件,也就是我們在剛進(jìn)入系統(tǒng)時(shí)就要監(jiān)聽這些事件,同時(shí)也開始計(jì)時(shí)(計(jì)時(shí)就是定義變量初始值為0,然后setInterval每隔1s加1),如果有其中某個(gè)事件觸發(fā)了,我們就要清除掉定時(shí)器,并將變量初始化為初始值也就是0,并重新計(jì)時(shí),基本跟防抖差不多。然后我們無操作滿足時(shí)間后會顯示遮罩層,也就是進(jìn)入鎖屏狀態(tài),這個(gè)是,我們就要把那些事件監(jiān)聽移除掉,并清除掉定時(shí)器,但是注意不要將變量初始化為0,因?yàn)槲覀円ㄟ^這個(gè)變量和我們設(shè)置時(shí)間做對比來決定是否顯示遮罩層,進(jìn)入遮罩層之后就是遮罩層的操作了,解鎖后呢,我們將變量的值初始化為0,隱藏遮罩層,并重新監(jiān)聽那些事件,重新計(jì)時(shí)就可以了。
哎喲,說太多了說太多了~ 下面上代碼了
我們首先在.env(development / production)的文件中定義個(gè)變量,這個(gè)變量就是無操作多長時(shí)間進(jìn)入鎖屏,單位 s。也就是可配置的
# 鎖屏?xí)r間(s)
VUE_APP_LOCK_TIME = 300
這個(gè)也就是說無操作5分鐘后進(jìn)入鎖屏狀態(tài)
然后我們需要在Vuex中保存一個(gè)計(jì)時(shí)時(shí)間lockTime,也就是當(dāng)這個(gè)時(shí)間大于等于我們設(shè)置的那個(gè)時(shí)間就進(jìn)入鎖屏,即 lockTime >= parseInt(process.env.VUE_APP_LOCK_TIME)
我這里分了個(gè)模塊 common (src/store/modules/common.js)
export default {
namespaced: true,
state: {
// 無操作計(jì)時(shí)時(shí)間
lockTime: 0
},
mutations: {
updatelockTime(state, lockTime) {
state.lockTime = lockTime
}
}
}然后是遮罩層(鎖屏)什么時(shí)候進(jìn)行顯示的邏輯:
我這里是封裝在了mixins中,這是為了可以把鎖屏的邏輯單獨(dú)抽離出來,邏輯更清晰一些,后面如果說我不想在整個(gè)系統(tǒng)鎖屏了,我只要在某些頁面中,也就是只在系統(tǒng)的A頁面、B頁面中才會有鎖屏,其他都不需要鎖屏,那我們直接將邏輯混入到組件就可以了。
// 引入鎖屏遮罩層組件
import Lock from '@/components/lock'
export default {
data() {
return {
timer: null
}
},
components: { Lock },
computed: {
isLock() {
return this.lockTime >= parseInt(process.env.VUE_APP_LOCK_TIME)
},
lockTime: {
get() {
return this.$store.state.common.lockTime
},
set(lockTime) {
this.$store.commit('common/updatelockTime', lockTime)
}
}
},
watch: {
isLock() {
if (this.isLock) {
this.removeHandle()
} else {
this.init()
}
}
},
mounted() {
this.init()
},
destroyed() {
this.removeHandle()
},
methods: {
init() {
this.reckonByTime()
document.addEventListener('click', this.clickHandle)
document.addEventListener('dblclick', this.dblclickHandle)
document.addEventListener('contextmenu', this.contextmenuHandle)
document.addEventListener('mousemove', this.mousemoveHandle)
document.addEventListener('mousewheel', this.mousewheelHandle)
document.addEventListener('keydown', this.keydownHandle)
},
// 移除事件監(jiān)聽、定時(shí)器等
removeHandle() {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
document.removeEventListener('click', this.clickHandle)
document.removeEventListener('dblclick', this.dblclickHandle)
document.removeEventListener('contextmenu', this.contextmenuHandle)
document.removeEventListener('mousemove', this.mousemoveHandle)
document.removeEventListener('mousewheel', this.mousewheelHandle)
document.removeEventListener('keydown', this.keydownHandle)
},
// 無操作計(jì)時(shí)
reckonByTime() {
if (this.timer) {
this.lockTime = 0
clearInterval(this.timer)
this.timer = null
}
this.timer = setInterval(() => {
this.lockTime += 1
}, 1000)
},
// 鼠標(biāo)點(diǎn)擊
clickHandle() {
this.reckonByTime()
},
// 鼠標(biāo)雙擊
dblclickHandle() {
this.reckonByTime()
},
// 鼠標(biāo)右鍵
contextmenuHandle() {
this.reckonByTime()
},
// 鼠標(biāo)移動(dòng)
mousemoveHandle() {
this.reckonByTime()
},
// 鼠標(biāo)滾輪
mousewheelHandle() {
this.reckonByTime()
},
// 鍵盤按下
keydownHandle(event) {
const { altKey, ctrlKey, keyCode } = event
if (altKey && ctrlKey && keyCode == 76) {
// Ctrl + Alt + L 快捷鍵直接鎖屏
this.lockTime = parseInt(process.env.VUE_APP_LOCK_TIME)
} else {
this.reckonByTime()
}
}
}
}然后是鎖屏組件(遮罩層組件)
@/components/lock/index.vue
<template>
<div class="lock">
<div>
<img src="../../assets/img/lock/lock-icon.png" alt="">
<el-input class="lockPasswdInp" v-show="!passwdError" ref="lockPasswdInp" size="small" show-password placeholder="密碼" v-model="passwd">
<template slot="append">
<el-button @click="unLock()" style="background: transparent;">
<i class="el-icon-right"></i>
</el-button>
</template>
</el-input>
<div class="passwdError-container" v-show="passwdError">
<div class="passwdError">密碼不正確。請?jiān)僭囈淮巍?lt;/div>
<div class="confirm-btn" @click="reset()">確認(rèn)</div>
</div>
</div>
<!-- <img @click="logout" class="logout" src="../../assets/img/system/logout.png"> -->
</div>
</template>
<script>
/**
* 注意:由于遮罩層優(yōu)先級太高 類似于$message之類的消息提示等會顯示不出來
*/
export default {
data() {
return {
passwd: '',
passwdError: false
}
},
computed: {
lockPassword: () => process.env.VUE_APP_LOCK_PASSWORD || '123456'
},
mounted() {
this.reset()
document.addEventListener('keydown', this.keyDownHandle)
document.addEventListener('contextmenu', this.contextmenuHandle)
},
destroyed() {
document.removeEventListener('keydown', this.keyDownHandle)
document.removeEventListener('contextmenu', this.contextmenuHandle)
},
methods:{
// 重置初始化
reset() {
this.passwdError = false
this.passwd = ''
this.$nextTick(() => {
this.$refs.lockPasswdInp.focus()
})
},
// 解鎖
unLock() {
if(this.passwd != this.lockPassword) {
return this.passwdError = true
}
this.$store.commit('common/updatelockTime', 0)
},
// 監(jiān)聽鼠標(biāo)按下事件,阻止 F12 事件
keyDownHandle(event) {
if(event.keyCode == 13) {
if(this.passwdError) {
this.reset()
} else {
this.unLock()
}
}
return (event.keyCode !== 123 ) || (event.returnValue = false)
},
// 阻止鼠標(biāo)右鍵事件
contextmenuHandle(event) {
return event.returnValue = false;
},
// // 退出登錄
// logout() {
// this.$store.commit('common/updatelockTime', 0)
// this.$router.replace('/login')
// /**
// * 走接口 清楚本地緩存等
// * ...
// */
// }
}
}
</script>
<style scoped>
.lock {
width: 100%;
height: 100vh;
background: #ccc;
position: fixed;
top: 0;
left: 0;
z-index: 999999;
display: flex;
justify-content: center;
align-items: center;
background-image: url('../../assets/img/lock/lock-bg.jpg');
background-repeat: no-repeat;
background-size: 100% 100%;
}
.lock > div {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.lockPasswdInp {
margin-top: 8px;
}
/deep/ .el-input__inner {
background-color: transparent !important;
border: 1px solid #0076c8 !important;
color: #fff;
}
/deep/ .el-input-group__append {
background-color: rgba(6, 14, 22, .5);
border: 1px solid #0076c8;
border-left-color: transparent;
}
/deep/ .el-input-group__append:hover {
background-color: rgba(6, 14, 22, .6);
cursor: pointer;
}
.passwdError-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.passwdError {
width: 260px;
text-align: center;
color: #fff;
font-size: 13px;
margin: 10px 0;
}
.confirm-btn {
width: 70px;
height: 28px;
text-align: center;
line-height: 28px;
color: #fff;
font-size: 13px;
background-color: rgba(6, 14, 22, .5);
border: 1px solid #0076c8;
border-radius: 3px;
cursor: pointer;
}
.confirm-btn:hover {
background-color: rgba(6, 14, 22, .8);
}
/* .logout {
position: fixed;
bottom: 20px;
right: 20px;
height: 40px;
cursor: pointer;
} */
</style>最后App.vue中混入上面的邏輯lock.js,然后引入lock.vue組件并使用
因?yàn)槲业男枨笫钦麄€(gè)系統(tǒng)都要有鎖屏的功能,所以我將其寫在App.vue中
<template>
<div id="app">
<router-view />
<Lock v-if="isLock" />
</div>
</template>
<script>
import lockMixin from "@/mixins/lock";
export default {
mixins: [lockMixin]
}
</script>
<style lang="scss">
* {
margin: 0;
padding: 0;
}
#app {
width: 100vw;
height: 100vh;
overflow-y: hidden;
}
</style>最好再給大家上個(gè)鎖屏遮罩層的樣式效果吧,我這個(gè)當(dāng)然是在無操作5分鐘才顯示出來的哈

以上就是Vue實(shí)現(xiàn)鎖屏功能的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于Vue鎖屏的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue如何使用watch監(jiān)聽指定數(shù)據(jù)的變化
這篇文章主要介紹了vue如何使用watch監(jiān)聽指定數(shù)據(jù)的變化,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04
如何使用vue-json-viewer插件展示JSON格式數(shù)據(jù)
這篇文章主要給大家介紹了關(guān)于如何使用vue-json-viewer插件展示JSON格式數(shù)據(jù)的相關(guān)資料,Vue-json-viewer是一個(gè)Vue組件,用于在Vue應(yīng)用中顯示JSON數(shù)據(jù)的可視化工具,需要的朋友可以參考下2023-11-11
vue form表單post請求結(jié)合Servlet實(shí)現(xiàn)文件上傳功能
這篇文章主要介紹了vue form表單post請求結(jié)合Servlet實(shí)現(xiàn)文件上傳功能,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01
vue 解決在微信內(nèi)置瀏覽器中調(diào)用支付寶支付的情況
這篇文章主要介紹了vue 解決在微信內(nèi)置瀏覽器中調(diào)用支付寶支付的情況,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11

