先说重点,一般这里锁屏这里放到了2个位置,一个是放到router-view和他同级,一个是用documount来实现放到对应的位置。
<template>
<div id="app">
<app-navbar v-if="!lockStatus"></app-navbar>
<router-view v-if="!lockStatus"></router-view>
<lock-screen :show-lock="lockStatus"></lock-screen>
</div>
</template>
<template>
<div id="app">
<router-view />
<lock-screen v-if="showLockScreen" @unlock="onlock" />
</div>
</template>
上面这种就是放到了router-view,还有一种就是
import LockScreenComponent from "./LockScreen.vue";
import { createApp, watch } from "vue";
const LockScreen = options => {
const LockScreenApp = createApp(LockScreenComponent, options);
showLockScreen(LockScreenApp);
};
const showLockScreen = app => {
const oFragment = document.createDocumentFragment();
const vm = app.mount(oFragment);
document.body.appendChild(oFragment);
vm.setVisible(true);
watch(vm.state, state => {
if (!state.visible) {
hideMessageBox(app);
}
});
};
const hideMessageBox = app => {
app.unmount();
};
export default LockScreen;
一个完整的例子
index.js
import LockScreen from "./src/index";
export { LockScreen };
src/index.js
import LockScreenComponent from "./LockScreen.vue";
import { createApp, watch } from "vue";
const LockScreen = options => {
const LockScreenApp = createApp(LockScreenComponent, options);
showLockScreen(LockScreenApp);
};
const showLockScreen = app => {
const oFragment = document.createDocumentFragment();
const vm = app.mount(oFragment);
document.body.appendChild(oFragment);
vm.setVisible(true);
watch(vm.state, state => {
if (!state.visible) {
hideMessageBox(app);
}
});
};
const hideMessageBox = app => {
app.unmount();
};
export default LockScreen;
src/LockScreen.vue
<template>
<transition name="messagebox-fade">
<div v-show="visible" class="messageBox-box">
<div class="lockscreen-item">
<div class="loc-date">
{{ date }}
</div>
<div class="loc-week">
{{ week }}
</div>
<div class="loc-time">
{{ time }}
</div>
<div class="loc-input">
<input type="text" v-model="state.lockValue" />
</div>
<div class="loc-btn">
<el-button type="primary" @click="cancalBtnClick">解锁</el-button>
</div>
</div>
</div>
</transition>
</template>
<script setup>
import { reactive, toRefs, onMounted, ref } from "vue";
import { getTime } from "@/utils/util";
import { ElMessage } from "element-plus";
const state = reactive({
visible: false,
promptValue: "",
type: "",
lockValue: ""
});
const { visible } = toRefs(state);
const setVisible = isVisible => {
state.visible = isVisible;
};
const cancalBtnClick = () => {
let item = localStorage.getItem("lockScreen");
if (item === state.lockValue) {
localStorage.removeItem("lockScreen");
setVisible(false);
} else {
return ElMessage.error("密码错误");
}
};
defineExpose({
setVisible,
state
});
const date = ref("loading..");
const time = ref("loading..");
const week = ref("loading..");
onMounted(() => {
setInterval(() => {
date.value = getTime(1);
time.value = getTime(2);
week.value = getTime(3);
}, 1000);
});
</script>
<style lang="scss" scoped>
.messagebox-fade-enter-from,
.messagebox-fade-leave-to {
opacity: 0;
}
.messagebox-fade-enter-active {
transition: opacity 0.2s ease-in;
}
.messagebox-fade-leave-active {
transition: opacity 0.2s ease-out;
}
.messageBox-box {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #000;
display: flex;
justify-content: center;
// align-items: center;
z-index: 2000;
animation: identifier 0.8s;
@keyframes identifier {
0% {
margin-left: 100vw;
}
100% {
margin-top: 0;
}
}
.lockscreen-item {
color: #fff;
text-align: center;
}
.loc-date {
text-align: center;
font-size: 30px;
margin-top: 50px;
}
.loc-week {
text-align: center;
font-size: 30px;
margin-top: 10px;
}
.loc-time {
font-size: 80px;
font-weight: bold;
margin-top: 10px;
}
.loc-input {
margin-top: 10px;
input {
margin: 40px 0;
box-sizing: border-box;
font-variant: tabular-nums;
list-style: none;
font-feature-settings: tnum;
position: relative;
display: inline-block;
width: 100%;
padding: 4px 11px;
color: #000000d9;
font-size: 14px;
line-height: 1.5715;
background-color: #fff;
background-image: none;
border: 1px solid #d9d9d9;
border-radius: 2px;
transition: all 0.3s;
outline: none;
}
}
}
</style>
触发上面的锁组件
这个layout中的组件中有个来触发锁屏的组件
<template>
<img src="@/assets/svg/suotou.svg" @click="handleLockScreen" style="width: 25x; height: 25px; cursor: pointer" />
</template>
<script setup>
import { onMounted } from "vue";
import { MessageBox } from "@/components/MessageBox";
import { LockScreen } from "@/components/LockScreen";
// 锁屏
const handleLockScreen = () => {
MessageBox.prompt({
confirmBtnText: "锁屏",
title: "请输入锁屏密码"
})
.then(value => {
if (!value)
return ElMessage({
message: "请输入",
type: "warning"
});
localStorage.setItem("lockScreen", value);
LockScreen();
})
.catch(() => {
console.log("取消");
});
};
onMounted(() => {
let lock = localStorage.getItem("lockScreen") || "";
if (lock) {
LockScreen();
}
});
</script>
另一种常见的完整例子
创建一个LockScreen.vue的组件,该组件包含一个输入框和按钮,用于验证锁屏密码。
<template>
<div class="lock-screen-container">
<input type="password" v-model="password" placeholder="请输入密码" />
<button @click="unlock">解锁</button>
</template>
<script>
export default {
data() {
return {
password: ''
}
},
methods: {
unlock() {
if (this.password === '{你设置的密码}') {
this.$emit('unlock'); //发送解锁事件
} else {
alert("密码错误");
}
}
}
}
</script>
<style scoped>
.lock-screen-container {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #fff;
display: flex;
align-items: center;
justify-content: center;
}
</style>
在App.vue中引入LockScreen组件,并使用v-if控制其显示和隐藏。
<template>
<div id="app">
<router-view />
<LockScreen v-if="showLockScreen" @unlock="unlock" />
</div>
</template>
<script>
import LockScreen from './components/LockScreen.vue';
export default {
data() {
return {
showLockScreen: false;
locked: false;
}
},
methods: {
lock() {
this.showLockScreen = true;
this.locked = true;
}
unlock() {
this.showLockScreen = false;
this.locked = true;
}
},
mounted() {
//监听页面是否出狱活动状态
document.addEventListener('visibilitychange', ()=>{
if (document.hidden && !this.locked) {
this.lock();
}
});
}
}
</script>
<style scoped>
.lock-screen-container {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #fff;
display: flex;
align-items: center;
justify-content: center;
}
</style>