1. 创建对象
javascript
// 对象:对象是属性和方法的集合
// 属性:事物的特征, 常用名词 眼睛,耳朵
// 方法:事物的行为, 可以谈恋爱,跑步
1.1 字面量
javascript
// 1. 字面量 ==> 看到就知道是什么类型的数据 [] {} /xxx/
// const obj = {} // 创建一个空对象
const obj = {
name:'张三丰',
age:108,
// sayHi:function(){}, 可以简写
sayHi(){
console.log('hello~~')
}
}
console.log(obj)
// 2. 获取对象的属性
// 2.1 对象.属性
console.log(obj.name)
// 2.2 对象['属性']
console.log(obj['age'])
// console.log(obj[age]) // Error ==> 不加引号,age表示一个变量
// 3. 调用对象中的方法
// 对象.方法()
obj.sayHi()
1.2 利用new Object()创建对象
javascript
const obj = new Object()
// const obj2 = {}
// console.log(obj === obj2)
// 数组对象,不能直接比较,不等的,地址都是不同
obj.name = '丰丰'
obj.age = 108
obj.sayHi = function(){
console.log('Hi~~')
}
console.log(obj)
const p = new Object({name:'杰伦', age: 18})
console.log(p)
// 语法糖
const obj = {} // const obj = new Object()
const arr = [] // const arr = new Array()
1.3 利用构造函数创建对象
- 构造函数,相当于是一个模板,通过这个构造函数,可以创建出一系列具有相同属性和方法的对象
- 实例化:通过构造函数,创建对象的过程叫做实例化 ==> new一个对象的过程
- 实例:具体的实际的例子,实际的那个对象 实例/实例对象
javascript
function 构造函数名(形参1,形参2,形参3) { // 构造函数的形参与对象的普通属性是一般一致的
this.属性名1 = 形参1;
this.属性名2 = 形参2; // 属性的值,一般是通过同名的形参来赋值的
this.属性名3 = 形参3;
this.方法名 = function(){
};
}
// 调用
const obj = new 构造函数名(实参1,实参2,实参3)
// 简记
function 构造函数名() {
this.属性 = 值; // 当前的这个对象的
this.方法 = function() {}
}
new 构造函数名();
// 注意:
// 1. 构造函数名字首字母要大写
// 2. 构造函数里 属性和方法前面必须添加 this
// 3. 构造函数不需要 return 就可以返回结果
// 4. 我们调用构造函数 必须使用 new
javascript
function Person(name, age, gender){
// this 这个对象
// 属性名一般和传入过来的形参同名
this.name = name
this.age = age
this.gender = gender
// 如果构造函数方法要传参数,写在这里
this.sayHi = function(msg){
console.log(msg)
}
}
const p = new Person('杰伦', 18, 'male')
console.log(p)
// 获取属性
console.log(p.age)
// 调用方法
p.sayHi('hello js')
// const obj = {}
const obj = new Object()
console.log(obj)
1.3.1 练习
javascript
function Goods(name, price, count){
this.name = name
this.price = price
this.count = count
}
const mi = new Goods('小米', 1999, 20)
const hw = new Goods('华为', 3999, 59)
const vivo = new Goods('vivo', 1888, 100)
console.log(mi, hw, vivo)
// 规则4:所有对象的隐式原型(__proto__,指向它的构造函数的显示原型prototype)
console.log(mi.__proto__ === Goods.prototype)
console.log(hw.__proto__ === Goods.prototype)
1.4 构造函数的执行过程-new的执行过程
/* ==================== 面试题 ===================== */ new的执行过程?构造函数的执行过程?
- 创建一个空对象
- 让this指向这个空对象
- 执行构造函数里面的代码,给这个空对象添加属性和方法
- 返回这个对象 return this
/* ==================== end ===================== */
javascript
// new一个对象的过程或者说构造函数的执行过程
function Person(name, age, gender){
// 1. 创建一个空对象
// 2. 让this指向这个空对象
// const this = {}
// 3. 执行构造函数里面的代码,给这个空对象添加属性和方法
this.name = name
this.age = age
this.gender = gender
this.sayHi = function(msg){
console.log(msg)
}
// return {name, age, sayHi}
// 4. return this 返回这个对象
}
const p = new Person('guoguo', 18, 'female')
console.log(p)
/* ==================== 面试题 ===================== */
// new的执行过程?构造函数的执行过程?
// 1. 创建一个空对象
// 2. 让this指向这个空对象
// 3. 执行构造函数里面的代码,给这个空对象添加属性和方法
// 4. 返回这个对象 return this
/* ==================== end ===================== */
1.5 实例-静态
1.5.1 实例成员
javascript
function Person(name, age, gender){
this.name = name
this.age = age
this.gender = gender
this.sayHi = function(msg){
console.log(msg)
}
}
// 实例:通过构造函数创建的对象叫做实例对象 => 实例
const p = new Person('平平', 18, 'male')
console.log(p)
// 实例成员:实例对象的属性和方法
// 实例成员 ==> 通过实例对象去访问
console.log(p.name)
p.sayHi('123')
1.5.2 静态成员
javascript
// 静态成员:在构造函数 本身 上添加的属性和方法
function Person(name, age, gender){
this.name = name
this.age = age
this.gender = gender
this.sayHi = function(msg){
console.log(msg)
}
}
// 静态属性
Person.eyes = 2
// 静态方法
Person.walk = function(){
console.log('人都会走路')
}
// 静态成员 => 通过构造函数本身来访问的
console.dir(Person)
// eg.例子
// 静态方法
Array.from()
Array.isArray()
console.log(Array.isArray([1, 2, 3])) // true 是数组
// 实例方法
const arr = [1, 2, 3]
// 实例方法
arr.forEach()
arr.map()
arr.filter()
arr.push()
1.5.3 包装类型
js底层,基本数据类型,也会包装成了复杂数据类型,这个时候就可以使用一些属性和方法了
javascript
// 基本数据类型 7 个 Symbol BigInt Number String Boolean undefined null
// 引用类型 Object ==> Function Array RegExp Date Error
// 按理说,只有对象引用类型才有属性和方法
const str = 'andy'
console.log(str.length)
// const str2 = new String('andy')
// console.log(str2)
// console.log(str2.length)
// str2 = null
const num = 10.123
// number的方法 toFixed() 保留小数位数,注意返回值是string
console.log(num.toFixed(2))
console.log(typeof num.toFixed(2))
2. Object的三种静态方法
2.1 for-in遍历对象
obj['key']
===obj.key
, 这两种情况,是找对象中有没有这个key属性名obj[key]
==> 这种情况,key是一个变量,它是字符串形式的,'name', 'age', 'hobby'
javascript
const obj = {name:'霖霖', age:6, hobby:'睡觉'}
// const obj = {name:'霖霖', age:6, hobby:'睡觉', key:'123'}
for(let key in obj){
// 属性名 ==> 键
console.log(key)
// 属性值 ==> 值 重点:[key] => key是一个变量,'name', 'age', 'hobby'
console.log(obj[key])
console.log(obj['key']) // undefined ==> 相当于去找obj中有没有key这样一个属性名
}
// 1. obj['key'] 等效 obj.key , 这两种情况,是找对象中有没有这个key属性名
// 2. obj[key] ==> 这种情况,key是一个变量,它是字符串形式的,'name', 'age', 'hobby'
2.2 Object.keys()-Object.values()
javascript
// 1. Object.keys(obj) 静态方法
// 返回一个对象的所有属性名/键名,得到一个数组
const obj = {name:'霖霖', age:6, hobby:'睡觉'}
const arr = Object.keys(obj)
console.log(arr)
// 2. Object.values(obj)
// 返回一个对象的所有属性值,得到的也是一个数组
const arr2 = Object.values(obj)
console.log(arr2)
2.2.1 eg.练习
javascript
// 属性值拼接 获取对象的所有属性值 Object.values()
const spec = { size: '40cm*40cm', color: '黑色'}
const div = document.querySelector('.box')
// 1. 获取对象的所有属性值
const res = Object.values(spec)
console.log(res)
// 2. 将数组以/分割,转为字符串,放到div中
div.innerHTML = res.join('/')
2.3 Object.assign()
对象的浅拷贝
javascript
// 美 /əˈsaɪn/
// 语法:
// Object.assign(target, ...sources)
// target: 目标对象, 接收源对象属性的对象,也是修改后的返回值
// sources: 一个或多个源对象
const obj = {}
const o = {name:'建国', hobby:'男'}
const res = Object.assign(obj, o)
console.log(res)
// eg2. 合并对象
const o1 = {a:1}
const o2 = {b:2}
const o3 = {c:3}
const res2 = Object.assign(o1, o2, o3)
console.log(res2)
console.log(o1)
console.log(res2 === o1) // true , 返回值就是目标对象!同一个
3. 数组array的方法
3.0 通过MDN学习新方法的步骤
javascript
// 查MDN文档,学习新方法的步骤
// 1. 语法: 先大致了解
// 2. 作用: 看这个方法是干嘛的
// 3. 参数: 熟悉一下参数
// 4. 返回值: 看是否有返回值
// 5. 描述: 注意事项 大致过一下
// 6. 示例代码,测试一下
3.1 arr.reduce()
javascript
// 实例方法: 通过构造函数创建的对象,它调用的方法。
// MDN上 Array.prototype.reduce() ==> reduce 实例方法
// 语法: arr.reduce(callbackFn, initialValue)
// 作用: 对数组里的每个元素都执行一个自定义的reducer函数,将其结果汇总为单个返回值。
// 参数:
// callbackFn : 回调函数 必须 √
// initialValue : 初始值 (可选) √
// callbackFn的参数:
// previousValue : 上一次调用callbackFn的返回值 √
// currentValue : 当前元素 √
// currentIndex : 当前元素的索引 (可选) 不要求
// array : 源数组 (可选) 不要求
// 返回值: 使用reducer回调函数遍历整个数组后的结果
// 注意: 如果有初始值,那么prev第一次执行的时候,就是写的初始值, cur取数组arr[0]
// 如果没有初始值,initValue就是数组的第一个元素 arr[0], cur就依次取第二个元素
const arr = [1, 2, 3]
const res = arr.reduce((pre, cur) => {
return pre + cur
}, 8)
// console.log(res)
const res3 = arr.reduce((pre,cur) => pre + cur, 8)
console.log(res3)
const res1 = arr.reduce(function(pre, cur){
// console.log(pre)
// 1 + 2 ==> 3
// 3 + 3 ==> 6
return pre + cur
})
console.log(res1)
// https://tlias-open-api.boxuegu.com/api1/ev/saveAttendance
3.1.1 员工薪资计算
javascript
// 计算涨薪30%后,一共需要多支出多少 ?
// 语法: arr.reduce(function(上一次返回值, 当前数组元素){}, 初始值)
const arr = [{
name: '张三',
salary: 10000
}, {
name: '李四',
salary: 10000
}, {
name: '王五',
salary: 20000
}]
// 思考,要不要写初始值,计算薪资, 如果不写, pre取的是数组中的第一个元素arr[0]
const res = arr.reduce(function(pre, cur){
return pre + cur.salary * 0.3
}, 0)
console.log(res)
const res2 = arr.reduce((pre,cur) => pre + cur.salary * 0.3, 0 )
// initValue重点:
// 1. 有初始值,pre第一次就取初始值
// 2. 如果没有初始值,pre取的是数组中第一个元素arr[0] !注意,第一个元素取出来可能是一个对象
3.2 arr.find()
返回数组中满足条件的第一个的元素, 否则返回 undefined
javascript
// 1. 语法: arr.find(cbFn)
// 2. 作用: 返回数组中满足条件的第一个的元素, 否则返回 undefined
// 3. 参数:
// cbFn 函数 ==> 注意,这个回调函数,一般需要写上return
// cbFn的参数
// 第一个参数 : item 当前元素
// 第二个参数 : index 索引 (可选)
// 4. 返回值: 数组中第一个满足条件的元素 / undefined
// 5. 注意: 返回的是 【第一个】 满足条件的元素, cbFn中写return!
// 6. 示例
// eg1.
const arr = ['orange', 'skyblue', 'green', 'purple']
const res = arr.find(function(el){
return el === 'purple'
})
console.log(res)
const res2 = arr.find(el => el === 'purple')
// eg2.
// 实际应用 ,从数组对象中,找到满足条件的某一个对象,返回
const arrTemp = [{name:"小米", price:1999}, {name:'iPhone', price:1999},{name:'hw', price:3999}]
const cb = function(el){
return el.price === 1999
}
// 注意:挪出去之后,cb这里不要写成 cb(el) ,加括号表示调用
const res3 = arrTemp.find(cb)
console.log(res3)
// eg3.
const mi = arrTemp.find(function(el){
return el.name === '小米'
})
// 参数可以解构
const mi2 = arrTemp.find(({name}) => name === '小米')
console.log(mi2)
// 1.1 和 filter的区别
// (1) 返回值不一样, filter 返回的是数组 find 返回的是数组元素
// (2) 查找方式不一样,filter是查找所有满足条件的数组元素, find只查找第一个满足条件的,找到就终止查找
3.3 arr.findIndex()
javascript
// 1. 语法:arr.findIndex(cbFn)
// 2. 作用:查找数组中满足条件的第一个元素,如果满足条件,返回索引,如果没有返回-1
// 3. 参数: cbFn ===> return
// cbFn:
// 第一个参数: item 当前数组
// 第二个参数: index 索引 (可选)
// 4. 返回值: 索引号/ 找不到返回-1
const arrTemp = [{name:"小米", price:1999}, {name:'iPhone', price:1999},{name:'hw', price:3999}]
const index = arrTemp.findIndex(function(el){
return el.price === 1999
})
const i = arrTemp.findIndex(el => el.price === 1999)
console.log(index, i)
3.4 arr.every()
every(每一个) 所有数组元素满足条件则返回true,否则返回false
javascript
// 1. 语法:arr.every(cbFn)
// 2. 作用:检测数组内的所有元素是否都满足指定的条件,如果都满足,返回true , 否则false
// 3. 参数: cbFn ===> return
// cbFn:
// 第一个参数: item 当前数组
// 第二个参数: index 索引 (可选)
// 4. 返回值: boolean true / false
// 5. 注意: cbFn 要写return
const arr = [10, 20, 30]
const resBool = arr.every(function(el){
return el >= 10
})
console.log(resBool)
3.5 arr.some()
检测数组中的元素是否满足指定的条件,只要有一个满足,就返回true 、 否则false
javascript
// arr.some(cbFn)
// 作用: 检测数组中的元素是否满足指定的条件,只要有一个满足,就返回true 、 否则false
const res2 = arr.some(function(el){
return el >= 20
})
console.log(res2)
3.6 arr.includes()
作用: 判断数组中是否包含某个元素,如果有, true, 否则false
javascript
const res3 = arr.includes(10)
console.log(res3)
3.7 arr.flat()
拍平数组
javascript
// arr.flat() : 拍平数组
const arr2 = [1, 2, [3, [4]]] // 二维
const res = arr2.flat(4)
// 1. 如果不传参,默认拍平一层 depth默认为1
// 2. 如果传的参数超过数组的深度 3维数组,传了4 ,全部展开,得到的是一位数组
console.log(res)
const arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
arr4.flat(Infinity); // 全部拍平,传入Infinity
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
3.8 arr.fill(val, start, end)
用一个固定值val,填充数组元素,返回一个新数组
javascript
// arr.fill(value, start, end) 用value替换数组中的元素
// [start, end)
const array1 = [1, 2, 3, 4];
// Fill with 0 from position 2 until position 4
console.log(array1.fill(0, 2, 4));
// Expected output: Array [1, 2, 0, 0]
// end不写,直到最后
// Fill with 5 from position 1
console.log(array1.fill(5, 1));
// Expected output: Array [1, 5, 5, 5]
// 如果不写start,end,全部替换
console.log(array1.fill(6));
// Expected output: Array [6, 6, 6, 6]
// 创建一个数组,长度为100,每个元素都是6
let arr = []
for(let i = 0; i < 100; i++){
arr.push(6)
}
console.log(arr)
const newArr = new Array(100).fill(6) // ==> 可以记一下
console.log(newArr)
3.9 arr.sort()
对数组的元素进行排序,并返回数组。
如果前一个大于后一个,把前一个元素冒泡到后面 a > b => a - b > 0 记忆 a-b升序
javascript
// arr.sort() // 对数组的元素进行排序,并返回数组。
const arr = [3, 1, 2, 5, 8, 11, 99]
// 冒泡排序 双重for循环
for(let i = 0; i < arr.length - 1; i++){
for(let j = 0; j < arr.length - 1 - i; j++){
// 判断
if(arr[j] > arr[j+1]){ a > b a - b > 0
// a > b ==> a - b > 0
// let tmp = arr[j]
// arr[j] = arr[j+1]
// arr[j+1] = tmp
;[arr[j], arr[j+1]] = [arr[j+1], arr[j]]
}
}
}
// console.log(arr)
// const res = arr.sort(function(a, b){
// return a - b // 从小到大 升序
// })
const resA1 = arr.sort((a,b) => a - b) // 升序
// const res2 = arr.sort(function(a, b){
// return b - a // 大到小 降序
// })
const resA2 = arr.sort((a,b) => b - a) // 降序
console.log(res2)
eg.全选、反选案例
javascript
// 全选案例
const checkAll = document.querySelector('#checkAll')
const cks = document.querySelectorAll('.ck')
// 1. 全选取消全选
// 点击全选框,下面的小复选框跟随变化
checkAll.addEventListener('click', function(){
// 选中 不选中 checked
// 让每个小复选框的选中状态 等于 全选框的状态
// console.log(checkAll.checked)
// cks.forEach(function(el){
// console.log(this) // 注意这里的this指向了window
// el.checked = this.checked
// })
// 改成箭头函数之后,this指向checkAll
cks.forEach(el => el.checked = this.checked)
})
javascript
// 2. 反选,小复选框全部选中后,大框框也选中
// 2.1. 给每一个小复选框绑定点击事件
// 2.2. 利用数组的every方法,检测小复选框是否都是选中状态,如果都满足,返回true,把这个状态给大复选框
cks.forEach(el => {
el.addEventListener('click', function(){
// 打印一个对象的所有属性和方法
console.dir(cks)
// checkAll.checked = [...cks].every(function(el){
// return el.checked === true
// })
// 伪数组转为真数组 : Array.from / [...likeArr]
checkAll.checked = [...cks].every(el => el.checked === true)
})
})
事件委托的方式
javascript
const tbody = document.querySelector('tbody')
tbody.addEventListener('click', function(e){
// 1. 全选 取消全选
console.log(e.target.id)
if (e.target.id === 'checkAll'){
// console.log(this)
// e.target 就是我们点击的全选框
cks.forEach(el => el.checked = e.target.checked)
}
// 2. 反选,选中下面的小复选框,如果都选中,让全选框也选中
if (e.target.className === 'ck'){
// every 会把数组中每个元素拿出来遍历,看是否满足条件,
// 如果有一个不满足条件,就终止循环了
checkAll.checked = [...cks].every(el => el.checked === true)
}
})
4. 字符串str的方法
4.1 str.split()
使用指定分隔符,将字符串分隔,转为数组
javascript
// 1. str.split('分隔符') => 字符串转为数组
// 将字符串转为数组
const str = 'hello-world-JS'
const arr = str.split('-')
console.log(arr)
// ==> 数组的join('') 相反
// 2. arr.join('') ==> 将数组转为字符串
// 2.1 如果什么都不传, 逗号隔开
const arr2 = [11, 22, 33]
console.log(arr2.join())
// 2.2 传空字符串 ==> 无缝拼接
console.log(arr2.join(''))
// 2.3 分隔符
console.log(arr2.join('-'))
eg.练习str.split()
javascript
const gift = '50g茶叶,清洗球'
// 1. 将字符串转为数组,以,分隔
const arr = gift.split(',')
console.log(arr)
// 2. 将转为的数组,映射成html结构的数组
const resArr = arr.map(function(el){
return `
<span class="tag">【赠品】${el}</span>
`
})
// 箭头函数
const resArr = arr.map(el => `<span class="tag">【赠品】${el}</span>`)
// 3. 将得到的数组转为字符串,渲染到p标签中
document.querySelector('.name').innerHTML = resArr.join('')
4.2 str.substring()
从字符串中截取某个子串出来
- [start, end) 前闭后开, 结束索引号不包含在截取的字符串中
javascript
// 3. str.substring(start, end)
// 从字符串中截取某个子串出来
const str2 = '建国十分爱学习,大家可以向建国同学学习'
const res2 = str2.substring(4, 7)
console.log(res2)
// eg2. 如果不传end,直接取到最后
const res3 = str2.substring(4)
console.log(res3)
4.3 str.startsWidth()
检测是否以某个字符开头,返回布尔值
javascript
// 生存还是毁灭
const str = "To be, or not to be, that is the question."
// 字符串 String 其他方法
// 1. str.startsWith(检测字符,[检测位置])
// 检测是否以某个字符开头,返回布尔值
console.log(str.startsWith('To be'))
console.log(str.startsWith('not to be'))
console.log(str.startsWith('not to be', 10))
4.4 str.includes()
判断一个字符串是否 包含 在另外一个字符串中,返回布尔值
javascript
// str.includes(搜索的字符,[检测位置])
const str = "To be, or not to be, that is the question.";
console.log(str.includes("To be")); // true
console.log(str.includes("question")); // true
console.log(str.includes("nonexistent")); // false
4.5 str.toUpperCase()
字符串转为大写
javascript
const sentence = 'The quick brown fox jumps over the lazy dog.';
console.log(sentence.toUpperCase());
// Expected output: "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG."
4.6 str.toLowerCase()
字符串转小写
javascript
console.log( "ALPHABET".toLowerCase() );
// "alphabet"
4.7 str.indexOf()
检测str中是否包含某个字符串! 如果找到,返回索引号,找不到返回-1
javascript
// 3. str.toUpperCase 字符串转为大写
// 4. str.toLowerCase 转小写
// 5. str.indexOf()
const paragraph = 'The quick brown fox jumps over the lazy dog.';
const search = 'cat';
const indexOfFirst = paragraph.indexOf(search)
console.log(indexOfFirst)
4.8 str.trim()
清除字符串两端的空格,注意中间的不清除
javascript
// str.trim(): 清除字符串两端的空格
// const str = ' teach er '
// console.log(str.trim())
const ipt = document.querySelector('input')
ipt.addEventListener('change', function(){
// // 取用户输入的值
console.log(this.value)
const res = this.value.trim()
console.log(res)
// ==> 应用 : 获取用户输入的值的时候,最好呢,去掉两端的空格
})
5. Number方法
5.1 num.toFixed()
javascript
// 保留小数位数, 四舍五入, 返回的是字符串
// num.toFixed()
const num = 10.863
// 1. 如果不传参数,直接四舍五入为整数(字符串)
console.log(num.toFixed())
// 2. 传参数,保留小数位数
console.log(num.toFixed(2))
console.log(num.toFixed(1))
6. 综合案例
todo01 渲染业务
javascript
const list = document.querySelector('.list')
const render = function(){
const resArr = goodsList.map(el => {
// const {name, price, picture, count, spec, gift} = el
return `
<div class="item">
<img src="https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg" alt="">
<p class="name">称心如意手摇咖啡磨豆机咖啡豆研磨机 <span class="tag">【赠品】10优惠券</span></p>
<p class="spec">白色/10寸</p>
<p class="price">289.90</p>
<p class="count">x2</p>
<p class="sub-total">579.80</p>
</div>
`
})
list.innerHTML = resArr.join('')
}
render()
todo02 渲染-解构
javascript
const list = document.querySelector('.list')
const render = function(){
const resArr = goodsList.map(el => {
// 解构
const {name, price, picture, count, spec, gift} = el
// 2. 内部的数据处理
// 2.1 一行的小计
// 涉及到小数精度的问题,可以扩大倍数,再除以对应的倍数
const total = (price * 100 * count ) / 100
console.log(total)
return `
<div class="item">
<img src="${picture}" alt="">
<p class="name">${name} <span class="tag">【赠品】10优惠券</span></p>
<p class="spec">白色/10寸</p>
<p class="price">${price.toFixed(2)}</p>
<p class="count">x${count}</p>
<p class="sub-total">${total.toFixed(2)}</p>
</div>
`
})
list.innerHTML = resArr.join('')
}
render()
todo03 一些数据的处理
javascript
const list = document.querySelector('.list')
const render = function(){
const resArr = goodsList.map(el => {
const {name, price, picture, count, spec, gift} = el
// 2. 内部的数据处理
// 2.1 一行的小计
// 涉及到小数精度的问题,可以扩大倍数,再除以对应的倍数
const total = (price * 100 * count ) / 100
console.log(total)
// 2.2 spec的文字处理
const text = Object.values(spec).join('/')
// 2.3 赠品的处理
// gift可能不存在 ,只有gift能解构出来,存在的时候,
const str = gift ? gift.split(',').map(el => `<span class="tag">【赠品】${el}</span>`).join(''):''
return `
<div class="item">
<img src="${picture}" alt="">
<p class="name">${name} ${str}</p>
<p class="spec">${text}</p>
<p class="price">${price.toFixed(2)}</p>
<p class="count">x${count}</p>
<p class="sub-total">${total.toFixed(2)}</p>
</div>
`
})
list.innerHTML = resArr.join('')
}
render()
第一天作业
作业01
当使用事件委托的时候,点击的元素中还有其他影响点击事件e.target的子元素,可以禁掉
javascript
.types-ms span,label{
/* 让span label对点击事件无效,事件就从li开始触发 */
pointer-events: none;
}
javascript
// 渲染函数 render
const box = document.querySelector('.herolist')
// 1. 渲染函数 render
function render(arr) {
const strArr = arr.map(el => {
const { icon, name } = el
return `
<li >
<a href="#" target="_blank"><img src="${icon}"
width="91" height="91" alt="${name}" />${name}</a>
</li>
`
})
// 渲染
box.innerHTML = strArr.join('')
}
render(heroArr)
// 2. 点击之后,筛选出对应的数据,渲染
const wrap = document.querySelector('.herolist-types')
wrap.addEventListener('click', function(e){
// 因为span / label 冒泡, 我们想要点击的li触发,可以进到span、label事件
console.log(e.target)
})
javascript
// 2. 点击之后,筛选出对应的数据,渲染
const wrap = document.querySelector('.herolist-types')
wrap.addEventListener('click', function(e){
// 因为span / label 冒泡, 我们想要点击的li触发,可以进到span、label事件
// console.log(e.target)
// 1. 点击的元素必须是li标签,tagName
// 2. 点击的li标签,必须有自定义属性data-ptype或者data-type
const {tagName, dataset:{ptype, type}} = e.target
if (tagName === 'LI' && (ptype || type)){
// 1. 上面的排他
this.querySelector('.current').classList.remove('current')
e.target.classList.add('current')
} // end if
// 给谁加current
})
javascript
const wrap = document.querySelector('.herolist-types')
wrap.addEventListener('click', function(e){
// 因为span / label 冒泡, 我们想要点击的li触发,可以进到span、label事件
// console.log(e.target)
// 1. 点击的元素必须是li标签,tagName
// 2. 点击的li标签,必须有自定义属性data-ptype或者data-type
const {tagName, dataset:{ptype, type}} = e.target
if (tagName === 'LI' && (ptype || type)){
// 1. 上面的排他
this.querySelector('.current').classList.remove('current')
e.target.classList.add('current')
// 2. 筛选对应的数据,渲染
let arr = []
// if (type === '0'){
// arr = heroArr
// } else {
// arr = heroArr.filter(function(el){
// // 把满足条件的元素重组为一个新的数组,过滤
// // 当点击下面的筛选元素
// return el.pay_type === +ptype || el.hero_type === +type
// })
// }
arr = +type === 0 ? heroArr : heroArr.filter(el => el.pay_type === +ptype || el.hero_type === +type)
render(arr)
} // end if
// 给谁加current
})
作业2,参考代码
注意,reset那个按钮,去掉了id,改成了类名获取 id为reset影响我们的reset重置事件
javascript
// 数据可以自己添加
let list = [
{ id: 1, name: "大乔", gender: "男", age: 18 },
{ id: 2, name: "小乔", gender: "女", age: 20 },
{ id: 3, name: "鲁班", gender: "男", age: 48 },
{ id: 4, name: "后羿", gender: "女", age: 28 },
]
const tbody = document.querySelector("tbody")
const searchBtn = document.querySelector("#search")
// const resetBtn = document.querySelector("#reset")
const addBtn = document.querySelector("#add")
const nameDom = document.querySelector("[name='name']")
const genderDom = document.querySelector("[name='gender']")
const ageDom = document.querySelector("[name='age']")
// 渲染模块
function render(arr) {
const strArr = arr.map((el, i) => {
const { name, gender, age, id } = el
return `
<tr>
<td>${i + 1}</td>
<td>${name}</td>
<td>${gender}</td>
<td>${age}</td>
<td>
<button type="button" class="btn btn-danger delete-btn" data-id="${id}" >删除</button>
</td>
</tr>
`
})
tbody.innerHTML = strArr.join('')
}
render(list)
searchBtn.addEventListener("click", function () {
// 每次点击的时候 取表单中的值
const v_name = nameDom.value.trim()
const v_gender = genderDom.value.trim()
const v_age = ageDom.value.trim()
// const newArr = list.filter(el => {
// // 如果表单没有输入名字,validName就为真
// // 用户什么都没输入,全为true,每一条都通过校验 显示4条
// const validName = v_name === "" || v_name === el.name
// const validGender = v_gender === "" || v_gender === el.gender
// const validAge = v_age === "" || +v_age === el.age
// return validName && validGender && validAge
// })
const newArr = list.filter(el => {
const okName = el.name.indexOf(v_name) > -1
const okGender = el.gender.indexOf(v_gender) > -1
const okAge = String(el.age).indexOf(v_age) > -1
return okName && okGender && okAge
})
render(newArr)
})
// 重置
const resetBtn = document.querySelector('.resetBtn')
resetBtn.addEventListener("click", function () {
render(list)
});
// 删除模块
tbody.addEventListener("click", function (e) {
if(e.target.tagName === 'BUTTON'){
if (!confirm("您确定删除吗")) return
const id = e.target.dataset.id
console.log(id)
list = list.filter(el => el.id !== +id)
// 删完,如果上面有搜索条件,自动触发搜索
searchBtn.click()
// render(list)
}
})