DOM(demo实操)

写在前面

这个文档主要是复习dom相关操作
属于实际操作性 只是复习知识点的就不用往下看了(太多了你难得找)
当然要是有初学者看到这里希望你一步一步按照下面的来操作
对dom操作的熟悉和运用会帮助很大
苦其心志 劳其筋骨 会有不小的收获

点击行变色

//获取点击元素:
window.event.srcElement
//或者
xxx.addEventListener("click",function(e){
	console.log(e.target);
})
//获取列表所有行 这里table1是列表table的ID名(好像必须是这个,类名用不起)
document.all.table1.rows;
//获取之后给循环到的元素加上类名(清空背景色的类)或者backgroundColor直接赋颜色值白色
//然后给点击元素的父元素附上变化的颜色比如红色
window.event.srcElement.parentNode.style.backgroundColor = 'red';


//完整代码贴一贴
function click(){
	var arr1 = window.event.srcElement.parentNode;
	for (let i = 0; i < document.all.table1.rows.length; i++) {
	    document.all.table1.rows[i].style.backgroundColor = '';
	    arr1.style.backgroundColor = 'red';
	}
}

点击列变色

//关于思路
//1.获取点击元素所在那一列的元素
//先获取所有行(也就是每个单元格的元素)
var arr = window.event.srcElement.parentNode.parentNode.children
var arr1 = document.all.table1.rows
//最开始我在想这两者的区别,打印出来发现获取的都是同一个数组(存放的是所有的tr元素)
//那就用第二个呗毕竟代码量小一些

//2.先将所有元素的背景色设为无
//这里补充一点通过上面两种获取的数组里有一个属性cellIndex就是该元素在其父级的下标
//这里指的是点击元素在 window.event.srcElement在父级中的也就是tr中td的下标

//所以现在在清除(或者将所有td元素背景色设置为无)所有td元素背景色后
//再去给点击的所有行cellIndex相同的元素的背景色设置为自己的颜色
//上面两行首先要将所有元素清除背景色也就是我们需要两层循环先遍历行再遍历每行的所有的元素

//完整代码
function change(e) {
	var arr = window.event.srcElement.parentNode.parentNode.children;
	var arr1 = document.all.table1.rows;
	//console.log(arr, arr1) 测试用 以及上面两个任选其一即可,这里用的是arr1
	for (let i = 0; i < arr1.length; i++) {
		for (let j = 0; j < arr1[i].children.length; j++) {
			arr1[i].children[j].style.backgroundColor = '';
			//先遍历行再遍历每行的所有的元素,然后将所有元素的背景色设为无
		}
		arr1[i].children[window.event.srcElement.cellIndex].style.backgroundColor = 'red';
		//给点击的所有行cellIndex相同的元素的背景色设置为自己的颜色
	}
}
总结

上面两个demo主要涉及的知识点:

  1. 事件的三要素
  2. 绑定事件的方法
  3. DOM元素相关的属性(父节点子节点的返回值及其返回数组中的属性cellIndex)
  4. 排它设计(这是个思想,这里主要是先清空全部元素样式,然后给对应的需求元素加上想要的样式)
    PS:cellIndex这个属性仅仅存在于tr里,在无序列表中没有
相关知识点说明

1.事件的三要素

  • 事件源 :要触发的对象 (一般是名词,事件发起者,比如div,li等等)
  • 事件:怎么触发这个事情 (一般是动词,触发事件,比如onclick,onmousedown)
  • 事件处理函数:发生了什么事情 (处理函数,打印一段文字,发起ajax请求等等)

2.绑定事件的方法

  • 行内绑定,例:(单一性绑定)
    <button type="button" onclick="fn()">xxx</button>

  • 选择器绑定,例:(单一性绑定)
    document.querySelector("#btn1").onclick=function() {console.log(111)}

  • 添加监听器(addEventListener):
    btn2.addEventListener("click",function() {console.log(777)})

3.Dom元素相关属性

  • classList
    -是html5新增的操作类名的方式,新类型具有如下方法:
    add():给指定的字符串(要添加的类名)添加到类表中,如果值已经存在就不添加了;
    remove():从列表中删除指定的字符串(要删除的类名)
    (只能放入一个参数,且只能一次性的操作添加,删除类名的操作)

  • children & childNodes
    children(获取的是子元素)
    childNodes(获取的是子节点包含空格,换行符(当做文本节点))
    两者返回的值都是数组

  • parentElement & parentNode
    parentElement (parentElement找的是元素,因此当找到根部document时候就是出现值为null的报错) parentNode(parentNode找的是节点,当然就可以显示出来)
    在其他的地方显示的结果都是相同的,显示的都是父级元素(HTML的格式)

