話不多說,先上全部代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#dom_id{
width: 100px;
background-color: #e0e0e0;
font-size: 12px;
text-align: center;
}
.btn{
width: 70px;
height: 35px;
line-height: 35px;
text-align: center;
font-size: 14px;
background-color: #9c9c9c;
user-select: none;
cursor: pointer;
}
</style>
</head>
<body>
<div id="dom_id" >
<div>something dangerous</div>
<!-- <div>絲滑</div> -->
<div>絲滑</div>
</div>
<div class="btn" onclick="slideToogle(event,'dom_id',500)">切換</div>
<script>
function slideToogle(e,el,duration=1000){
var dom = document.getElementById(el)
dom.status = dom.status || getComputedStyle(dom,null)['display']
var flag = dom.status != 'none' //保存當前的顯示狀態,方便進行判斷
dom.status = flag?'none':'block' //更改dom上的顯示屬性
dom.style.transition = 'height '+duration/1000+'s' //設置動畫時間
dom.style.overflow = 'hidden' //保證子元素不外溢
animateDom(flag,dom,duration) //操作dom的height屬性
}
function animateDom(flag,dom,duration){
clearTimeout(dom.tagTimer);
setData(dom);
dom.style.height = flag?dom.tagHeight:"0px"
setTimeout(()=>{
dom.style.height = flag?"0px":dom.tagHeight
},0)
dom.tagTimer = setTimeout(()=>{
dom.style.display = flag?'none':'block'
dom.style.transition = '';
dom.style.overflow = '';
dom.style.height = '';
},duration)
}
function setData(dom){
dom.tagTimer = dom.tagTimer || null
dom.style.display = 'block';
dom.tagHeight = dom.tagHeight || dom.clientHeight+'px'
dom.style.display = '';
}
</script>
</body>
</html>
Transtion屬性
jquery、及vue的slide效果都用到了transition屬性,這個屬性設置的是元素的過渡效果,想要有這種絲滑的動態效果,必須要設置該屬性
div{
height: 50px;
/* 下面這行表示,height值如果變化,就會在1秒內線性變化到指定的值 */
transition: height 1s linear;
}
對要操作的dom進行處理
我在dom加了一個屬性data-status為了方便控制顯示和隱藏(其實可以直接設置在js的dom對象上),然后設置css的transition,overflow屬性。
<div id="dom_id" >
<div>something dangerous</div>
<!-- <div>絲滑</div> -->
<div>絲滑</div>
</div>
<div class="btn" onclick="slideToogle(event,'dom_id',500)">切換</div>
<script>
function slideToogle(e,el,duration=1000){
var dom = document.getElementById(el)
dom.status = dom.status || getComputedStyle(dom,null)['display']
var flag = dom.status != 'none' //保存當前的顯示狀態,方便進行判斷
dom.status = flag?'none':'block' //更改dom上的顯示屬性
dom.style.transition = 'height '+duration/1000+'s' //設置動畫時間
dom.style.overflow = 'hidden' //保證子元素不外溢
animateDom(flag,dom,duration) //操作dom的height屬性
}
</script>
操作dom時需要注意的點
function animateDom(flag,dom,duration){
clearTimeout(dom.tagTimer); // 清除定時器,因為連續點擊會產生很多定時器,避免同時作用於dom
setData(dom); // 這個函數主要是設置一下屬於當前dom的tagTimer,以及保存初始化高度tagHeight
dom.style.height = flag?dom.tagHeight:"0px" //這一行代碼是初始化height屬性,免得transition效果不觸發,
setTimeout(()=>{
//這個定時器只是為了讓js異步執行這兩行代碼(這里涉及宏任務和微任務的概念),從而產生transition的過渡效果
dom.style.height = flag?"0px":dom.tagHeight //如果是顯示,那就設置為原始高度,不顯示就設置為0px
},0)
dom.tagTimer = setTimeout(()=>{
//動畫結束以后設置 顯示狀態,並且把相關屬性清空,這樣更清爽,不是么?
dom.style.display = flag?'none':'block'
dom.style.transition = '';
dom.style.overflow = '';
dom.style.height = '';
},duration)
}
function setData(dom){ //這個就不多說了,理解一下
dom.tagTimer = dom.tagTimer || null
dom.style.display = 'block';
dom.tagHeight = dom.tagHeight || dom.clientHeight+'px'
dom.style.display = '';
}
