这是我参与「 第五届青训营 」笔记创作活动的第2天
【知之非艰,行之惟难。】
一、本堂课重点内容:
围绕写好JavaScript的三原则对JavaScript讲解。
三原则:各司其职、组件封装、过程抽象。
二、详细知识点介绍:
写好JS的一些原则
- 各司其职:让HTML、CSS和JavaScript三者分离,负责自己应该做的事
- 组件封装:一个组件应当具有正确性、可拓展性和复用性
- 过程抽象:利用函数闭包、函数编程式思想
示例:
- 各司其职:深夜食堂(在网页中实现深色模式与浅色模式的自由切换)
// 版本一
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 = '🌞';
}
});
// 版本二
const btn = document.getElementById('modeBtn');
btn.addEventListener('click', (e) => {
const body = document.body;
if(body.className !== 'night') {
body.className = 'night';
} else {
body.className = '';
}
});
版本三
<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>
这是一间营业时间从午夜十二点到早上七点的特殊食堂。这里的老板,不太爱说话,却总叫人吃得热泪盈眶。
</p>
</div>
</main>
</div>
#modeCheckBox {
display: none;
}
#modeCheckBox:checked + .content {
background-color: black;
color: white;
transition: all 1s;
}
在版本一的代码中,直接由JS直接控制样式,没有使用CSS。版本二中使用JS控制元素的class标签,再通过css设置元素样式,但是此时的JS代码为一次性代码,可复用性低。版本三中仅使用HTML和CSS,没有JS代码。
- 组件封装:轮播图 在最开始中使用HTML、CSS、JS去描述一个组件的相关内容,但是并不符合一个组件应该具备的特性,因此对其进行改进。
// 模板化
class Slider{
constructor(id, opts = {images:[], cycle: 3000}){
this.container = document.getElementById(id);
this.options = opts;
this.container.innerHTML = this.render();
this.items = this.container.querySelectorAll('.slider-list__item, .slider-list__item--selected');
this.cycle = opts.cycle || 3000;
this.slideTo(0);
}
render(){
const images = this.options.images;
const content = images.map(image => `
<li class="slider-list__item">
<img src="${image}">
</li>
`.trim());
return `<ul>${content.join('')}</ul>`;
}
...
}
// 插件化
function pluginController(slider){
const controller = slider.container.querySelector('.slide-list__control');
if(controller){
const buttons = controller.querySelectorAll('.slide-list__control-buttons, .slide-list__control-buttons--selected');
controller.addEventListener('mouseover', evt=>{
const idx = Array.from(buttons).indexOf(evt.target);
if(idx >= 0){
slider.slideTo(idx);
slider.stop();
}
});
controller.addEventListener('mouseout', evt=>{
slider.start();
});
slider.addEventListener('slide', evt => {
const idx = evt.detail.index
const selected = controller.querySelector('.slide-list__control-buttons--selected');
if(selected) selected.className = 'slide-list__control-buttons';
buttons[idx].className = 'slide-list__control-buttons--selected';
});
}
}
function pluginPrevious(slider){
const previous = slider.container.querySelector('.slide-list__previous');
if(previous){
previous.addEventListener('click', evt => {
slider.stop();
slider.slidePrevious();
slider.start();
evt.preventDefault();
});
}
}
function pluginNext(slider){
const next = slider.container.querySelector('.slide-list__next');
if(next){
next.addEventListener('click', evt => {
slider.stop();
slider.slideNext();
slider.start();
evt.preventDefault();
});
}
}
将组件通用模型抽象出来的方法
class Component{
constructor(id, opts = {name, data:[]}){
this.container = document.getElementById(id);
this.options = opts;
this.container.innerHTML = this.render(opts.data);
}
registerPlugins(...plugins){
plugins.forEach(plugin => {
const pluginContainer = document.createElement('div');
pluginContainer.className = `.${name}__plugin`;
pluginContainer.innerHTML = plugin.render(this.options.data);
this.container.appendChild(pluginContainer);
plugin.action(this);
});
}
render(data) {
/* abstract */
return ''
}
}
在组件实现过程中要考虑组件的设计原则(封装性,正确性,可扩展性,可复用性),对于设计出的组件可进行插件化、模板化等优化。
- 过程抽象:
剥离项目开发中的大量重复代码(实现相同功能),将其过程进行抽象。
过程抽象,将那些需要重复的操作抽象出来,利用函数闭包的语法,实现类似装饰器的效果,将业务代码加上这些功能。
【left-pad事件】 leftpad是一个简单处理字符串的函数,主要功能:当字符串的长度没有达到我们要的长度时,就在它的左边补若干个字符,把它的长度补齐。
module.exports = leftpad;
function leftpad (str, len, ch) {
str = String(str);
var i = -1;
if (!ch && ch !== 0) ch = ' ';
len = len - str.length;//期望的长度-字符串的长度 = 要拼接的长度
while (++i < len) {//通过循环,把用来替代的字符添加到字符串前面去
str = ch + str;
}
return str;
}
小八卦:【Left-pad事件】就是当年 NPM 圈发生的“一个十几行代码的模块引发的血案”。left-pad工具模块被作者 Azer从 NPM 上撤下,所有直接或者间接依赖这个模块的 NPM 包就都忧伤的挂掉了,其中就包括 babel 、React等。作者为什么要删包?事情是这样的,Azer 写了一个工具叫 kik 发布在 npm 上,这天有个同名的公司律师找上门要求他删掉,Azer 不从,这律师就找上 npm,npm 把包的管理权限转给了这家公司——当然,Azer 就怒了,从 npm 上解放了所有自己发布的包。
三、实践练习例子:
四、课后个人总结:
进一步熟悉掌握了JS,不过对于JS的深入了解还需要进一步去细致学习。
五、引用参考: