基础知识 | 基础知识(一)

简介: 数据双向绑定

image.png

1.数据双向绑定

观察者模式,数据的双向绑定,手写一个基本的数据双向绑定,通过使用 defineProperty 去实现数据的双向绑定。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>数据双向绑定</title>
  </head>

  <body>
    <input type="text" id="input" />
    <span id="output"></span>
  </body>
  <script>
    // 定义一个数据对象
    const userInfo = {};
    // 获取输入框
    const input = document.getElementById("input");
    // 当输入框输入的时候赋值,更新视图到数据上
    input.oninput = () => {
      userInfo.name = input.value;
    };
    // 获取输出的dom
    const output = document.getElementById("output");
    // 更新数据到视图
    Object.defineProperty(userInfo, "name", {
      get: () => {
        console.log("get", userInfo);
      },
      set: (val) => {
        output.innerHTML = val;
        input.value = val;
        console.log("set", val);
      },
    });
</script>
</html>

2.事件总线程

源码:

class EventBus {
  constructor() {
    this.eventContainer = this.eventContainer || new Map(); //用一个容器存放事件
  }
  on(type, callback) {
    if (!this.eventContainer.has(type)) {
      //如果容器里面没有这种类型的事件,就增加
      this.eventContainer.set(type, callback);
    }
  }
  off(type) {
    if (this.eventContainer.has(type)) {
      this.eventContainer.delete(type);
    }
  }
  emit(type) {
    let fn = this.eventContainer.get(type);
    fn.apply(this, [...arguments].slice(1));
  }
}

es5 手写:

思路:事件队列存在很对的事件名称,所以创建的事件队列是一个对象。

订阅事件,首先判断事件队列里面是否含有该事件名称,没有的话就创建一个,将订阅的事件加入队列。

订阅一次事件,在订阅事件的基础之上,首先执行一次回调,然后取消订阅即可。

发布事件,如果存在传入的事件名称,则遍历队列中该事件名称的所有事件,并给事件传入对应参数。

取消订阅,如果存在传入的事件名称,则删除本事件。

class EventBus {
  constructor() {
    // 创建事件队列,因为可能会存在很多的eventbus,所以使用对象的形式,键为名,值为函数。
    this.tasks = {};
  }
  /**
   * 订阅事件
   * @param {String} type 事件名称
   * @param {Function} fn 回调函数
   */
  on(type, fn) {
    // 如果事件队列中不包含传入的type类型,则需要创建一个。
    if (!this.tasks[type]) {
      this.tasks[type] = [];
    }
    // 如果事件队列中存在,则将回调函数加入队列
    this.tasks[type].push(fn);
  }
  /**
   * 订阅一次的事件
   * @param {String} type
   * @param {Function} fn
   */
  once(type, fn) {
    // 如果事件队列中不包含传入的type类型,则需要创建一个。
    if (!this.tasks[type]) {
      this.tasks[type] = [];
    }
    const _this = this;
    // 只执行一次,然后注销移除回调
    const _once = (...args) => {
      fn(...args);
      _this.off(type, _once);
    };
    this.tasks[type].push(_once);
  }
  /**
   * 发布事件
   * @param {String} type 事件名称
   * @param  {...any} args 传入的参数
   * @returns
   */
  emit(type, ...args) {
    // 如果队列中不存在传入的type时候,则不执行任何操作
    if (!this.tasks[type]) {
      return;
    }
    // 如果队列中含有传入的type时,遍历队列中的函数,并传入参数
    this.tasks[type].forEach((fn) => fn(...args));
  }
  /**
   * 取消订阅
   * @param {String} type 事件名称
   * @param {Function} fn 回调函数
   * @returns
   */
  off(type, fn) {
    const tasks = this.tasks[type];
    // 如果队列中不存在传入的type时候,则不执行任何操作
    if (!Array.isArray(tasks)) {
      return;
    }
    // 利用 filter 删除队列中的指定函数
    this.tasks[type] = tasks.filter((cb) => fn !== cb);
  }
}

使用:

let eventBus = new EventBus();
eventBus.on("testEvent", (name) => {
  setTimeout(() => {
    console.log("This is a", name);
  }, 1000);
});
eventBus.emit("testEvent", "testEvent");
相关文章
|
6月前
|
缓存 安全 SoC
GICV2&GICV3的基础知识
GICV2&GICV3的基础知识
190 0
|
存储 编解码 监控
视频基础知识 3
视频基础知识
149 0
|
3月前
|
存储 监控 安全
安全基础知识
【8月更文挑战第9天】
39 1
|
6月前
|
机器学习/深度学习 人工智能 大数据
一些基础知识
了解人工智能基础,探索AI系统如何结合算法、机器学习和数据分析模拟人类智能。从 Siri 和 Alexa 的语音助手到 Netflix 的个性化推荐,AI已深入日常生活中。查阅《人工智能入门手册(AI101)》深入学习,同时参考《抖音百科》和《大数据》拓宽知识领域。
|
存储 编解码 索引
视频基础知识 2
视频基础知识
61 0
|
存储 编解码 算法
视频基础知识 1
视频基础知识
203 0
|
存储 Web App开发 SQL
基础知识
基础知识
106 0
|
编译器 C++
C++模板基础知识
本文将讲述C++模板初阶的相关知识。
145 1
前后台交互基础知识
在别人造的轮子上飞奔的时候,轮子背后的前后台交互如何进行一脸懵$.
72 0
|
安全 编译器 程序员
【C++】C++基础知识
其中 { } 内容即为命名空间的成员,注意最后右花括号后不用加分号结尾。