手風琴效果——原生JS
寫在前面
作為一隻前端小汪,以自己一個初學者的視角,在這裡記錄自己在學習過程中遇到的問題,解決的方法,也算是成長的歷程吧!過程中難免會有疏忽和自己沒有發現的錯誤,如果你碰巧看到了我的部落格,歡迎和我一起交流、學習,給我提出寶貴的意見。
我的QQ群號:495086635,需要學習資源的歡迎進群,我自己的資源無償提供給大家。
酷炫的手風琴效果
手風琴效果的特點:每次只展開一個元素,其他的兄弟元素都閉合
先從樣式和佈局開始,做一個原生JS的手風琴效果
html:
<div class="c"> <p class="red">1</p> <p class="blue">2</p> <p class="green">3</p> <p class="yellow">4</p> </div>
css:
.c{ background-color: black; } .c::before,.c::after{ content: ''; display: table; } .c::after{ clear: both; } .red{ width: 100px; background-color:red; float: left; height: 300px; } .blue{ background-color:blue; } .green{ background-color: green; } .yellow{ background-color: yellow; } .yellow,.green,.blue{ width: 20px; float: left; height: 300px; }
效果如圖:
寫完結構和樣式,對JS要完成的效果進行拆解
需求分析:當滑鼠點選一個元素時,對應元素的寬度變大,兄弟元素中寬度最大的元素寬度變小
實踐:
1.首先,手風琴的效果要動起來,在JS中能夠動起來的只有計時器,因此這裡會用到週期性計時器,這一步可以後寫,先進行第二步
如果你回到這裡,恭喜你,已經完成了一半
問題:何時停掉計時器,停計時器要寫在計時器函式中,滿足條件時清除計時器
+(function () { //查詢元素 var c = document.querySelector('.c'); var ps = document.querySelectorAll('.c p'); //繫結事件:事件的物件是其中一個p元素,給每個p元素繫結事件 for (var i = 0; i < ps.length; i++) { //需求的第一個元素:被點選的元素 var p = ps[i]; p.onclick = function () { //需求的第二個元素:兄弟中最大的元素 for (var j = 0; j < ps.length; j++) { if(getComputedStyle(ps[j]).width=='100px'){ var obj = ps[j]; break; } } if(parseInt(getComputedStyle(this).width)==20){ //新增計時器 var timer = setInterval(move,100); var step = 10; var that = this; function move() { if(parseInt(getComputedStyle(that).width)<100){ //點選的當前元素寬度變大 that.style.width = parseInt(getComputedStyle(that).width) + step + 'px'; obj.style.width = parseInt(getComputedStyle(obj).width) - step + 'px'; console.log(getComputedStyle(that).width); }else{ clearInterval(timer); } } } } } })();
問題:如果一次元素的寬度尚未到達20px,又去點選另一個元素,這時兩個元素會同時動,
解決:讓一個動作完成再執行另一個動作
分析:判斷另一個動作是否要執行時在執行前判斷的,所以在事件之外定義一個布林全域性變數
+(function () {
//查詢元素
var c = document.querySelector('.c');
var ps = document.querySelectorAll('.c p');
//繫結事件:事件的物件是其中一個p元素,給每個p元素繫結事件
for (var i = 0; i < ps.length; i++) {
//需求的第一個元素:被點選的元素
var p = ps[i];
var flag = true;
p.onclick = function () {
if(flag){
flag = false;
//需求的第二個元素:兄弟中最大的元素
for (var j = 0; j < ps.length; j++) {
if(getComputedStyle(ps[j]).width=='100px'){
var obj = ps[j];
break;
}
}
if(parseInt(getComputedStyle(this).width)==20){
//新增計時器
var timer = setInterval(move,100);
var step = 10;
var that = this;
function move() {
if(parseInt(getComputedStyle(that).width)<100){
//點選的當前元素寬度變大
that.style.width = parseInt(getComputedStyle(that).width) + step + 'px';
obj.style.width = parseInt(getComputedStyle(obj).width) - step + 'px';
console.log(getComputedStyle(that).width);
}else{
clearInterval(timer);
flag = true;
}
}
}
}
}
}
})();
2.從需求來看,這裡需要一個事件,事件的三要素:元素、事件、函式
元素:被點選的元素和兄弟元素中最大的那個(兩個)
事件:click
函式:匿名函式
函式的功能:①點選的當前元素:如果寬度為20px,變為100px;否則,不變
+(function () {
//查詢元素
var c = document.querySelector('.c');
var ps = document.querySelectorAll('.c p');
//繫結事件:事件的物件是其中一個p元素,給每個p元素繫結事件
for (var i = 0; i < ps.length; i++) {
//需求的第一個元素:被點選的元素
var p = ps[i];
//需求的第二個元素:兄弟中最大的元素
for (var j = 0; j < ps.length; j++) {
if(getComputedStyle(ps[j]).width=='100px'){
var obj = ps[j];
break;
}
}
p.onclick = function () {
console.log("我執行了");
//點選的當前元素寬度變大
if(getComputedStyle(this).width=='20px'){
this.style.width = 100 + 'px';
obj.style.width = 20 + 'px';
}
}
}
})();
程式碼到這裡遇到一個問題:除了初始設定預設值100px的那個元素,以後的元素寬度都不會再變回20px
分析:兄弟中最大的元素除了預設值之外,都是點選事件發生後才產生的,上面的程式碼只在初始時獲得一次,點選後產生的最大兄弟元素並沒有獲得,因此,查詢兄弟中最大的元素應該放在事件處理函式中
更新程式碼:
+(function () {
//查詢元素
var c = document.querySelector('.c');
var ps = document.querySelectorAll('.c p');
//繫結事件:事件的物件是其中一個p元素,給每個p元素繫結事件
for (var i = 0; i < ps.length; i++) {
//需求的第一個元素:被點選的元素
var p = ps[i];
p.onclick = function () {
//需求的第二個元素:兄弟中最大的元素
for (var j = 0; j < ps.length; j++) {
if(getComputedStyle(ps[j]).width=='100px'){
var obj = ps[j];
break;
}
}
//點選的當前元素寬度變大
if(getComputedStyle(this).width=='20px'){
this.style.width = 100 + 'px';
obj.style.width = 20 + 'px';
}
}
}
})();
此時,測試沒有問題,接下來給程式碼新增動畫,回到第一步