作为一只前端小汪,以自己一个初学者的视角,在这里记录自己在学习过程中遇到的问题,解决的方法,也算是成长的历程吧!过程中难免会有疏忽和自己没有发现的错误,如果你碰巧看到了我的博客,欢迎和我一起交流、学习,给我提出宝贵的意见。
我的QQ群号:495086635,需要学习资源的欢迎进群,我自己的资源无偿提供给大家。
手风琴效果的特点:每次只展开一个元素,其他的兄弟元素都闭合
先从样式和布局开始,做一个原生JS的手风琴效果
html:
1
2
3
4
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';
}
}
}
})();
此时,测试没有问题,接下来给代码添加动画,回到第一步