JavaScript 编码原则 | 青训营笔记

48 阅读4分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第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)