下拉菜单的设计

做demo之前要先理清代码的逻辑
通过点击控制下滑和上收--------事件的绑定,条件控制语句控制下滑和上收执行函数if & addEventListener
下滑和上收------动画效果,使用定时器和清除定时器setInterval & clearInterval
获取高度-------需要变化元素的高度window.getComputedStyle(获取元素).height
转化-----获取的高度的值是字符串,所以这里用parseInt & parseFloat即可转化为数值用于if判断条件
高度的计算公式--------- 选中元素高度 = 选中元素高度 + (目标高度 - 选中元素高度)*0.7 + ‘px’

以上涉及到的问题
关于定时器,下滑和上收是两个处理函数,其中之一运行的时候必须要先清除另一个定时器,否则同时运行则会出现bug
定时器的声明需要在全局作用域下,不然清除定时器时因为互相定时器函数形成的作用域而无法访问变量

关于条件控制语句的判断条件-----全局作用域下声明一个控制变量,值为false&true,每次点击的时候的取反值即可

 		var btn = document.querySelector("#sss") //点击元素
        var box1 = document.querySelector(".sv") //被控制的元素
 		var flag = false //标志位控制变量
        btn.addEventListener('click', () => {
            flag = !flag
            if (flag) {
                window.timer1 = setInterval(() => {
                    var bh = parseFloat(window.getComputedStyle(btn).height)
                    var rh = parseFloat(window.getComputedStyle(box1).height)
                    box1.style.height = rh + (bh - rh) * 0.7 + 'px'//高度的计算公式
                    if (rh <= bh) { 
                    //这里是因为是选取ul里的li元素,所以在控制外层div高度变化时必须留下点击元素
                        window.clearInterval(timer1)
                    }
                }, 50)
            } else {
                window.timer2 = setInterval(() => {
                    if (window.timer1 != null) {
                        window.clearInterval(timer1)//使用前先清理上一个定时器
                    }
                    var bh = parseFloat(window.getComputedStyle(btn).height)
                    var rh = parseFloat(window.getComputedStyle(box1).height)
                    box1.style.height = rh + (210 - rh) * 0.7 + 'px'//高度的计算公式
                    if (rh >= 200) {
                        window.clearInterval(timer2)
                    }
                }, 50)
            }
        })

多级联动

先上效果图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
效果就是点击第一列的省份会弹出对应的城市
再去点击城市会弹出对应的交通站点

理理逻辑
这里的数据是用的假数据(写好的模拟数据)
意在模仿多级联动的效果

 var data = [{
            name: "四川",
            next: [{
                name: '成都',
                next: ["东站", "北站", "南站", "西站", "汽车客运站", "双流机场"]
            }, {
                name: '绵阳',
                next: ["富乐汽车站", "南湖汽车站", "火车站"]
            }, {
                name: '广安',
                next: ["广安南站", "广安北站"]
            }]
        }, {
            name: "云南",
            next: [{
                name: '大理',
                next: ["东站", "北站", "南站"]
            }, {
                name: '昆明',
                next: ["东站", "北站", "南站", "东站", "北站", "南站"]
            }, {
                name: '五华区',
                next: ["东站", "北站"]
            }, {
                name: '水富县',
                next: ["东站", "北站", "南站"]
            }, {
                name: '安宁县',
                next: ["东站", "北站", "南站", "东站", "北站", "南站"]
            }, {
                name: '香格里拉',
                next: ["东站", "北站"]
            }]
        }, {
            name: "浙江",
            next: [{
                name: '杭州',
                next: ["一区", "二区", "三区", "四区", '五区', "六区"]
            }, {
                name: '温州',
                next: ["1区", "2区"]
            }, {
                name: '金华',
                next: ["壹区", "贰区", "叁区", "肆区"]
            }]
        }, {
            name: "重庆",
            next: [{
                name: '万州',
                next: ["东站", "北站", "南站"]
            }, {
                name: '渝北',
                next: ["东站", "北站", "南站", "东站", "北站", "南站"]
            }, {
                name: '北碚',
                next: ["东站", "北站"]
            }, {
                name: '渝中',
                next: ["东站", "北站", "南站"]
            }, {
                name: '大渡口',
                next: ["东站", "北站", "南站", "东站", "北站", "南站 "]
            }]
        }]

