这是我参与「第五届青训营 」伴学笔记创作活动的第3天。
一、本堂课重点内容
- 各司其责
- 组件封装
二、详细知识点介绍
各司其责
- HTML/CSS/JS各司其责
- 应当避免不必要的由JS直接操作样式
- 可以用class来表示状态
- 纯展示类交互应寻求零JS方案,但不强求
label的for属性规定label与哪个表单元素绑定。<label>是专门为<input>元素服务的,为其定义标记。
给 label 加了 for 属性绑定了input控件后,可以提高鼠标用户的体验。如果在label元素内点击文本,就会触发此控件,也就是说,当用户渲染该标签时,浏览器就会自动将焦点转到和标签相关的表单控件上。
隐式绑定:
<label>Date of Birth: <input type="text" name="DofB" /></label>
显式绑定:
<label for="SSN">Social Security Number:</label>
<input type="text" name="SocSecNum" id="SSN" />
组件封装
组件是指Web页面上抽出来的一个个包含模板(HTML)、功能(JS)和样式(CSS)的单元。好的组件具备封装性、正确性、扩展性、复用性。
实现组件的步骤:结构设计、展现效果、行为设计。
JavaScript自定义事件
javascript与HTML之间的交互是通过事件来实现的。事件,就是文档或浏览器窗口发生的一些特定的交互瞬间。通常大家都会认为事件是在用户与浏览器进行交互的时候触发的,其实通过javascript我们可以在任何时刻触发特定的事件,并且这些事件与浏览器创建的事件是相同的。
JavaScript依赖注入
将功能抽象为一个个函数或对象,在组件初始化时将功能传入到组件构造函数内,需要什么功能就传入什么函数或对象,称之为注册。
注册函数时,组件将对功能进行统一的操作。
功能函数或对象也应具有相同的结构,以供组件调用。
模板化
将组件抽象成一个个JS类,在类内定义函数约束组件的行为,将HTML内声明的元素id传入到JS组件的构造函数中让JS知道要渲染哪个元素。有相似功能的一类组件可以继承自同一个抽象类。
三、实践实习例子
伪类选择器修改DOM元素状态
<main>
<input type="checkbox" id="check">
<p id="para2">这是一间营业时间从午夜十二点到早上七点的特殊食堂。这里的老板,不太爱说话,却总叫人吃得热泪盈眶。</p>
</main>
<style>
#check:checked + #para2{
color: aqua;
background-color: brown;
transition: background-color 1s,color 1s;
}
</style>
Label的for属性结合伪类选择器
<main>
<input type="checkbox" id="check">
<label id="checkLabel" for="check"></label>
<p id="para2">这是一间营业时间从午夜十二点到早上七点的特殊食堂。这里的老板,不太爱说话,却总叫人吃得热泪盈眶。</p>
</main>
<style>
/* #check{ //解注释后,input标签不再渲染,但点击label仍然对input有效
display: none;
} */
#checkLabel::after{
content: '🌞';
}
#check:checked+#checkLabel::after{
content: '🌜';
}
#check:checked ~ #para2{
color: aqua;
background-color: brown;
transition: background-color 1s,color 1s;
}
</style>
JavaScript自定义事件
<style>
#para {
transition: all 1s;
}
</style>
<main>
<button id="btn">trigger custom event</button>
<p id="para">本节课将主要围绕编码三大原则的“组件封装”原则展开。组件是 Web 页面上所抽取的模版、功能与样式的单元,自从
React,Vue 等前端框架在市面上大量使用之后,组件化开发逐渐成为了前端主流开发方式。</p>
</main>
<script>
const btn = document.getElementById("btn");
const para = document.getElementById("para");
let flag = 0;
para.addEventListener("customEvent", event => {
para.style.background = event.detail.background;
});
btn.onclick = () => {
const event = new CustomEvent("customEvent", {
detail: { background: flag === 0 ? "red" : "yellow" }
});
flag ^= 1;
para.dispatchEvent(event);
};
</script>
依赖注入
class Slider{//一个组件
...
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);
});
...
}
const pluginNext = {//一个功能,具有返回UI和执行动作的功能
render(){
return `<a class="slide-list__next"></a>`;
},
action(slider){
let previous = slider.container.querySelector('.slide-list__next');
if(previous){
previous.addEventListener('click', evt => {
slider.stop();
slider.slideNext();
slider.start();
evt.preventDefault();
});
}
}
};
...
slider.registerPlugins(pluginController, pluginPrevious, pluginNext);//组件注册功能
四、课后个人总结
本节课通过2个例子,分别介绍了JS编程思想的各司其责和组件封装,其实软件工程的设计思想不仅在JS适用,在各种面向对象编程场景下都适用。对于面向对象的场景,要贯彻继承、多态、封装的思想,深入分析功能需求,将功能抽象为一个个组件,组件要高内聚低耦合,具备较好的兼容性和可移植性。
本节课使用的部分JS和CSS特性还不太了解,如label标签的for属性,通过伪类规定元素的行为,JS的自定义事件等,需要之后继续学习研究。
五、参考链接
label 的for属性总结 - 三高娘子 - 博客园 (cnblogs.com)
CustomEvent自定义事件_荷花微笑的博客-CSDN博客_customevent
跟着月影学 JavaScript(上).pptx - 飞书云文档 (feishu.cn)