JavaScript提升,对JS的一点理解

写好JS的原则

各司其职

HTML,CSS,JS职能分离

组件封装

好的UI组件具备正确性,扩展性,复用性

过程抽象

应用函数式编程思想

案列一 各司其职

深夜食堂

写一段JS,控制一个网页,让它支持浅色和深色两种浏览模式。

第一版代码
  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 = '🌞';
    }
  });

代码看懂了,JS是这么写的吗,基本语法学过一点但没这么用过,即是用JS来控制CSS,没有职能分离。其实也用

第二版代码
  const btn = document.getElementById('modeBtn');
  btn.addEventListener('click', (e) => {
    const body = document.body;
    if(body.className !== 'night') {
      body.className = 'night';
    } else {
      body.className = '';
    }
  });

专业一点的,实现了一些职能分离,让人一眼看懂,其实第一版也能看懂吧。。。个人认为。。。不过写得确实漂亮!

第三版

不用JS,通过CSS和HTML实现

CSS伪类选择器,修改checkbox状态,匹配HTML中id,实现,隐藏checkbox,在label里赋值checkbox的状态,即绑定状态。就不贴代码了,有点牛!直接避免了写JS代码。

总结
  1. HTML/CSS/JS各司其责
  2. 应当避免不必要的由JS直接操作样式
  3. 可以用class来表示状态
  4. 纯展示类交互寻求零JS方案

案列二 组件封装

经典轮播图

定义HTML结构,无序列表

div嵌套ul再嵌套li

image-20220727144250424

CSS
  • 使用CSS绝对定位将图片重叠在同一个位置

  • 轮播图切换的状态使用修饰符(modifier)

  • 轮播图的切换动画使用CSS transition

    把图片重叠,定义选中和未选中的样式。通过不透明度opacity来改变

image-20220727144602647

行为:JS 定义API

image-20220727144801635

主要是这些函数。命名挺好的,见名知意,驼峰命名YYDS。

getSelectedltem()

getSelectedltemlndex()

slideTo()

slideNext()

slidePrevious()

实现的代码就不贴了,还是比较简单的(大概。。)

主要是代码细节和一些函数没学过比较难理解,看着简单,真自己从零写还是挺难的。


getElementById() 根据指定的id属性值得到对象

语法:

obj= document . getElementById ( sID )

参数:

sID : 必选项。字符串(String)。

返回值:

obj: 对象(object)。


querySelectorAll()

获取文档中 class=“example” 的所有元素:

var x = document.querySelectorAll(“.example”);

返回 NodeList 对象。

NodeList 对象表示节点的集合。可以通过索引访问,索引值从 0 开始。

提示: 你可以使用 NodeList 对象的 length 属性来获取匹配选择器的元素属性,然后你可以遍历所有元素,从而获取你想要的信息。


querySelector()

querySelector() 方法返回匹配指定 CSS 选择器元素的第一个子元素 。


JS事件流

实现状态,小圆点,自定义事件解耦,比较复杂,也不贴全部代码了,CV也没太多意义

  const detail = {index: idx}
  const event = new CustomEvent('slide', {bubbles:true, detail})
  this.container.dispatchEvent(event)

JS组件封装的基本过程

  • 结构设计
  • 展现效果
  • 行为设计
    1. API (功能)
    2. Event (控制流)

尽量不要让HTML,CSS,JS绑定,让组件插件化。

  • 将控制元素抽取成插件
  • 插件与组件之间通过依赖注入方式建立联系

要添加新功能,实现对应代码后依赖注入,不用修改其他代码,把组件注入JS就行了

HTML模板化

甚至能够让HTML模板化,解耦 与JS的差不多,通过render方法去生成HTML代码,将代码写入HTML,这样插入图片的时候,不用修改HTML CSS

 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>`;
    }
    ...
  }

render() 方法用于在提供的容器参数 container 里渲染一个 React 元素 element。

render() 方法返回对该组件的引用(或者针对无状态组件返回 null)。

就是在JS里面写HTML代码并插入,跟我学JAVA servlet的response.print()方法差不多,写起来挺折磨,毕竟JS里面没有HTML的代码补全,其中还用到了表达式取值EI,这个到好理解一点。

trim() 方法用于删除字符串的头尾空白符,空白符包括:空格、制表符 tab、换行符等其他空白符等。

其他函数百度把,见名知意硬理解也行hhh

抽象
  • 将组件通用模型抽象出来

image-20220727153202022

相当于手写一个小框架?继承出其他插件,注册给组件,再渲染,实现最后的封装。

总结

实现封装的原则

  • 组件设计的原则:封装性、正确性、扩展性、复用性
  • 实现组件的步骤:结构设计、展现效果、行为设计
  • 三次重构
    1. 插件化
    2. 模板化
    3. 抽象化(组件框架)

还可以改进

比如 :CSS组件化。

让各个部分各司其职,虽然写在了同一个文件里。

案列三 过程抽象

  • 些异步交互
  • 一次性的HTTP请求

例如:

  const list = document.querySelector('ul');
  const buttons = list.querySelectorAll('button');
  buttons.forEach((button) => {
    button.addEventListener('click', (evt) => {
      const target = evt.target;
      target.parentNode.className = 'completed';
      setTimeout(() => {
        list.removeChild(target.parentNode);
      }, 2000);
    });
  });

用户2秒内点击多次,因为child已经被移除了,调试工具会报错。提示已经移除,但其实不影响使用。。。确实,还是有影响的,因为例子很单一,实际开发中非常复杂,一个小BUG引发的错误有时候挺离谱的。

​ 为了能够让“只执行一次“的需求覆盖不同的事件处理,我们可以将这个需求剥离出来。这个过程我们称为过程抽象

手动实现once方法

  function once(fn) {
    return function(...args) {
      if(fn) {
        const ret = fn.apply(this, args);
        fn = null;
        return ret;
      }
    }
  }
高阶函数

HOF

  • 以函数作为参数
  • 以函数作为返回值
  • 常用于作为函数装饰器
 function HOF0(fn) {
    return function(...args) {
      return fn.apply(this, args);
    }
  }

​ 这个函数就是等价高阶函数,不论怎么给args,fn最终都会调用这个函数,等价。

常用的高阶函数

  • Once//见前文
  • Throttle//节流函数,实现控制频率
  • Debounce//防抖,不断变化时不改变,停止的时候改变,防止服务器负担过大
  • Consumer / 2//异步调用,间隔,但会完整运行完,延时调用
  • Iterative//批量操作

纯函数,行为造成的结果永远可以预期,输入确定,输出即确定。

在工程中,纯函数比较好调试。

编程范式

命令式

注重怎么做

声明式

注重做什么

命令式简单,但声明式扩展性更强,类似于前面的模块化

实现代码细节多想想怎么用声明式

第二节课主要讲代码的设计模式,还有一些算法的例子,举例了著名的leftpad事件(详情点击)

即是写代码要综合使用的场景,不是写得短写得漂亮就是最好的,要根据具体的场景去设计代码

  • 风格
  • 效率
  • 约定
  • 使用场景
  • 设计
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kun.A.A

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值