JS 网页动态技术(上半场) | 青训营笔记

119 阅读7分钟

这是我参与「第四届青训营 」笔记创作活动的的第3天

写JS的一些原则

各司其职

让HTML、CSS、Javascript职能分离

组件封装

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

过程抽象

应用函数式编程思维

三种JS写法的区别与优劣

用js控制css

image.png

不利于其他程序员阅读代码,需求改变代码修改复杂

用js控制类名

image.png

符合各司其职的js代码原则

纯css控制页面变化

image.png

通过lable设置一个for一个元素,for checkbox的id,使点击label的效果等同于checkbox的点击效果

image.png

image.png

使chekbox不可见

image.png

利用伪类选择器改变状态,给checkbox设计一个checked状态,通过checked状态和兄弟选择器匹配到class=.content的内容,然后对.content进行修改

image.png

总结:

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

封装组件

组件是指Web页面上抽出来一个个包含模版(HTML)、功能(JS)和样式(CSS)的单元。好的组件具备封装性、正确性、扩展性、复用性。

制作轮播图

结构:HTML

轮播图是一个共型的列表结构,我们可以使用无序列表ul元素来实现。

image.png

CSS表现

  • 使用CSS绝对定位将图片重叠在同一个位置
  • 轮播图切换的状态使用修饰符(modifier)
  • 轮播图的切换动画使用CSS transition

image.png

行为:API

Slider

  • getSelectedItem() 得到当前选中的图片元素
  • getselectedltemlndex() 得到当前选中图片元素列表下标
  • slideTo() 到特定位置
  • slideNext() 轮播下一张图片
  • slidePrevious() 轮播上一张图片

image.png

根据container的id获得外面DIV元素,将里面li的元素作为items,来自“container.queryselectorAlL('.slider-list_item,.slider-list_item-selected');”将没被选中的元素(list_item)和被选中的元素(list_item_select)都装入items

image.png

直接得到被选中的元素

image.png

利用indexOf方法判断items里面的第几个元素和getSelectItem的元素一样,就得到了下标

image.png

得到当前被选中元素,并将被选中元素修改为非选中元素状态,选出被选中的items[idx]

image.png

通过getSelectedItemIndex()得到当前显示图片的下标,nextindex是当前加一取模

image.png

减一加模长再取模,保证取到的是正数

image.png

计时器,每两秒钟切换

JS行为

控制流,使用自定义事件来解释

image.png

image.png

鼠标悬停时停止播放

image.png

根据图片的idx得到li小圆点的idx

image.png

切换时停掉动画,切换完成后继续

image.png

往前往后的不需要slide监听事件

image.png

派发自定义事件

image.png

总结:

  • 结构设计
  • 展现效果
  • 行为设计 [ API(功能)+ Event(控制流)]

重构:插件化

解耦

  • 将控制元素抽取成插件
  • 插件与组件之间通过依赖注入方式建立联系
  • 将HTML模板化,更易于扩展

image.png

1.做了插件抽象,将slide简化

image.png

2.当不需要某一部分的时候可以直接注释掉(结构、效果依然在,但其执行功能不再实现)

image.png

image.png

插件化,实现扩展性,加入组件用组件控制轮播图,不用修改轮播图,只需要把轮播图注册到轮播图的插件中

image.png

HTML代码只有容器代码本身,其他代码通过JS中Slider的remder函数接收图片数据传入组件

image.png

注册插件,调用插件的plugin.remeder方,法同时传入四张图片,生成插件对应的模板,把模板放入插件的container里,把插件的的container放入组件的container里,利用插件的action功能完成插件初始化

image.png

渲染出自己的内容

image.png

image.png

完成插件初始化

image.png

image.png

除它外的功能好的,低下小圆点也消失了。 非常灵活

抽象

将组件通用模型抽象出来

image.png

image.png

component组件框架,形成抽象的通用模型,有注册插件plugins和渲染remder(抽象方法、空的)

image.png

image.png

Slider继承component的remder,实现该方法,其他方法不变

image.png

plugincontroler实现ramder和action

image.png

pluginprevious实现ramder和action

image.png

image.png

new一个含id的silder(即传入的HTML的容器的id),name是所有css的前缀,传入图片数据,和循环时间3s

总结:

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

过程抽象

用来处理局部细节控制的一些方法

函数式编程思维的基础应用