这里先要在body中创建一个盒子来容纳第一级的数据
(看数据最好是打印在Chrome中便于查看,直接看数据会看晕)
所以要先创建盒子,然后data进行循环,在循环里创建每个省份的小盒子,用于存放省份的名字数据
创建之后还得将每个小盒子添加进容纳第一级数据的盒子,然后给每个小盒子添加点击事件,再去创建存放下一级数据的盒子,然后依次类推直到全部循环完毕

以上涉及的问题

  • 容纳每级数据的盒子是兄弟关系,也就是并列关系,使用浮动去排列,所以添加到的都是body下也就是这句document.body.appendChild(box)
  • 盒子和小盒子的样式各设置一个,所有的盒子和小盒子类名都采用相同类名(减少代码量)
  • 排它设计:这个很重要,就是你点击第一级省份的每个省份时,如果不对之前的进行清除,就会全部依次排列(下图)
    在这里插入图片描述
    所以这里要对其进行清除
    前面说到了存放每个省份城市和站点的数据都会有一个盒子去装他们,这里就可以用到这句
var boxs = document.querySelectorAll('.box')
boxs.forEach((el, index) => {
	if (index > 0) {
		el.remove()
	}
})

通过foreach自带的index参数去算,第一级就是下标为零,所以利用这点就可以去清除

  • 最后一点就是再点完所有的省份城市和站点最好是将其在当层数组的下标和点击的数据打印出来便于收集点击的具体站点,这里在最内层的循环里添加点击事件,为了区分每层的index参数那就给每层的foreach的index参数取上不同名字(下图)
btn.onclick = function() {
	console.log(data[index1].name, 
	data[index1].next[index2].name, 
	data[index1].next[index2].next[index3])
	console.log('第' + (index1 + 1) + '个省',
	'第' + (index2 + 1) + '个市', 
	'第' + (index3 + 1) + '个站')
}

最后就上代码

//创建并添加到body下用于容纳存放第一级数据小盒子的盒子
var box = document.createElement('div')
box.className = 'box'
document.body.appendChild(box)
//对第一级的数组进行遍历
data.forEach((el, index1) => {
	//创建容纳第一级数据的小盒子
	var btn = document.createElement('div')
	btn.className = 'btn'
	btn.innerHTML = el.name
	box.appendChild(btn)
	//给第一级每个小盒子添加点击事件
	btn.onclick = function() {
		//排它设计 清除第一级的二级盒子
		var boxs = document.querySelectorAll('.box')
		boxs.forEach((el, index) => {
			if (index > 0) {
				el.remove()
			}
		})
		//创建并添加到body下用于容纳存放第二级数据小盒子的盒子
		var box = document.createElement('div')
		box.className = 'box'
		document.body.appendChild(box)
		//对第二级的数组进行遍历
		el.next.forEach((el, index2) => {
			//创建容纳第二级数据的小盒子
			var btn = document.createElement('div')
			btn.className = 'btn'
			btn.innerHTML = el.name
			box.appendChild(btn)
			//给第二级每个小盒子添加点击事件
			btn.onclick = function() {
				//排它设计 清除第二级的三级盒子
				var boxs = document.querySelectorAll('.box')
				boxs.forEach((el, index) => {
					if (index > 1) {
						el.remove()
					}
				})
				//创建并添加到body下用于容纳存放第三级数据小盒子的盒子
                var box = document.createElement('div')
				box.className = 'box'
				document.body.appendChild(box)
				//对第三级的数组进行遍历
				el.next.forEach((el, index3) => {
					//创建容纳第三级数据的小盒子
					var btn = document.createElement('div')
					btn.className = 'btn'
					btn.innerHTML = el
					box.appendChild(btn)
					//打印点击的具体站点和其对应下标
					btn.onclick = function() {
						console.log(data[index1].name, 
									data[index1].next[index2].name, 
									data[index1].next[index2].next[index3]);
						console.log('第' + index1 + '个省', 
									'第' + index2 + '个市', 
									'第' + index3 + '个站')
					}
				})
			}
		})
	}
})
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值