写好JS的一些原则
- 各司其责
让HTML、CSS和JavaScript职能分离。 - 组件封装
好的UI组件具备正确性、扩展性、复用性。 - 过程抽象
应用函数式编程思想。
深夜食堂
写一段JS,控制一个网页,让它支持浅色和深色两种浏览模式。 如果是你来实现,你会怎么做?
- HTML/CSS/JS 各司其责
- 应当避免不必要的由 JS 直接操作样式
- 可以用 class 来表示状态
- 纯展示类交互寻求零 JS 方案
实现的第一种方式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>深夜食堂</title> </head> <body> <header> <button id="modeBtn">🌞</button> <h1>深夜食堂</h1> </header> <main> <div class="pic"> <img src="https://p2.ssl.qhimg.com/t0120cc20854dc91c1e.jpg"> </div> <div class="description"> <p> 这是一间营业时间从午夜十二点到早上七点的特殊食堂。这里的老板,不太爱说话,却总叫人吃得热泪盈 眶。在这里,自卑的舞蹈演员偶遇隐退多年舞界前辈,前辈不惜讲述自己不堪回首的经历不断鼓舞年轻人,最终令其重拾自信;轻言绝交的闺蜜因为吃到共同喜爱的美食,回忆起从前的友谊,重归于好;乐观的绝症患者遇到同命相连的女孩,两人相爱并相互给予力量,陪伴彼此完美地走过了最后一程;一味追求事业成功的白领,在这里结交了真正暖心的朋友,发现真情比成功更有意义。食物、故事、真情,汇聚了整部剧的主题,教会人们坦然面对得失,对生活充满期许和热情。每一个故事背后都饱含深情,情节跌宕起伏,令人流连忘返 [6] 。 </p> </div> </main> </body> </html> 复制代码
body, html { width: 100%; height: 100%; padding: 0; margin: 0; overflow: hidden; } body { padding: 10px; box-sizing: border-box; } div.pic img { width: 100%; } #modeBtn { font-size: 2rem; float: right; border: none; background: transparent; } 复制代码
const btn = document.getElementById('modeBtn'); btn.addEventListener('click', (e) => { const body = document.body; if(e.target.innerHTML === '🌞') { body.style.backgroundColor = 'black'; body.style.color = 'white'; e.target.innerHTML = '🌜'; } else { body.style.backgroundColor = 'white'; body.style.color = 'black'; e.target.innerHTML = '🌞'; } }); 复制代码
获取切换按钮元素, 给按钮绑定鼠标点击事件, 获取页面body元素, 判断当前按钮元素是🌞还是🌜, 是🌞就将页面的背景色改成黑色,字体颜色改成白色,并将按钮元素变成🌜, 否则说明按钮就是🌜,我们就将页面背景色改为白色,字体改为黑色,并将按钮元素变成🌞。
第二种方式
通过改变body的class名字,比直接操作dom更加有效,因为频繁的去操作DOM会导致页面频繁的重排重绘。这样可以提高效率。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>深夜食堂</title> </head> <body> <header> <button id="modeBtn"></button> <h1>深夜食堂</h1> </header> <main> <div class="pic"> <img src="https://p2.ssl.qhimg.com/t0120cc20854dc91c1e.jpg"> </div> <div class="description"> <p> 这是一间营业时间从午夜十二点到早上七点的特殊食堂。这里的老板,不太爱说话,却总叫人吃得热泪盈 眶。在这里,自卑的舞蹈演员偶遇隐退多年舞界前辈,前辈不惜讲述自己不堪回首的经历不断鼓舞年轻人,最终令其重拾自信;轻言绝交的闺蜜因为吃到共同喜爱的美食,回忆起从前的友谊,重归于好;乐观的绝症患者遇到同命相连的女孩,两人相爱并相互给予力量,陪伴彼此完美地走过了最后一程;一味追求事业成功的白领,在这里结交了真正暖心的朋友,发现真情比成功更有意义。食物、故事、真情,汇聚了整部剧的主题,教会人们坦然面对得失,对生活充满期许和热情。每一个故事背后都饱含深情,情节跌宕起伏,令人流连忘返 [6] 。 </p> </div> </main> </body> </html> 复制代码
body, html { width: 100%; height: 100%; max-width: 600px; padding: 0; margin: 0; overflow: hidden; } body { padding: 10px; box-sizing: border-box; transition: all 1s; } div.pic img { width: 100%; } #modeBtn { font-size: 2rem; float: right; border: none; outline: none; cursor: pointer; background: inherit; } body.night { background-color: black; color: white; transition: all 1s; } #modeBtn::after { content: '🌞'; } body.night #modeBtn::after { content: '🌜'; } 复制代码
const btn = document.getElementById('modeBtn'); btn.addEventListener('click', (e) => { const body = document.body; if(body.className !== 'night') { body.className = 'night'; } else { body.className = ''; } }); 复制代码
第三种
使用input标签和css样式改变背景。checkbox的切换正好对应样式的切换
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>深夜食堂</title> </head> <body> <input id="modeCheckBox" type="checkbox"> <div class="content"> <header> <label id="modeBtn" for="modeCheckBox"></label> <h1>深夜食堂</h1> </header> <main> <div class="pic"> <img src="https://p2.ssl.qhimg.com/t0120cc20854dc91c1e.jpg"> </div> <div class="description"> <p> 这是一间营业时间从午夜十二点到早上七点的特殊食堂。这里的老板,不太爱说话,却总叫人吃得热泪盈 眶。在这里,自卑的舞蹈演员偶遇隐退多年舞界前辈,前辈不惜讲述自己不堪回首的经历不断鼓舞年轻人,最终令其重拾自信;轻言绝交的闺蜜因为吃到共同喜爱的美食,回忆起从前的友谊,重归于好;乐观的绝症患者遇到同命相连的女孩,两人相爱并相互给予力量,陪伴彼此完美地走过了最后一程;一味追求事业成功的白领,在这里结交了真正暖心的朋友,发现真情比成功更有意义。食物、故事、真情,汇聚了整部剧的主题,教会人们坦然面对得失,对生活充满期许和热情。每一个故事背后都饱含深情,情节跌宕起伏,令人流连忘返 [6] 。 </p> </div> </main> </div> </body> </html> 复制代码
body, html { width: 100%; height: 100%; max-width: 600px; padding: 0; margin: 0; overflow: hidden; } body { box-sizing: border-box; } .content { height: 100%; padding: 10px; transition: background-color 1s, color 1s; } div.pic img { width: 100%; } #modeCheckBox { display: none; } #modeCheckBox:checked + .content { background-color: black; color: white; transition: all 1s; } #modeBtn { font-size: 2rem; float: right; } #modeBtn::after { content: '🌞'; } #modeCheckBox:checked + .content #modeBtn::after { content: '🌜'; } 复制代码
让HTML、CSS和JavaScript职能分离,避免不必要的由JS直接操作样式。
组件封装
组件是指Web页面上抽出来一个个包含模版(HTML)、功能(JS)和样式(CSS)的单元。好的组件具备封装性、正确性、扩展性、复用性。
结构
轮播图是一个典型的列表结构,我们可以使用无序列表ul
元素来实现。
表现
- 使用 CSS 绝对定位将图片重叠在同一个位置
- 轮播图切换的状态使用修饰符(modifier)
- 轮播图的切换动画使用 CSS transition