CSS代码
注意CSS中tab栏切换的简便写法
HTML代码
JS初始代码
模块一:封装渲染函数
function render(arr) {
let str = ''
//item指当前数组元素即对象
arr.forEach(item => {
const { name, price, picture } = item
str += `
${name}
${price}
`
})
document.querySelector('.list').innerHTML = str
}
render(goodsList)
精华:提前声明一个空字符串,用字符串拼接的方法生成结构添加到页面中
模块二:筛选商品
document.querySelector('.filter').addEventListener('click', e => {
const { tagName, dataset } = e.target
if (tagName === 'A') {
// arr是返回的新数组
let arr = goodsList //这样赋值点击4就把全部商品进行渲染
if (dataset.index === '1') {
arr = goodsList.filter(item => item.price > 0 && item.price <= 100)
} else if (dataset.index === '2') {
arr = goodsList.filter(item => item.price >= 100 && item.price <= 300)
} else if (dataset.index === '3') {
arr = goodsList.filter(item => item.price >= 300)
}
//调用渲染函数
render(arr)
}
})
精华:
1.filter()方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素
主要使用场景:筛选数组符合条件的元素,并返回筛选之后元素的新数组
2.arr是返回的新数组,初始化赋值为goodsList,因为事件委托点击对象必定为链接,在判断条件中没有对4号进行特判,这样赋值能满足点击4就把全部商品进行渲染的需求
CSS代码
HTML代码
合计:1000.00
JS初始代码
模块一:更换数据模块
document.querySelector('.list').innerHTML = goodsList.map(item => {
const { picture, name, count, price, spec, gift } = item//对象解构
//规格文字模块处理
const text = Object.values(spec).join('/')
//赠品模块处理
const str = gift ? gift.split(',').map(item => `【赠品】${item} `).join('') : ''
//计算小计模块 单价 * 数量 保留两位小数
// 注意精度问题,因为保留两位小数,所以乘以 100 最后除以100
const subTotal = ((price * 100 * count) / 100).toFixed(2)
return `
${name} ${str}
${text}
${price.toFixed(2)}
x${count}
${subTotal}
`
}).join('')
总体思路:
先利用map来遍历,有多少条数据就渲染多少商品,注意map返回值是数组,我们需要用join 转换为字符串,再把返回的字符串赋值给list大盒子的innerHTML
具体处理:
先更换不需要处理的数据,图片,商品名称,单价,数量,采取对象解构的方式,注意单价要保留2位小数,toFixed(2)
处理规格文字模块:获取每个对象里面的spec , 用Object.values()获得所有属性值,返回的是数组,再使用join(‘/’)这样就可以转换为符合格式要求的字符串了
处理赠品模块:获取每个对象里面的gift , 注意要判断是否有gift属性,没有的话不需要渲染,如果有的话先用split(‘,’)方法把字符串拆分为数组,再利用map遍历数组,同时把数组元素生成到span里面,再使用join(‘’)转换为字符串
精度问题:
关于小数的计算精度问题
0.1 + 0.2 = ?
解决方案:我们经常转换为整数(0.1*100 + 0.2*100)/ 100 === 0.3
模块二:合计模块
const total = goodsList.reduce((prev, item) => prev + (item.price * 100 * item.count) / 100, 0)
document.querySelector('.amount').innerHTML = total.toFixed(2)
求和用到数组reduce 方法累计器,根据数据里面的数量和单价累加和即可,注意reduce方法有2个参数,第一个是回调函数,第二个是初始值,遇到对象数组起始值必先设置为0
CSS代码
HTML代码
练习面向对象写插件(模态框)
模块一:制作Modal构造函数
function Modal(title = '', message = '') {
//创建div标签
this.modalBox = document.createElement('div')
//给div标签添加类名为modal
this.modalBox.className = 'modal'
//modal盒子内部填充2个div标签并且修改文字内容
this.modalBox.innerHTML = `
${title} x
${message}
`
}
模块二:open方法
Modal.prototype.open = function () {
//先来判断页面中是否有modal盒子,如果有先删除,否则继续添加
const box = document.querySelector('.modal')
box && box.remove()
//注意这个方法不要用箭头函数,因为我们需要使用this
//把刚才创建的modalBox显示到页面body中
document.body.append(this.modalBox)
//要等着盒子显示出来,就可以绑定点击事件了
this.modalBox.querySelector('i').addEventListener('click', () => {
//这个地方需要用到箭头函数
//这里的this指向实例对象
this.close()
})
}
需要写在构造函数的原型对象上,共享方法
open 打开的本质就是把创建标签添加到页面中,把刚才创建的modalBox添加到页面body 标签中
需要注意,x 删除按钮绑定事件,要写到open里面添加,因为只有等到盒子显示出来,才可以绑定点击事件
为了避免多次点击x 删除按钮所导致的出现多个模态框的情况,我们在给构造函数原型对象挂载open方法时需要先来判断页面中是否有modal盒子,如果有先删除,否则继续添加,这里使用&&的逻辑中断方法十分合适
关于此处this的指向问题,必须明确这步代码的操作对象究竟是谁才能选择正确。要注意:箭头函数不会创建自己的this,它只会从自己的作用域链的上一层沿用this
模块三:close方法
Modal.prototype.close = function () {
this.modalBox.remove()
}
需要写在构造函数的原型对象上,共享方法
把刚才创建的modalBox从页面body 标签中删除
document.querySelector('#delete').addEventListener('click', () => {
const del = new Modal('温馨提示', '您没有权限删除')
del.open()
})
document.querySelector('#login').addEventListener('click', () => {
const login = new Modal('友情提示', '您还没有注册账号')
login.open()
})