Skip to content

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 利用构造函数创建对象

  1. 构造函数,相当于是一个模板,通过这个构造函数,可以创建出一系列具有相同属性和方法的对象
  2. 实例化:通过构造函数,创建对象的过程叫做实例化 ==> new一个对象的过程
  3. 实例:具体的实际的例子,实际的那个对象 实例/实例对象
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的执行过程?构造函数的执行过程?

  1. 创建一个空对象
  2. 让this指向这个空对象
  3. 执行构造函数里面的代码,给这个空对象添加属性和方法
  4. 返回这个对象 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遍历对象

  1. obj['key'] === obj.key , 这两种情况,是找对象中有没有这个key属性名
  2. 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()

从字符串中截取某个子串出来

  1. [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)
  }
})