一、递归
简单来说就是再函数之中再一次调用了函数自己,迟早有一天会停下来
- 何时:专门用于遍历层级不明确的情况 - DOM树和数据(children只能找到儿子层,找不到孙子层)
- 如何使用:
function 函数名(root){
第一层要做什么直接做
判断有没有下一层,如果有下一层则再次调用此方法,只不过传入的实参是自己的下一层
}
函数名(实际的根)
- 算法:深度优先!优先遍历当前节点的子节点,子节点遍历完毕才会跳到兄弟节点
- 缺陷:不要过多使用,性能相对较差,同时开启大量的函数调用,浪费内存
- 递归 vs 纯循环
- 递归:优点:简单易用
缺点:性能低 - 纯循环:优点:几乎不占用性能
缺点:难
- 递归:优点:简单易用
二、绑定事件:3种方式
- 在HTML上书写事件属性
<elem on事件名="函数名(实参)"></elem>
缺点:
- 不符合内容与样式与行为的分离原则
- 无法动态绑定,一次只能绑定一个元素
- 不支持绑定多个函数对象
- 在js中使用事件处理函数属性
elem.on事件名=function(){操作}
优点:
- 符合内容与样式与行为的分离原则
- 动态绑定,一次能绑定多个元素
缺点: - 不支持绑定多个函数对象
- 在js中使用事件API:如果不用考虑老IE,他也不错
- 主流:elem.addEventListener("事件名",callback);
- 老IE:elem.attachEvent("on事件名",callback);
- 兼容:
if(elem.addEventListener){
elem.addEventListener("事件名",callback);
}else{
elem.attachEvent("on事件名",callback);
}
<script>
// 主流浏览器
btn.addEventListener('click',function(){
console.log(1);
})
// 老IE(8-)
btn.attachEvent('onclick',function(){
console.log(1);
})
// 兼容写法
if (btn.addEventListener) {
btn.addEventListener('click',function(){
console.log(1);
})
} else {
btn.attachEvent('onclick',function(){
console.log(1);
})
}
</script>
优点:
- 符合内容与样式与行为的分离原则
- 动态绑定
- 支持绑定多个函数对象
缺点:有兼容性问题
三、select&option只有他们可以简化创建元素&上树
select.add(new Option("innerHTML","value"));
四、练习
// 递归-DOM 给#ul的孩子设置边框
function getArea(root) {
for(var i = 0; i < root.length; i++) {
root[i].style.border = "1px solid #fc1"
if(root[i].children.length > 0) {
getArea(root[i].children)
}
}
}
getArea(ul.children)
<script>
// 递归 - 数据
var json=[{"name":"杨俊杰","children":[{"name":"杨俊"},{"name":"杨杰"}]},
{"name":"冯小龙"},
{"name":"胡畔","children":[{"name":"胡田","children":[{"name":"胡半"}]}]},
{"name":"袍哥","children":[{"name":"钟哥","children":[{"name":"小钟","children":[{"name":"钟种"}]}]}]}
];
// 拿到所有人的姓名
function getName(root) {
root.forEach(obj=>{
console.log(obj.name);
if(obj.children) {//没有就是undefined
getName(obj.children)
}
})
}
getName(json)
</script>
<script>
// 纯循环 - 设置#ul和所有它孩子的边框
function getArea(root) {
//
var org = ul
while(1) {
root.style.border = "1px solid #fc1"
if(root.firstElementChild) {
root = root.firstElementChild
} else if (root.nextElementSibling) {
root = root.nextElementSibling
} else {
while(!root.parentNode.nextElementSibling&&root!=org.lastElementChild) {
root = root.parentNode
}
root = root.parentNode.nextElementSibling
if(root == org.lastElementChild) {
root.style.border = "1px solid #fc1"
break
}
}
}
}
getArea(ul)
</script>
<select name="provs">
<option>—请选择—</option>
<option>北京市</option>
<option>天津市</option>
<option>河北省</option>
<option>重庆省</option>
</select>
<select name="cities" class="hide">
</select>
<script>
// 二级联动
var cities=[//JSON:javascript object notation数据
[], /*0号下标没有元素*/
[{"name":'东城区',"value":101},
{"name":'西城区',"value":102},
{"name":'海淀区',"value":103},
{"name":'朝阳区',"value":104},],
[{"name":'河东区',"value":201},
{"name":'河西区',"value":202},
{"name":'南开区',"value":203}],
[{"name":'石家庄市',"value":301},
{"name":'廊坊市',"value":302},
{"name":'保定市',"value":303},
{"name":'唐山市',"value":304},
{"name":'秦皇岛市',"value":305}],
[{"name":'渝中区',"value":401},
{"name":'九龙坡区',"value":402},
{"name":'沙坪坝区',"value":403},
{"name":'渝北区',"value":404},
{"name":'江北区',"value":405}]
];
// 拿到两个select
var sels = document.querySelectorAll('select')
// 第一个select选中项改变时候
sels[0].onchange = function(){
// 拿到当前项的下标
var i = this.selectedIndex
// 判断是否为为请选择项 如果是
if(i > 0){
// 清除第二个li里面所有的内容
sels[1].innerHTML = ''
// 让第二个select显示
sels[1].className = ''
// 在数组中对应下标的内容做遍历
cities[i].forEach(obj=>{
/* // 创建标签
var opt = document.createElement('option')
// 设置属性和内容
opt.innerHTML = obj.name
opt.value = obj.value
// 上树
sels[1].appendChild(opt) */
// 简写以上内容
sels[1].add(new Option(obj.name,obj.value))
})
} else {
// 清除第二个li里面所有的内容
sels[1].innerHTML = ''
// 让第二个select隐藏
sels[1].className = 'hide'
}
}
</script>
<!--根据数据渲染多级联动-->
<div id="category">
</div>
<script type="text/javascript">
var categories=[
{"id":10,"name":'男装',"children":[
{"id":101,"name":'正装'},
{"id":102,"name":'T恤'},
{"id":103,"name":'裤衩'}
]},
{"id":20,"name":'女装',"children":[
{"id":201,"name":'短裙'},
{"id":202,"name":'连衣裙'},
{"id":203,"name":'裤子',"children":[
{"id":2031,"name":'长裤'},
{"id":2031,"name":'九分裤'},
{"id":2031,"name":'七分裤'}
]},
]},
{"id":30,"name":'童装',"children":[
{"id":301,"name":'帽子'},
{"id":302,"name":'套装',"children":[
{"id":3021,"name":"0-3岁"},
{"id":3021,"name":"3-6岁","children":[
{"id":2031,"name":'长裤'},
{"id":2031,"name":'九分裤'},
{"id":2031,"name":'七分裤',"children":[
{"id":101,"name":'正装'},
{"id":102,"name":'T恤'},
{"id":103,"name":'裤衩'}
]}
]},
{"id":3021,"name":"6-9岁"},
{"id":3021,"name":"9-12岁"}
]},
{"id":303,"name":'手套'}
]}
];
// 创建函数
function getSel(arr) {
// 创建一个select标签
var sel = document.createElement('select')
// 向select里面添加一个请选择option标签
sel.add(new Option('-请选择-',-1))
// 遍历数组并且设置option
arr.forEach(obj=>{sel.add(new Option(obj.name,obj.id))})
// 当select里面的内容发生改变得到时候
sel.onchange = function(){
// 拿到当前下标
var i = this.selectedIndex
// 循环判断当前select有没有下一个兄弟 有就删除
while(sel.nextElementSibling) {
sel.nextElementSibling.remove()
}
// 判断是否为请选择项
if (i > 0) {
// 判断是否有children
if (arr[i-1].children) {
// 如果有再次调用函数
getSel(arr[i-1].children)
}
}
}
// 上树
category.appendChild(sel)
}
getSel(categories)
</script>
<script type="text/javascript">
var json = [
{ "name": "杨俊杰", "children": [{ "name": "杨俊" }, { "name": "杨杰" }] },
{ "name": "冯小龙" },
{ "name": "胡畔", "children": [{ "name": "胡田", "children": [{ "name": "胡半" }] }] },
{ "name": "袍哥", "children": [{ "name": "钟哥", "children": [{ "name": "小钟", "children": [{ "name": "钟种" }] }] }] }
];
// 创建函数
function getUl(arr,parent) {
// 创建ul
var ul = document.createElement('ul')
// 遍历数组
arr.forEach(obj=>{
// 创建li
var li = document.createElement('li')
// 设置li的内容
li.innerHTML = obj.name
// 上树
ul.appendChild(li)
// 判断对象是否有children
if (obj.children) {
// 再次调用函数
getUl(obj.children,li)
}
})
// 上树
parent.appendChild(ul)
}
getUl(json,bd)
</script>
<div id="data1"></div>
<script type="text/javascript">
var data = [ { "id": 1001, "name": '可口可乐', "price": 2.5, "count": 3000 }, { "id": 1003, "name": '百事可乐', "price": 2.5, "count": 5000 }, { "id": 1011, "name": '非常可乐', "price": 2.3, "count": 1000 }, { "id": 1012, "name": '天府可乐', "price": 2.3, "count": 1000 }, { "id": 1013, "name": '地府可乐', "price": 2.3, "count": 1000 }, { "id": 1014, "name": '阳间可乐', "price": 2.3, "count": 1000 }, { "id": 1015, "name": '阴间可乐', "price": 2.3, "count": 1000 }, ];
//根据数据生成一个表格
// 创建一个table
var table = document.createElement('table')
// 生成表头
// 创建数组
var arr = ['序号','名称','价格','数量','操作']
// 创建行
var tr = document.createElement('tr')
// 遍历数组
arr.forEach(val=>{
// 创建列
var td = document.createElement('td')
// 设置每一列的内容
td.innerHTML = val
// 上树
tr.appendChild(td)
})
// 上树
table.appendChild(tr)
// 表体
// 遍历
data.forEach(obj=>{
// 创建行
var tr = document.createElement('tr')
// 遍历对象
for(var i in obj) {
// 创建列
var td = document.createElement('td')
// 设置列的内容
td.innerHTML = obj[i]
// 上树
tr.appendChild(td)
}
// 设置操作列
// 创建列
var td = document.createElement('td')
// 设置列的内容
td.innerHTML = '<button onclick = "del(this)">x</button>'
// 上树
tr.appendChild(td)
// 上树
table.appendChild(tr)
})
// 上树
data1.appendChild(table)
// 删除函数
function del(btn) {
var bool = confirm('你确定要删除' + btn.parentNode.parentNode.firstElementChild.nextElementSibling.innerHTML + '吗?')
if (bool) {
btn.parentNode.parentNode.remove()
}
}
</script>