Js进阶案例合集
案例一:渲染商品
CSS代码
<style>* {margin: 0;padding: 0;box-sizing: border-box;}.list {width: 990px;margin: 0 auto;display: flex;flex-wrap: wrap;}.item {width: 240px;margin-left: 10px;padding: 20px 30px;transition: all .5s;margin-bottom: 20px;}.item:nth-child(4n) {margin-left: 0;}.item:hover {box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2);transform: translate3d(0, -4px, 0);cursor: pointer;}.item img {width: 100%;}.item .name {font-size: 18px;margin-bottom: 10px;color: #666;}.item .price {font-size: 22px;color: firebrick;}.item .price::before {content: "¥";font-size: 14px;}.filter {display: flex;width: 990px;margin: 0 auto;padding: 50px 30px;}.filter a {padding: 10px 20px;background: #f5f5f5;color: #666;text-decoration: none;margin-right: 20px;}/* tab栏切换 */.filter a:active,.filter a:focus {background: #05943c;color: #fff;}</style>
注意CSS中tab栏切换的简便写法
HTML代码
<div class="filter"><a data-index="1" href="javascript:;">0-100元</a><a data-index="2" href="javascript:;">100-300元</a><a data-index="3" href="javascript:;">300元以上</a><a href="javascript:;">全部区间</a></div><div class="list"><!-- <div class="item"><img src="" alt=""><p class="name"></p><p class="price"></p></div> --></div>
JS初始代码
<script>const goodsList = [{id: '4001172',name: '称心如意手摇咖啡磨豆机咖啡豆研磨机',price: '289.00',picture: 'https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg',},{id: '4001594',name: '日式黑陶功夫茶组双侧把茶具礼盒装',price: '288.00',picture: 'https://yanxuan-item.nosdn.127.net/3346b7b92f9563c7a7e24c7ead883f18.jpg',},{id: '4001009',name: '竹制干泡茶盘正方形沥水茶台品茶盘',price: '109.00',picture: 'https://yanxuan-item.nosdn.127.net/2d942d6bc94f1e230763e1a5a3b379e1.png',},{id: '4001874',name: '古法温酒汝瓷酒具套装白酒杯莲花温酒器',price: '488.00',picture: 'https://yanxuan-item.nosdn.127.net/44e51622800e4fceb6bee8e616da85fd.png',},{id: '4001649',name: '大师监制龙泉青瓷茶叶罐',price: '139.00',picture: 'https://yanxuan-item.nosdn.127.net/4356c9fc150753775fe56b465314f1eb.png',},{id: '3997185',name: '与众不同的口感汝瓷白酒杯套组1壶4杯',price: '108.00',picture: 'https://yanxuan-item.nosdn.127.net/8e21c794dfd3a4e8573273ddae50bce2.jpg',},{id: '3997403',name: '手工吹制更厚实白酒杯壶套装6壶6杯',price: '99.00',picture: 'https://yanxuan-item.nosdn.127.net/af2371a65f60bce152a61fc22745ff3f.jpg',},{id: '3998274',name: '德国百年工艺高端水晶玻璃红酒杯2支装',price: '139.00',picture: 'https://yanxuan-item.nosdn.127.net/8896b897b3ec6639bbd1134d66b9715c.jpg',},]
</script>
模块一:封装渲染函数
function render(arr) {let str = ''//item指当前数组元素即对象arr.forEach(item => {const { name, price, picture } = itemstr += `<div class="item"><img src=${picture} alt=""><p class="name">${name}</p><p class="price">${price}</p></div>`})document.querySelector('.list').innerHTML = str}render(goodsList)
精华:提前声明一个空字符串,用字符串拼接的方法生成结构添加到页面中
模块二:筛选商品
document.querySelector('.filter').addEventListener('click', e => {const { tagName, dataset } = e.targetif (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代码
<style>* {margin: 0;padding: 0;box-sizing: border-box;}.list {width: 990px;margin: 100px auto 0;}.item {padding: 15px;transition: all .5s;display: flex;border-top: 1px solid #e4e4e4;}.item:nth-child(4n) {margin-left: 0;}.item:hover {cursor: pointer;background-color: #f5f5f5;}.item img {width: 80px;height: 80px;margin-right: 10px;}.item .name {font-size: 18px;margin-right: 10px;color: #333;flex: 2;}.item .name .tag {display: block;padding: 2px;font-size: 12px;color: #999;}.item .price,.item .sub-total {font-size: 18px;color: firebrick;flex: 1;}.item .price::before,.item .sub-total::before,.amount::before {content: "¥";font-size: 12px;}.item .spec {flex: 2;color: #888;font-size: 14px;}.item .count {flex: 1;color: #aaa;}.total {width: 990px;margin: 0 auto;display: flex;justify-content: flex-end;border-top: 1px solid #e4e4e4;padding: 20px;}.total .amount {font-size: 18px;color: firebrick;font-weight: bold;margin-right: 50px;}</style>
HTML代码
<div class="list"><!-- <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> --></div><div class="total"><div>合计:<span class="amount">1000.00</span></div></div>
JS初始代码
<script>const goodsList = [{id: '4001172',name: '称心如意手摇咖啡磨豆机咖啡豆研磨机',price: 289.9,picture: 'https://yanxuan-
item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg',count: 2,spec: { color: '白色' }},{id: '4001009',name: '竹制干泡茶盘正方形沥水茶台品茶盘',price: 109.8,picture: 'https://yanxuan-item.nosdn.127.net/2d942d6bc94f1e230763e1a5a3b379e1.png',count: 3,spec: { size: '40cm*40cm', color: '黑色' }},{id: '4001874',name: '古法温酒汝瓷酒具套装白酒杯莲花温酒器',price: 488,picture: 'https://yanxuan-item.nosdn.127.net/44e51622800e4fceb6bee8e616da85fd.png',count: 1,spec: { color: '青色', sum: '一大四小' }},{id: '4001649',name: '大师监制龙泉青瓷茶叶罐',price: 139,picture: 'https://yanxuan-item.nosdn.127.net/4356c9fc150753775fe56b465314f1eb.png',count: 1,spec: { size: '小号', color: '紫色' },gift: '50g茶叶,清洗球'}]
</script>
模块一:更换数据模块
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 => `<span class="tag">【赠品】${item}</span> `).join('') : ''//计算小计模块 单价 * 数量 保留两位小数// 注意精度问题,因为保留两位小数,所以乘以 100 最后除以100const subTotal = ((price * 100 * count) / 100).toFixed(2)return `<div class="item"><img src=${picture} alt=""><p class="name">${name} ${str}</span></p><p class="spec">${text}</p><p class="price">${price.toFixed(2)}</p><p class="count">x${count}</p><p class="sub-total">${subTotal}</p></div>`}).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代码
<style>.modal {width: 300px;min-height: 100px;box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);border-radius: 4px;position: fixed;z-index: 999;left: 50%;top: 50%;transform: translate3d(-50%, -50%, 0);background-color: #fff;}.modal .header {line-height: 40px;padding: 0 10px;position: relative;font-size: 20px;}.modal .header i {font-style: normal;color: #999;position: absolute;right: 15px;top: -2px;cursor: pointer;}.modal .body {text-align: center;padding: 10px;}.modal .footer {display: flex;justify-content: flex-end;padding: 10px;}.modal .footer a {padding: 3px 8px;background: #ccc;text-decoration: none;color: #fff;border-radius: 2px;margin-right: 10px;font-size: 14px;}.modal .footer a.submit {background-color: #369;}</style>
HTML代码
<button id="delete">删除</button><button id="login">登录</button><!-- <div class="modal"><div class="header">温馨提示 <i>x</i></div><div class="body">您没有删除权限操作</div></div> -->
练习面向对象写插件(模态框)
模块一:制作Modal构造函数
function Modal(title = '', message = '') {//创建div标签this.modalBox = document.createElement('div')//给div标签添加类名为modalthis.modalBox.className = 'modal'//modal盒子内部填充2个div标签并且修改文字内容this.modalBox.innerHTML = `<div class="header">${title} <i>x</i></div><div class="body">${message}</div>`}
模块二: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()})