表格案例
渲染表格——字符串
反引号``内添加可换行字符串,用${}引入变量
//动态渲染表格1
var table = document.querySelector('table')
var str = `
<tr>
<th>编号</th>
<th>姓名</th>
<th>年龄</th>
<th>城市</th>
</tr>
`
function bindHtml() {
for(var i = 0; i < data.length; i++) {
str += `
<tr>
<td>${data[i].id}</td>
<td>${data[i].name}</td>
<td>${data[i].age}</td>
<td>${data[i].city}</td>
</tr>
`
}
table.innerHTML = str
}
bindHtml()
创建+添加
Object.keys(对象名)——对象的属性名形成的数组
document.createElement('tr')——创建tr
myTr.appendChild(myTd)——把td加到tr中
function bindHtml() {
// 根据 数据, 创建 表格内容
for (var i = 0; i < data.length; i++) {
// 1. 创建一个 tr 标签, 后续用于追加到 table
var myTr = document.createElement('tr')
// console.log(data[i])
// console.log(Object.keys(data[i]))
// 获取到 对象内部 有 多少个属性
var dataKeys = Object.keys(data[i])
// 根据 对象内部有多少个属性, 决定创建多少个 td
for (var k = 0; k < dataKeys.length; k++) {
// 创建 td
var myTd = document.createElement('td')
// console.log(dataKeys[k]) // 获取到 对象中的 所有属性名
// console.log(data[i]) // 获取到 每一个对象
/**
* data[i] === {id: 1, name: '张三', age: 25, city: '北京'}
* dataKeys[k] === 他的值就是上述对象的某一个 属性名
*
* 通过 属性名 是能够获取到 对象中的 属性值
*
* 语法: 对象[属性名]
* 根据语法并结合当前 案例: data[i][dataKeys[k]]
*/
// myTd.innerText = data[i][dataKeys[k]]
var obj = data[i] // 获取到 对象
var key = dataKeys[k] // 获取到 属性名
myTd.innerText = obj[key]
// 将 处理好的 td 追加到 tr 中
myTr.appendChild(myTd)
}
// console.log(myTr)
// 将创建出来的 tr 追加到 table 中
var tbody = document.querySelector('tbody')
tbody.appendChild(myTr)
}
}
bindHtml()
全选
一个新的主流的开发思想
数据驱动视图,即我们的任何操作不应该直接更改 真实 DOM 节点 (不应该直接修改标签),而是做一些操作的时候, 完成后直接修改数据, 然后用新数据重新渲染页面。
- 方法一(不推荐)
var data = [
{
status: true,
id: 1,
name: '张三',
age: 25,
city: '北京',
},
{
status: false,
id: 2,
name: '李四',
age: 30,
city: '上海',
},
{
status: true,
id: 3,
name: '王五',
age: 22,
city: '杭州',
}
]
// 页面打开时调用渲染函数
bindHtml()
// 创建一个渲染函数
function bindHtml() {
// 在页面渲染前, 先清空之前的页面
document.querySelector('table').innerHTML = ""
// 在页面渲染前, 先计算出有多少个数据被选中, 用于决定是否选中全选
var checkedNum = 0 // 存储当前数据中 有多少个数据被选中了
for (var q = 0; q < data.length; q++) {
// if (data[q].status === true) {
// checkedNum++
// }
data[q].status && checkedNum++ // 如果当前对象的status属性为 true, 那么代表当前对象被选中了, 所以计数器 + 1
}
// ==================创建表头内容开始==================
var headerArr = ['选择', '编号', '姓名', '年龄', '城市']
var headerTr = document.createElement('tr') // 当前tr只需要创建一个, 内部放一些 th 也就是 表头
for (var j = 0; j < headerArr.length; j++) { // 根据数据批量创建表头
var headerTh = document.createElement('th') // 创建一个表头
if (j === 0) { // 如果 j === 0, 代表循环第一次执行, 那么这个单元格的内容, 应该是一个多选框
// headerTh.innerHTML = '<input type="checkbox" class="check_all" checked >'
var inp = document.createElement('input') // 创建一个 input 标签, 注意: 默认为 输入框
inp.type = 'checkbox' // 如果没有这一行那么创建的默认是一个 单行文本输入框
inp.className = 'check_all' // 因为一会需要添加事件, 所以这里提前给这个选择框添加一个类名标识
inp.checked = checkedNum === data.length // 根据 现有选中的数据数量和总数据数量对比, 如果相同代表所有数据被选中, 那么选中全选按钮
headerTh.appendChild(inp) // 将 多选框 添加到 th 中
} else {
headerTh.innerHTML = headerArr[j] // 给表头单元格赋值一个文本
}
headerTr.appendChild(headerTh) // 将 th 单元格 放到 tr 单元行 内
}
document.querySelector('table').appendChild(headerTr)
// ==================创建表头内容结束==================
// ==================创建表格内容开始==================
for (var i = 0; i < data.length; i++) {
var myTr = document.createElement('tr')
var dataKeys = Object.keys(data[i])
for (var k = 0; k < dataKeys.length; k++) {
var myTd = document.createElement('td')
// 如果 展示的内容是一个 布尔值, 那么应该展示一个多选框
if (data[i][dataKeys[k]] === true || data[i][dataKeys[k]] === false) {
var inpItems = document.createElement('input') // 创建一个 input 标签, 注意: 默认为单行输入框
inpItems.type = 'checkbox' // 更改类型为 多选框
inpItems.className = 'check_item' // 给多选框添加类名, 因为一会需要添加事件
inpItems.checked = data[i][dataKeys[k]] // 给多选框 添加一个默认的选中状态, 需要根据数据提供的来展示
myTd.appendChild(inpItems) // 将 多选框 添加到 td 单元格中
} else {
myTd.innerText = data[i][dataKeys[k]] // 如果 展示的内容不是 布尔值, 那么正常展示文本
}
myTr.appendChild(myTd)
}
document.querySelector('table').appendChild(myTr)
}
// ==================创建表格内容结束==================
// ==================全选功能开始==================
// 一个不太好的方式 重新获取 全选按钮, 将来有更好的方式
var checkAll = document.querySelector('.check_all')
checkAll.onclick = function (e) {
// console.log(checkAll)
// console.log(e.target)
// 1. 修改数据
for (var i = 0; i < data.length; i++) {
data[i].status = e.target.checked
}
console.log(data)
// 2. 重新渲染页面
bindHtml()
}
// ==================全选功能结束==================
}
事件冒泡
当你点击了一个元素的时候, 相当于触发了这个元素的点击事件,当一个元素的点击事件被触发的时候, 那么按照JS中事件冒泡的特性,会将这个事件的触发也传递给自己的父级
冒泡会从 点击的元素开始, 一直到页面最顶层的元素,哪怕你的元素没有绑定点击事件, 也会触发事件冒泡
事件委托
事件委托就是利用事件冒泡的原理,将所有子元素的一个事件(点击事件), 委托给共同的父级
- 方法二(事件委托)
var data = [
{
status: true,
id: 1,
name: '张三',
age: 25,
city: '北京',
},
{
status: false,
id: 2,
name: '李四',
age: 30,
city: '上海',
},
{
status: true,
id: 3,
name: '王五',
age: 22,
city: '杭州',
}
]
// 页面打开时调用渲染函数
bindHtml()
// 创建一个渲染函数
function bindHtml() {
// 在页面渲染前, 先清空之前的页面
document.querySelector('table').innerHTML = ""
// 在页面渲染前, 先计算出有多少个数据被选中, 用于决定是否选中全选
var checkedNum = 0 // 存储当前数据中 有多少个数据被选中了
for (var q = 0; q < data.length; q++) {
// if (data[q].status === true) {
// checkedNum++
// }
data[q].status && checkedNum++ // 如果当前对象的status属性为 true, 那么代表当前对象被选中了, 所以计数器 + 1
}
// ==================创建表头内容开始==================
var headerArr = ['选择', '编号', '姓名', '年龄', '城市']
var headerTr = document.createElement('tr') // 当前tr只需要创建一个, 内部放一些 th 也就是 表头
for (var j = 0; j < headerArr.length; j++) { // 根据数据批量创建表头
var headerTh = document.createElement('th') // 创建一个表头
if (j === 0) { // 如果 j === 0, 代表循环第一次执行, 那么这个单元格的内容, 应该是一个多选框
// headerTh.innerHTML = '<input type="checkbox" class="check_all" checked >'
var inp = document.createElement('input') // 创建一个 input 标签, 注意: 默认为 输入框
inp.type = 'checkbox' // 如果没有这一行那么创建的默认是一个 单行文本输入框
inp.className = 'check_all' // 因为一会需要添加事件, 所以这里提前给这个选择框添加一个类名标识
inp.checked = checkedNum === data.length // 根据 现有选中的数据数量和总数据数量对比, 如果相同代表所有数据被选中, 那么选中全选按钮
headerTh.appendChild(inp) // 将 多选框 添加到 th 中
} else {
headerTh.innerHTML = headerArr[j] // 给表头单元格赋值一个文本
}
headerTr.appendChild(headerTh) // 将 th 单元格 放到 tr 单元行 内
}
document.querySelector('table').appendChild(headerTr)
// ==================创建表头内容结束==================
// ==================创建表格内容开始==================
for (var i = 0; i < data.length; i++) {
var myTr = document.createElement('tr')
var dataKeys = Object.keys(data[i])
for (var k = 0; k < dataKeys.length; k++) {
var myTd = document.createElement('td')
// 如果 展示的内容是一个 布尔值, 那么应该展示一个多选框
if (data[i][dataKeys[k]] === true || data[i][dataKeys[k]] === false) {
var inpItems = document.createElement('input') // 创建一个 input 标签, 注意: 默认为单行输入框
inpItems.type = 'checkbox' // 更改类型为 多选框
inpItems.className = 'check_item' // 给多选框添加类名, 因为一会需要添加事件
inpItems.checked = data[i][dataKeys[k]] // 给多选框 添加一个默认的选中状态, 需要根据数据提供的来展示
inpItems.dataset.id = i + 1 // 用于给 标签 添加一个 标识, 能够知道将来点的是那个
myTd.appendChild(inpItems)
// 将 多选框 添加到 td 单元格中
} else {
myTd.innerText = data[i][dataKeys[k]] // 如果 展示的内容不是 布尔值, 那么正常展示文本
}
myTr.appendChild(myTd)
}
document.querySelector('table').appendChild(myTr)
}
// ==================创建表格内容结束==================
}
// ==================全选功能 (事件委托) 开始==================
var myTable = document.querySelector('table')
myTable.onclick = function (e) {
if (e.target.className === 'check_all') {
// 1. 修改数据
for (var i = 0; i < data.length; i++) {
data[i].status = e.target.checked
}
// 2. 重新渲染页面
bindHtml()
}
if (e.target.className === 'check_item') {
// 1. 修改数据
// console.log(e.target.dataset.id - 0) // 因为 我们获取到的 数据被 浏览器转换为 字符串了, 然后自己数据中是数字类型, 所以需要 - 0
for (var k = 0; k < data.length; k++) {
if (e.target.dataset.id - 0 === data[k].id) {
// data[k].status = !data[k].status
data[k].status = e.target.checked
}
}
// 2. 重新渲染页面
bindHtml()
}
}
排序
// ==================排序功能开始==================
var sortBtn = document.querySelector('#sort_btn')
var num = 0
sortBtn.onclick = function () {
num++ // 每次点击的时候 修改计数器的数字
if (num === 1) { // 1. 第一次点击 按照 年龄的从小到大
data.sort(function (a, b) {return a.age - b.age})
} else if (num === 2) { // 2. 第二次点击 按照 年龄的从大到小
data.sort(function (a, b) {return b.age - a.age})
} else { // 3. 第三次点击 恢复默认排序(按照ID从小到大)
data.sort(function (a, b) {return a.id - b.id})
num = 0 // 清零计数器, 下次可以重新执行逻辑
}
// 上述的 if 语句内 处理完数据后, 重新渲染页面
bindHtml()
}
// ==================排序功能结束==================
新增
// ==================新增功能开始==================
// 1. 点击 "新增按钮" 打开 遮罩层 和 信息框
var addBtn = document.querySelector('#add_btn')
var overlay = document.querySelector('.overlay')
var addUserBox = document.querySelector('.add_user_box')
addBtn.onclick = function () {
overlay.classList.remove('close')
addUserBox.classList.remove('close')
}
// 2. 点击 "新增用户按钮" 收集用户输入的信息, 然后创建一个对象, 追加到原数组的末尾, 最后重新渲染页面
var addUserBtn = document.querySelector('.add_user_btn')
addUserBtn.onclick = function () {
// 2.1 获取到用户输入的信息
var nameEl = document.querySelector('.username')
var ageEl = document.querySelector('.userage')
var cityEl = document.querySelector('.usercity')
var nameValue = nameEl.value
var ageValue = ageEl.value
var cityValue = cityEl.value
// 2.2 安全校验 (非空校验, 规则校验/正则校验)
if (nameValue === '' || ageValue === '' || cityValue === '') return alert('您的输入框有一个为空, 请补全输入框')
// 2.3 如果代码能够正常执行到这里, 说明输入框的的内容不是空的, 所以可以组装一个对象, 然后追加到原数组的末尾
var obj = {
status: false,
id: data.length + 1,
name: nameValue,
age: ageValue - 0,
city: cityValue,
}
data.push(obj)
// 2.4 调用渲染函数
bindHtml()
// 2.5 清空弹框数据
nameEl.value = ''
ageEl.value = ''
cityEl.value = ''
// 2.6 关闭弹框
closeBoxFn()
}
// 3. 点击 "取消按钮" 关闭 遮罩层和信息框
var closeBoxBtn = document.querySelector('.close_box_btn')
closeBoxBtn.onclick = closeBoxFn
function closeBoxFn () {
overlay.classList.add('close')
addUserBox.classList.add('close')
}
// ==================新增功能结束==================
获取平均年龄
// ==================获取平均年龄开始==================
var getAge = document.querySelector('#get_age')
getAge.onclick = function () {
// 1. 获取到年龄的总和
var sum = 0
for (var i = 0; i < data.length; i++) {
sum += data[i].age
}
// 2. 总和 / 总数量 === 年龄的平均值
sum = sum / data.length
// 3. 提示给用户年龄的平均值
alert(sum.toFixed(1))
}
// ==================获取平均年龄结束==================
本地存储
var data = JSON.parse(window.localStorage.getItem('data')) || [
{
status: true,
id: 1,
name: '张三',
age: 25,
city: '北京',
},
{
status: false,
id: 2,
name: '李四',
age: 30,
city: '上海',
},
{
status: true,
id: 3,
name: '王五',
age: 22,
city: '杭州',
}
]
//渲染函数中
window.localStorage.setItem('data', JSON.stringify(data))
最终版
var oldData = [
{
status: false,
id: 1,
name: '张三',
age: 25,
city: '北京',
},
{
status: false,
id: 2,
name: '李四',
age: 30,
city: '上海',
},
{
status: false,
id: 3,
name: '王五',
age: 22,
city: '杭州',
}
]
if(!window.localStorage.getItem('arr')) {
window.localStorage.setItem('arr', JSON.stringify(oldData))
}
var data = JSON.parse(localStorage.getItem('arr'))
var table = document.querySelector('table')
function bindHtml() {
document.querySelector('table').innerHTML = ''
var sum = 0
for (var z = 0; z < data.length; z++) {
data[z].status && sum++
}
//表头
var headerArr = ['选择', '编号', '姓名', '年龄', '城市']
var headerTr = document.createElement('tr')
for(var i = 0; i < headerArr.length; i++) {
var headerTh = document.createElement('th')
if (i === 0) {
var inp = document.createElement('input')
inp.className = 'check_all'
inp.type ='checkbox'
inp.checked = sum === data.length
headerTh.appendChild(inp)
} else {
headerTh.innerHTML = headerArr[i]
}
headerTr.appendChild(headerTh)
}
table.appendChild(headerTr)
//表格
for (var j = 0; j < data.length; j++) {
var myTr = document.createElement('tr')
var dataKeys = Object.keys(data[j])
for (var k = 0; k < dataKeys.length; k++) {
var myTd = document.createElement('td')
if (data[j][dataKeys[k]] === true || data[j][dataKeys[k]] === false) {
var inp2 = document.createElement('input')
inp2.className = 'check_item'
inp2.type = 'checkbox'
inp2.dataset.id = j + 1
inp2.checked = data[j][dataKeys[k]]
myTd.appendChild(inp2)
} else {
myTd.innerText = data[j][dataKeys[k]]
}
myTr.appendChild(myTd)
}
table.appendChild(myTr)
}
window.localStorage.setItem('arr', JSON.stringify(data))
}
bindHtml()
//全选
table.onclick = function (e) {
if (e.target.className === 'check_all') {
for (var a = 0; a < data.length; a++) {
data[a].status = e.target.checked
}
bindHtml()
}
if(e.target.className === 'check_item') {
for (var b = 0; b < data.length; b++) {
if (e.target.dataset.id - 0 === data[b].id) {
data[b].status = e.target.checked
}
}
bindHtml()
}
}
//排序
var sortBtn = document.querySelector('.sort_btn')
var sum2 = 0
sortBtn.onclick = function () {
sum2++
if (sum2 === 1) {
data.sort(function (a, b) {
return a.age - b.age
})
} else if (sum2 === 2) {
data.sort(function (a, b) {
return b.age - a.age
})
} else {
data.sort(function (a, b) {
return a.id - b.id
})
sum2 = 0
}
bindHtml()
}
//新增
var AddBtn = document.querySelector('.add_btn')
var outer = document.querySelector('.outer')
var cancelBtn = document.querySelector('.cancel_btn')
var addingBtn = document.querySelector('.adding_btn')
AddBtn.onclick = function () {
outer.classList.remove('close')
}
cancelBtn.onclick = function () {
outer.classList.add('close')
}
addingBtn.onclick = function () {
var nameEl = document.querySelector('.username')
var ageEl = document.querySelector('.userage')
var cityEl = document.querySelector('.usercity')
var nameValue = nameEl.value
var ageValue = ageEl.value
var cityValue = cityEl.value
if (nameValue === '' || ageValue === '' || cityValue === '') return alert('请您检查并补全输入框')
var obj = {
status: false,
id: data.length + 1,
name: nameValue,
age: ageValue - 0,
city: cityValue,
}
data.push(obj)
bindHtml()
nameEl.value = ''
ageEl.value = ''
cityEl.value = ''
outer.classList.add('close')
}
//平均数
var ageBtn = document.querySelector('.age_btn')
var backBtn = document.querySelector('.back_btn')
var outer2 = document.querySelector('.outer2')
var span = document.querySelector('span')
ageBtn.onclick = function () {
outer2.classList.remove('close')
var average = 0
for (var c = 0; c < data.length; c++) {
average += data[c].age
}
span.innerText = (average / data.length).toFixed(2)
}
backBtn.onclick = function () {
outer2.classList.add('close')
}
//删除
// ==================删除功能(事件委托)开始==================
if (e.target.className === "del_btn") {
// var res = window.confirm('您确定删除吗?')
// console.log('现在要删除一个内容', res)
if (!confirm('您确定删除吗?')) return
// 改变数据
console.log('如果代码能够执行到这里, 说明需要删除', e.target.dataset.id)
// data.splice(0, 1)
// data.splice(1, 1)
// data.splice(2, 1)
data.splice(e.target.dataset.id - 1, 1)
// 重新渲染页面
bindHtml()
}
// ==================删除功能(事件委托)结束==================