<html>
<head>
<title>伸缩的菜单</title>
<style>
<!--
body{
background-color:#ffdee0;
}
#navigation {
width:200px;
font-family:Arial;
}
#navigation > ul {
list-style-type:none; /* 不显示项目符号 */
margin:0px;
padding:0px;
}
#navigation > ul > li {
border-bottom:1px solid #ED9F9F; /* 添加下划线 */
}
#navigation > ul > li > a{
display:block; /* 区块显示 */
padding:5px 5px 5px 0.5em;
text-decoration:none;
border-left:12px solid #711515; /* 左边的粗红边 */
border-right:1px solid #711515; /* 右侧阴影 */
}
#navigation > ul > li > a:link, #navigation > ul > li > a:visited{
background-color:#c11136;
color:#FFFFFF;
}
#navigation > ul > li > a:hover{ /* 鼠标经过时 */
background-color:#990020; /* 改变背景色 */
color:#ffff00; /* 改变文字颜色 */
}
/* 子菜单的CSS样式 */
#navigation ul li ul{
list-style-type:none;
margin:0px;
padding:0px 0px 0px 0px;
}
#navigation ul li ul li{
border-top:1px solid #ED9F9F;
}
#navigation ul li ul li a{
display:block;
padding:3px 3px 3px 0.5em;
text-decoration:none;
border-left:28px solid #a71f1f;
border-right:1px solid #711515;
}
#navigation ul li ul li a:link, #navigation ul li ul li a:visited{
background-color:#e85070;
color:#FFFFFF;
}
#navigation ul li ul li a:hover{
background-color:#c2425d;
color:#ffff00;
}
#navigation ul li ul.myHide{ /* 隐藏子菜单 */
display:none;
}
#navigation ul li ul.myShow{ /* 显示子菜单 */
display:block;
}
-->
</style>
<script language="javascript">
function change(){
//通过父元素li,找到兄弟元素ul
var oSecondDiv = this.parentNode.getElementsByTagName("ul")[0];
//CSS交替更换来实现显、隐
if(oSecondDiv.className == "myHide")
oSecondDiv.className = "myShow";
else
oSecondDiv.className = "myHide";
}
window.onload = function(){
var oUl = document.getElementById("listUL"); //一级菜单的ul标签
var aLi = oUl.childNodes; //子元素
var oA;
for(var i=0;i<aLi.length;i++){
//如果子元素为li,且这个li有子菜单ul
if(aLi[i].tagName == "LI" && aLi[i].getElementsByTagName("ul").length){
oA = aLi[i].firstChild; //找到超链接
oA.onclick = change; //动态添加点击函数
}
}
}
</script>
</head>
<body>
<div id="navigation">
<ul id="listUL">
<li><a href="#">Home</a></li>
<li><a href="#">News</a>
<ul class="myHide">
<li><a href="#">Lastest News</a></li>
<li><a href="#">All News</a></li>
</ul>
</li>
<li><a href="#">Sports</a>
<ul class="myHide">
<li><a href="#">Basketball</a></li>
<li><a href="#">Football</a></li>
<li><a href="#">Volleyball</a></li>
</ul>
</li>
<li><a href="#">Weather</a>
<ul class="myHide">
<li><a href="#">Today's Weather</a></li>
<li><a href="#">Forecast</a></li>
</ul>
</li>
<li><a href="#">Contact Me</a></li>
</ul>
</div>
</body>
</html>
上菜单为二级菜单,伸缩菜单是在一级菜单<li>下点击实现的
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh-cn">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<title>伸缩菜单</title>
<meta name="keywords" content="关键字列表" />
<meta name="description" content="网页描述" />
<link rel="stylesheet" type="text/css" href="" />
<style type="text/css">
body,p,ul,li{padding:0px;margin:0px;}
ul li{list-style:none;}
body{font-size:13px;}
.menu{
width:210px;
margin:50px auto;
border:1px solid #ccc;
}
.menu p{
height:25px;
line-height:25px;
font-weight:bold;
background:#eee;
border-bottom:1px solid #ccc;
padding-left:5px;
cursor:pointer;
}
.menu ul li{
height:24px;
line-height:24px;
padding-left:5px;
}
</style>
<script type="text/javascript">
//分析思路
//当页面加载完成后
//获取到所有的p元素 获取到所有的ul元素
//给每一个p元素绑定一个onclick事件
//判断每一个p元素对应的ul是否是隐藏或者是显示
window.onload = function(){
//获取id=menu对象
var div_obj = document.getElementById("menu");
//获取所有的p元素
var ps_obj = div_obj.getElementsByTagName("p");
var ps_length = ps_obj.length;
//获取到所有的ul元素
var uls_obj = div_obj.getElementsByTagName("ul");
//给每一个p元素绑定一个onclick事件
for(var i=0;i<ps_length;i++){
ps_obj[i].id = i; //给每一个p元素加上一个标识
ps_obj[i].onclick = function(){
//判断对应的ul是否是显示或者隐藏
if(uls_obj[this.id].style.display == "none"){
uls_obj[this.id].style.display = "block";
}else{
uls_obj[this.id].style.display = "none";
}
}
}
}
</script>
</head>
<body>
<div id="menu" class="menu">
<div>
<p>web前端</p>
<ul style="display:none;">
<li>HTML</li>
<li>DIV+CSS</li>
<li>JAVASCRIPT</li>
<li>jQuery</li>
<li>Bootstrap</li>
</ul>
</div>
<div>
<p>PHP+MYSQL核心编程</p>
<ul style="display:none;">
<li>PHP</li>
<li>MYSQL</li>
<li>HTTP协议</li>
<li>PHP绘图技术</li>
</ul>
</div>
<div>
<p>PHP高级</p>
<ul style="display:none;">
<li>XML编程</li>
<li>AJAX</li>
<li>MVC</li>
</ul>
</div>
</div>
</body>
</html>
类似QQ伸缩菜单:
插入,更新或从DOM中删除项目时,Vue提供了多种应用转换效果的方法。这包括以下工具:
在这个页面上,我们只会介绍进入,离开和列表转换,但您可以看到管理状态转换的下一部分。
过渡单个元素/组件
Vue提供了一个transition包装组件,允许您在以下上下文中为任何元素或组件添加进入/离开转换:
这就是一个例子:
<div id="demo"> <button v-on:click="show = !show"> Toggle </button> <transition name="fade"> <p v-if="show">hello</p> </transition> </div> new Vue({ el: '#demo', data: { show: true } }) .fade-enter-active, .fade-leave-active { transition: opacity .5s } .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ { opacity: 0 }
切换
hello
transition插入或移除组件中包含的元素时,会发生以下情况:
1. Vue会自动嗅探目标元素是否有CSS转换或动画应用。如果是这样,CSS转换类将在适当的时机添加/删除。
2. 如果转换组件提供了JavaScript钩子,这些钩子将在适当的时机调用。
3. 如果没有检测到CSS转换/动画,并且没有提供JavaScript钩子,插入和/或删除的DOM操作将在下一帧立即执行(注意:这是一个浏览器动画框架,与Vue的概念不同nextTick).Transition ClassesThere有六类申请进入/离开转换。
4. v-enter:输入的起始状态。插入元素之前添加,插入元素后删除一帧。
5. v-enter-active:输入的活动状态。在整个进入阶段应用。插入元素之前添加,当过渡/动画完成时删除。该类可用于定义输入转换的持续时间,延迟和缓动曲线。
6. v-enter-to:仅适用于版本2.1.8+。结束进入状态。插入元素后添加一个框架(同时v-enter删除),当转换/动画完成时删除。
7. v-leave:开始状态请假。当离开转换被触发时立即添加,在一帧后删除。
8. v-leave-active:离开的活动状态。在整个离开阶段应用。当离开转换被触发时立即添加,当转换/动画结束时删除。该类可用于定义离开转换的持续时间,延迟和缓动曲线。
9. v-leave-to:仅适用于版本2.1.8+。结束离开状态。加入一个帧一个离开转换被触发(在相同的时间之后v-leave被移除),当过渡/动画完成除去。
这些类将与过渡的名称为前缀。这里的v-前缀是你使用<transition>没有名字的元素时的默认值。如果你使用<transition name="my-transition">例子,那么这个v-enter类将会是my-transition-enter。v-enter-active和v-leave-active让您能够为进入/离开转换指定不同的缓动曲线,您将在下面的部分中看到一个示例.CSS转换一种最常见的转换类型使用CSS转换。下面是一个例子:
<button @click="show = !show"> Toggle render </button> <transition name="slide-fade"> <p v-if="show">hello</p> </transition> </div>new Vue({ el: '#example-1', data: { show: true } })/* Enter and leave animations can use different */ /* durations and timing functions. */ .slide-fade-enter-active { transition: all .3s ease; } .slide-fade-leave-active { transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0); } .slide-fade-enter, .slide-fade-leave-to /* .slide-fade-leave-active below version 2.1.8 */ { transform: translateX(10px); opacity: 0; }
CSS动画CSS动画以与CSS转换相同的方式应用,区别在于v-enter不是在插入元素后立即移除,而是在animationend事件中。这里是一个例子,为了简洁起见,省略了前缀CSS规则:<div id="example-2"> <button @click="show = !show">Toggle show</button> <transition name="bounce"> <p v-if="show">Look at me!</p> </transition> </div>new Vue({ el: '#example-2', data: { show: true } }).bounce-enter-active { animation: bounce-in .5s; } .bounce-leave-active { animation: bounce-in .5s reverse; } @keyframes bounce-in { 0% { transform: scale(0); } 50% { transform: scale(1.5); } 100% { transform: scale(1); } }
自定义转换类您还可以通过提供以下属性来指定自定义转换类:
10. enter-class
11. enter-active-class
12. enter-to-class (2.1.8+)
13. leave-class
14. leave-active-class
15. leave-to-class (2.1.8+)
这些将覆盖传统的类名称。当您想要将Vue的转换系统与现有的CSS动画库(如Animate.css)结合使用时,此功能特别有用。
这是一个例子:
<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css"> <div id="example-3"> <button @click="show = !show"> Toggle render </button> <transition name="custom-classes-transition" enter-active-class="animated tada" leave-active-class="animated bounceOutRight" > <p v-if="show">hello</p> </transition> </div> new Vue({ el: '#example-3', data: { show: true } })
一起使用转换和动画
Vue需要附加事件监听器才能知道转换何时结束。它可以是transitionend或者animationend,取决于所应用的CSS规则的类型。如果您只使用其中一种,Vue可以自动检测正确的类型。
然而,在某些情况下,您可能希望同时拥有两个元素,例如由Vue触发的CSS动画,以及悬停时的CSS过渡效果。在这些情况下,您必须在type属性中明确声明您想要Vue关心的类型,其值为animation或transition。
显式过渡时间
New in 2.2.0+
在大多数情况下,Vue可以自动计算转换完成的时间。默认情况下,Vue等待根转换元素上的第一个transitionend或animationend事件。然而,这可能并不总是需要的 - 例如,我们可能有一个编排的转换序列,其中一些嵌套的内部元素具有比根转换元素延迟的转换或更长的转换持续时间。
在这种情况下,您可以使用组件duration上的prop 指定明确的转换持续时间(以毫秒为单位)<transition>:
<transition :duration="1000">...</transition>
您还可以为输入和保留持续时间指定单独的值:
<transition :duration="{ enter: 500, leave: 800 }">...</transition>
JavaScript Hooks
你也可以在属性中定义JavaScript hooks:
<transition v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:after-enter="afterEnter" v-on:enter-cancelled="enterCancelled" v-on:before-leave="beforeLeave" v-on:leave="leave" v-on:after-leave="afterLeave" v-on:leave-cancelled="leaveCancelled" > <!-- ... --> </transition> // ... methods: { // -------- // ENTERING // -------- beforeEnter: function (el) { // ... }, // the done callback is optional when // used in combination with CSS enter: function (el, done) { // ... done() }, afterEnter: function (el) { // ... }, enterCancelled: function (el) { // ... }, // -------- // LEAVING // -------- beforeLeave: function (el) { // ... }, // the done callback is optional when // used in combination with CSS leave: function (el, done) { // ... done() }, afterLeave: function (el) { // ... }, // leaveCancelled only available with v-show leaveCancelled: function (el) { // ... } }
这些钩子可以与CSS转换/动画结合使用或单独使用。
当使用JavaScript的过渡只,将 需要为回调和钩。否则,它们将被同步调用,并且转换将立即结束。done enter leave
明确添加v-bind:css="false"仅用于JavaScript的转换也是一个好主意,以便Vue可以跳过CSS检测。这也可以防止CSS规则意外干扰转换。
现在我们来看一个例子。这里使用了Velocity.js的JavaScript转换:
<!-- Velocity works very much like jQuery.animate and is a great option for JavaScript animations --> <script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script> <div id="example-4"> <button @click="show = !show"> Toggle </button> <transition v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:leave="leave" v-bind:css="false" > <p v-if="show"> Demo </p> </transition> </div> new Vue({ el: '#example-4', data: { show: false }, methods: { beforeEnter: function (el) { el.style.opacity = 0 }, enter: function (el, done) { Velocity(el, { opacity: 1, fontSize: '1.4em' }, { duration: 300 }) Velocity(el, { fontSize: '1em' }, { complete: done }) }, leave: function (el, done) { Velocity(el, { translateX: '15px', rotateZ: '50deg' }, { duration: 600 }) Velocity(el, { rotateZ: '100deg' }, { loop: 2 }) Velocity(el, { rotateZ: '45deg', translateY: '30px', translateX: '30px', opacity: 0 }, { complete: done }) } } })
初始渲染过渡
如果您还想在节点的初始渲染上应用转场,则可以添加appear属性:
<transition appear> <!-- ... --> </transition>
默认情况下,这将使用为进入和离开指定的转换。但是,如果您想要,也可以指定自定义CSS类:
<transition appear appear-class="custom-appear-class" appear-to-class="custom-appear-to-class" (2.1.8+) appear-active-class="custom-appear-active-class" > <!-- ... --> </transition>
和自定义JavaScript钩:
<transition appear v-on:before-appear="customBeforeAppearHook" v-on:appear="customAppearHook" v-on:after-appear="customAfterAppearHook" v-on:appear-cancelled="customAppearCancelledHook" > <!-- ... --> </transition>
元素之间的过渡
我们稍后讨论组件之间的转换,但也可以使用v-if/ 在各个原始元素之间转换v-else。最常见的两元素转换之一是在列表容器和描述空列表的消息之间:
<transition> <table v-if="items.length > 0"> <!-- ... --> </table> <p v-else>Sorry, no items found.</p> </transition>
这很有效,但有一点需要注意:
在具有相同标签名称的元素之间切换时,必须通过为Vue指定唯一key属性来区分它们是不同的元素。否则,Vue的编译器只会替换元素的内容以提高效率。即使在技术上没有必要,但总是在<transition>组件内键入多个项目被认为是很好的做法。
例如:
<transition> <button v-if="isEditing" key="save"> Save </button> <button v-else key="edit"> Edit </button> </transition>
在这些情况下,您也可以使用该key属性在同一元素的不同状态之间转换。代替使用的v-if和v-else,上述例子可以被重写为:
<transition> <button v-bind:key="isEditing"> {{ isEditing ? 'Save' : 'Edit' }} </button> </transition>
实际上可以在任意数量的元素之间进行转换,可以使用多个v-ifs或将单个元素绑定到动态属性。例如:
<transition> <button v-if="docState === 'saved'" key="saved"> Edit </button> <button v-if="docState === 'edited'" key="edited"> Save </button> <button v-if="docState === 'editing'" key="editing"> Cancel </button> </transition>
这也可以写成:
<transition> <button v-bind:key="docState"> {{ buttonMessage }} </button> </transition> // ... computed: { buttonMessage: function () { switch (this.docState) { case 'saved': return 'Edit' case 'edited': return 'Save' case 'editing': return 'Cancel' } } }
过渡模式
但仍然有一个问题。尝试点击下面的按钮:
当它在“开启”按钮和“关闭”按钮之间转换时,两个按钮都被渲染 - 一个转换出来,而另一个转换进来。这是<transition>的默认行为- 进入和离开同时发生。
有时候,这很有效,就像转换项目绝对位于彼此之上一样:
然后也可能翻译成它们看起来像幻灯片切换:
虽然同时进入和离开转换并不总是需要,所以Vue提供了一些替代转换模式:
现在让我们用out-in更新我们开/关按钮的转换:
<transition name="fade" mode="out-in"> <!-- ... the buttons ... --> </transition>
除了一个属性外,我们已经修复了原始转换,而无需添加任何特殊样式。
该in-out模式并不经常使用,但有时对于稍微不同的过渡效果有用。让我们尝试将它与早先我们所做的幻灯片淡化转换相结合:
(这种方法)很酷,对吧?
组件之间的转换
组件之间的转换甚至更简单 - 我们甚至不需要该key属性。相反,我们包装一个动态组件:
<transition name="component-fade" mode="out-in"> <component v-bind:is="view"></component> </transition> new Vue({ el: '#transition-components-demo', data: { view: 'v-a' }, components: { 'v-a': { template: '<div>Component A</div>' }, 'v-b': { template: '<div>Component B</div>' } } }) .component-fade-enter-active, .component-fade-leave-active { transition: opacity .3s ease; } .component-fade-enter, .component-fade-leave-to /* .component-fade-leave-active below version 2.1.8 */ { opacity: 0; }
列表转换
到目前为止,我们已经为以下方面管理过渡:
那么当我们有一整套我们想要同时渲染的物品时,例如v-for。在这种情况下,我们将使用该<transition-group>组件。在我们深入研究一个例子之前,有几件重要的事情要了解这个组件:
列表输入/离开转场
现在我们来看一个例子,使用我们以前使用过的相同的CSS类来转换进入和离开:
<div id="list-demo"> <button v-on:click="add">Add</button> <button v-on:click="remove">Remove</button> <transition-group name="list" tag="p"> <span v-for="item in items" v-bind:key="item" class="list-item"> {{ item }} </span> </transition-group> </div> new Vue({ el: '#list-demo', data: { items: [1,2,3,4,5,6,7,8,9], nextNum: 10 }, methods: { randomIndex: function () { return Math.floor(Math.random() * this.items.length) }, add: function () { this.items.splice(this.randomIndex(), 0, this.nextNum++) }, remove: function () { this.items.splice(this.randomIndex(), 1) }, } }) .list-item { display: inline-block; margin-right: 10px; } .list-enter-active, .list-leave-active { transition: all 1s; } .list-enter, .list-leave-to /* .list-leave-active below version 2.1.8 */ { opacity: 0; transform: translateY(30px); }
这个例子有一个问题。当你添加或删除一件物品时,它周围的物品会立即进入新位置,而不是平稳过渡。我们稍后会解决这个问题。
列表移动转换
<transition-group>组件还有另一个窍门。它不仅可以动画进入和离开,而且可以改变位置。您需要知道的使用此功能的唯一新概念是添加了v-move类,该类在项目更改位置时添加。像其他类一样,它的前缀将与提供的属性的值匹配,您也可以手动指定具有namemove-class属性的类。
该类对于指定转换时间和缓动曲线非常有用,如下所示:
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script> <div id="flip-list-demo" class="demo"> <button v-on:click="shuffle">Shuffle</button> <transition-group name="flip-list" tag="ul"> <li v-for="item in items" v-bind:key="item"> {{ item }} </li> </transition-group> </div> new Vue({ el: '#flip-list-demo', data: { items: [1,2,3,4,5,6,7,8,9] }, methods: { shuffle: function () { this.items = _.shuffle(this.items) } } }) .flip-list-move { transition: transform 1s; }
这可能看起来很神奇,但在引擎盖下,Vue正在使用名为FLIP的动画技术,以使用变换平滑地将元素从旧位置过渡到新位置。
我们可以将此技术与我们之前的实现结合起来,为每个可能的变化添加动画。
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script> <div id="list-complete-demo" class="demo"> <button v-on:click="shuffle">Shuffle</button> <button v-on:click="add">Add</button> <button v-on:click="remove">Remove</button> <transition-group name="list-complete" tag="p"> <span v-for="item in items" v-bind:key="item" class="list-complete-item" > {{ item }} </span> </transition-group> </div> new Vue({ el: '#list-complete-demo', data: { items: [1,2,3,4,5,6,7,8,9], nextNum: 10 }, methods: { randomIndex: function () { return Math.floor(Math.random() * this.items.length) }, add: function () { this.items.splice(this.randomIndex(), 0, this.nextNum++) }, remove: function () { this.items.splice(this.randomIndex(), 1) }, shuffle: function () { this.items = _.shuffle(this.items) } } }) .list-complete-item { transition: all 1s; display: inline-block; margin-right: 10px; } .list-complete-enter, .list-complete-leave-to /* .list-complete-leave-active below version 2.1.8 */ { opacity: 0; transform: translateY(30px); } .list-complete-leave-active { position: absolute; }
一个重要的提示是,这些FLIP转换不适用于设置为的元素display: inline。作为替代,您可以display: inline-block在Flex上下文中使用或放置元素。
这些FLIP动画也不限于单个轴。多维网格中的项目也可以进行转换:
交错列表转换
通过通过数据属性与JavaScript转换进行通信,也可以在列表中错开转换:
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script> <div id="staggered-list-demo"> <input v-model="query"> <transition-group name="staggered-fade" tag="ul" v-bind:css="false" v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:leave="leave" > <li v-for="(item, index) in computedList" v-bind:key="item.msg" v-bind:data-index="index" >{{ item.msg }}</li> </transition-group> </div> new Vue({ el: '#staggered-list-demo', data: { query: '', list: [ { msg: 'Bruce Lee' }, { msg: 'Jackie Chan' }, { msg: 'Chuck Norris' }, { msg: 'Jet Li' }, { msg: 'Kung Fury' } ] }, computed: { computedList: function () { var vm = this return this.list.filter(function (item) { return item.msg.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1 }) } }, methods: { beforeEnter: function (el) { el.style.opacity = 0 el.style.height = 0 }, enter: function (el, done) { var delay = el.dataset.index * 150 setTimeout(function () { Velocity( el, { opacity: 1, height: '1.6em' }, { complete: done } ) }, delay) }, leave: function (el, done) { var delay = el.dataset.index * 150 setTimeout(function () { Velocity( el, { opacity: 0, height: 0 }, { complete: done } ) }, delay) } } })
可重复使用的转换
转换可以通过Vue的组件系统重用。要创建可重用的转换,您只需将<transition>或<transition-group>组件放在根上,然后将所有子项传递给转换组件。
以下是使用模板组件的示例:
Vue.component('my-special-transition', { template: '\ <transition\ name="very-special-transition"\ mode="out-in"\ v-on:before-enter="beforeEnter"\ v-on:after-enter="afterEnter"\ >\ <slot></slot>\ </transition>\ ', methods: { beforeEnter: function (el) { // ... }, afterEnter: function (el) { // ... } } })
功能组件特别适合这项任务:
Vue.component('my-special-transition', { functional: true, render: function (createElement, context) { var data = { props: { name: 'very-special-transition', mode: 'out-in' }, on: { beforeEnter: function (el) { // ... }, afterEnter: function (el) { // ... } } } return createElement('transition', data, context.children) } })
动态转换
是的,甚至Vue中的转换都是数据驱动的!动态转换的最基本示例将该name属性绑定到动态属性。
<transition v-bind:name="transitionName"> <!-- ... --> </transition>
当您使用Vue的过渡类约定定义CSS过渡/动画并希望在它们之间切换时,这会很有用。
实际上,任何转换属性都可以动态绑定。这不仅是属性。由于事件挂钩是方法,因此它们可以访问上下文中的任何数据。这意味着取决于组件的状态,JavaScript转换可能会有不同的表现。
平时做前端开发,对于页面切换、最小化、长时间不操作这些安全问题,其实接触不多,除非涉及到隐秘问题,可能需要将这些实现考虑进去。这次我接到这个需求时,也是处于懵逼状态
visibilityChange,这个在浏览器标签页被隐藏或显示的时候都会除非该方法,看似能满足页面切换或最小化。但是它有个问题,就是在页面缩放,下图绿色标识,而非最小化时也会执行该方法。
document.addEventListener(visibilityChange, () => { let screenTop = window.localStorage.getItem('screenTop'); // 隐藏时触发了2次 setTimeout(() => { // 采用screenTop,是因为缩放时也会触发该事件,无法区分是缩放还是最小化 if (screenTop && screenTop == window.screenTop && document.visibilityState === hidden) { this.props.dispatch({ type: 'SET_PAYROLL_STATUS', data: false }) // window.location.href = window.location.href; } else { window.localStorage.setItem('screenTop', window.screenTop) } }, 0) }, false)
上面代码中的判断screenTop==window.screenTop能将缩放这个排除在外,结合document.visibilityState能实现页面切换、页面最小化的时候修改状态保证页面内容安全,譬如通过设置状态为false,不展示设计安全的内容。
而判断长时间是否操作,主要是通过setInterval来倒计时变量count,如果有操作就将count初始化,从新倒计时。
hasOperate = (callback, second) => { let count = 0; const countTime = () => { timer = setInterval(() => { if (document.visibilityState === 'hidden') { count = 0; // clearInterval(timer); } count++; if (count == second) { callback(); clearInterval(timer); count=0 } }, 1000); } let x; let y; document.addEventListener('mousemove', () => { let x1 = event.clientX; let y1 = event.clientY; if (x != x1 || y != y1) { count = 0; } x = x1; y = y1; }) document.addEventListener('keydown', () => { count = 0; }) document.addEventListener('scroll', () => { count = 0; })
上面代码,主要通过统计count等于你设置的初始化时间second,进行回调,回调的主要内容是隐藏安全页面;如果在统计的过程中发现有滚动或鼠标移动以及键盘按下等相关操作,则将count初始化为0,酱紫就能完成长时间不操作的问题了
*请认真填写需求信息,我们会在24小时内与您取得联系。