image.png

e.g.:操作次数限制

一些异步交互,一次性http请求

image.png

触发一次click事件,会设置completed状态,两秒之后remove,如果重复点击会执行多次remove,但是已经移出了,会报错,所以改代码只能执行一次,有bug

image.png

在最后增加了once:true代表改代码触发只能执行一次

image.png

不是click事件,是向服务器请求一个数据,希望数据被请求,多次请求只回复第一次,其他的都block掉(多次调用只执行一次)——once的过程抽象(高阶函数),只会执行一次

image.png

测试运行,控制台上每次只出现一个bar的打印,不会输出三次,once方法保证foo()只执行一次。

怎么保证只执行一次:

function once(fn)//形成外部闭包outer scape closure
{
    return function{...args}{//一个函数return另一个函数,称该函数为高阶函数。inner scope
    if(fn){
    //第一次调用时fn有值,会有返回值
        const ret=fn.apply(this,args);
        //调用函数,return
        fn=null;
        //之后fn变为null,不会有返回值,保证once返回方法只有一次
        return ret;
        }
    }
}
//抽象一个once的过程,使参数为函数,使这个函数里的任何一个函数只被调用一次。为了能够让"只执行一次"的需求覆盖不同的事件处理,我们可以将这个需求剥离出来。这个过程我们称为过程抽象。

高阶函数HOF

  • 以函数作为参数
  • 以函数作为返回值
  • 常用于作为函数装饰器

image.png

image.png

等价函数

常用高阶函数

  • Once
  • Throttle节流函数(鼠标移动moucemove事件,窗口滚动scroll事件)——事件触发多,带来相应的性能开销
  • Debounce防抖(自动保存)
  • Consumer/2
  • Iterative可迭代方法(Jquery

节流函数

image.png

限制频率。传一个fn函数,传一个节流频率(间隔时间),return一个新的function,这个function最开始timer为null,然后去设置一个timer,500ms之后再把timer设置为null,如果timer没有到500,是不会走进if语句中调用fn.apply,超市之后再点击才会实现fn

防抖

image.png

moucemove的时候debounce一个function,会让内容不变化,但在鼠标停止运动后会跟随鼠标到现在位置
function debounce(fn, dur){
    dur = dur || 100;
    var timer;
    return function(){
    //频繁调用的时候会清空timer
        clearTimeout(timer);
        //只有停止的时候才会调用
        tiner = setTimeout(()=>fn.apply(
        this,arguments),dur);
    }
}

consumer

image.png

每隔一个时间才去调用fn

consumer

image.png

实现连续点击,延时调用

可迭代方法

image.png

Jquery设计原则——同时操作多个元素。
function iterative(fn){
    return function(subjoct,...rest){
        if(isIterable(subjet)){
        //判断subject是否可迭代
            const ret=[];
            for(let obj of subject){
            //用subject里的每个函数调用fn方法
                ret.push(fn.applyithis,[obj, ...rest]);
                }
            return ret;
            }
     return fn.applyithis,[subject, ...rest]);
     //不可迭代只调用一次
     }
 }
//有了iterative函数能操作多个元素进行函数

纯函数与非纯函数

image.png

纯函数结果可预期,输入确定,输出确定,容易测试函数正确性。(高阶函数是纯函数)

非纯函数,会改变外部状态,需要构造特定环境,测试难度高,越多可度容信息差

使用高阶函数可以减少使用非纯函数

编程范式

命令式

声明式

三态

image.png

命令式

image.png

强调怎么做(写出具体做法)

声明式

image.png

定义一个double函数(更简洁),做什么

image.png

//命令式代码
switcher.onclick = function(evt){
    if(evt.target.className === 'on'){
        evt.target.className = 'off';
    }else{
        evt.target.className= 'on';
    }
}

//声明式实现
function toggle(...actions){//接收一系列actins
    return function(...args){
        let action =actions.shift();
        //取出第一个action放到最后一个
        actions.push(action);
        return action. apply(this, args);
        //调用当前取出的action
    }
}
switcher.onclick= toggle(
evt =>evt.target.className = 'off',
evt=>evt.target.className = 'on'
);
//在实现多个状态时,命令式需要添加多个逻辑代码,在声明式中只需要改个状态

总结:

  • 过程抽象/ HOF/装饰器
  • 命令式/声明式