searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Javascript在函数内部实现对数据的监听

2023-07-12 09:55:42
37
0

       观察者(Observer)模式的定义是指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新,目前主流的对数据监听的方案是基于观察者模式进行的。在知名前端框架Vue中,Vue2实现观察者模式的一个核心方法则是Javascript的Object。defineProperty方法,进一步实现数据的监听。

       Object.defineProperty方法传入三个参数,第一个参数为要添加或改变属性的对象,第二个参数为属性的名称,第三个参数为要定义或修改属性的函数,其中最为重要的是get函数和set函数,其中get函数用于表示该属性被访问时的回调函数,set函数用于表示该属性被修改时的回调函数。

let obj = {
  key1: 1,
  key2: 2,
  key3: 3,
};

Object.defineProperty(obj, "key1", {
  get() {
    console.log(`obj对象的key1属性被访问了`);
  },
  set(newVal) {
    if (newVal !== val) {
      val = newVal;
      console.log(`obj对象的key1属性被更新了`);
      update(); //此处填写更新后的操作
    }
  },
});

       在Vue3版本,对于复杂类型数据的监听主要采用Object.Proxy方法来实现观察者模式,当使用watch函数时,Vue3会创建一个Proxy对象来包裹被观察的对象。

let p = new Proxy(target, {
    get(target, property, receiver) {
        console.log(`${target}的${property}属性被访问了`)
    },
    set(target, property, value, receiver) {
       console.log(`${target}的${property}属性被设置为了${value}`)
    }
 });

在Vue中使用watch能够实现对于数据的监听功能,但是有些场景下,仅通过watch函数并不能完成我们想要的功能。例如如果想在一个函数内部实现对一个变量的监听,当变量未发生变化时,程序要求在当前位置阻塞,直到变量发生变化时,程序才能往下进行,这种情景下,使用watch函数并不能满足要求,我们就需要自己写一个监听函数来实现我们当前的场景。

       为了达到在函数内部阻塞的要求,需要使用Promise对象,而为了达到监听的效果,可以使用setInterval启用定时器来循环监视变量的值是否变化。

const watchPromise = (variable, oldVal) => {
  return new Promise((resolve, reject) => {
    try {
      const intervalId = setInterval(() => {
        if (variable !== oldVal) {
          //监听对象的值变化后,取消定时器,并且将目前的值resolve出去
          clearInterval(intervalId);
          resolve(variable);
        }
      }, 100);
    } catch (err) {
      reject(err);
    }
  });
};

该函数传入两个参数,第一个参数为要监听的变量,第二个参数为变量的当前值。在函数内部启用了Promise和定时器,每间隔100ms对变量进行一次监听(间隔时间可以自定义),当监听到对象的值变化后,将定时器取消,并将修改后的值resolve出去,使外部函数接收。

        但是上述函数有个问题,就是只支持基本数据类型的监听,如果要监听引用类型,如对象、数组等,需要将函数改造一下。loadsh库提供了一个isEqual方法判断两个变量是否相等,该方法不仅支持基本类型,也支持引用类型的判断因此将上述监听函数进行一下改造,使用isEqual来判断变量前后的变化。

import _ from "loadsh"
const watchPromise = (variable, oldVal) => {
  return new Promise((resolve, reject) => {
    try {
      const intervalId = setInterval(() => {
        if (!_.isEqual(variable, oldVal)) {
          //监听对象的值变化后,取消定时器,并且将目前的值resolve出去
          clearInterval(intervalId);
          resolve(variable);
        }
      }, 100);
    } catch (err) {
      reject(err);
    }
  });
};

监听函数写完后,下面来看一个实际例子。在项目中,经常会遇到确认框来确认用户的操作,确认框有两个状态,分别是"确认"和"取消",当一个函数内部需要打开确认框来确认函数是否执行的时候,就需要采用上述的监听函数。

let confirmDialogVisible = false;
let confirmTag = "";  //确认框状态,点击"确认"为true,点击"取消"或关闭窗体为false,什么都不操作为空字符串
const showConfirmDialog = () => {
  confirmDialogVisible = true;
  confirmTag = "";
};
//实际运行的函数
const run =async () => {
  showConfirmDialog()   //打开对话框
  let canGoNext=""
  try{
    const res= await watchPromise(confirmTag,"")  //监听confirmTag状态变为true或false(用户操作确认框)
    confirmTag="" //重置确认框状态
    canGoNext = res   //将确认框状态返回
  }catch(err){
    return err
  }
  if(canGoNext){
    nextFunc()    //用户点击确认后要执行的函数,点击取消或不操作不进入该函数
  }
};

其中confirmTag表示确认框状态,点击"确认"为true,点击"取消"或关闭窗体为false,什么都不操作为空字符串。run为实际运行的函数,打开对话框后调用watchPromise方法,对confirmTag变量进行持续监听,当弹出确认框并且用户进行确认后(即confirmTag状态变为true),才能执行后续的代码。

0条评论
0 / 1000
赵****喆
2文章数
0粉丝数
赵****喆
2 文章 | 0 粉丝
赵****喆
2文章数
0粉丝数
赵****喆
2 文章 | 0 粉丝
原创

Javascript在函数内部实现对数据的监听

2023-07-12 09:55:42
37
0

       观察者(Observer)模式的定义是指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新,目前主流的对数据监听的方案是基于观察者模式进行的。在知名前端框架Vue中,Vue2实现观察者模式的一个核心方法则是Javascript的Object。defineProperty方法,进一步实现数据的监听。

       Object.defineProperty方法传入三个参数,第一个参数为要添加或改变属性的对象,第二个参数为属性的名称,第三个参数为要定义或修改属性的函数,其中最为重要的是get函数和set函数,其中get函数用于表示该属性被访问时的回调函数,set函数用于表示该属性被修改时的回调函数。

let obj = {
  key1: 1,
  key2: 2,
  key3: 3,
};

Object.defineProperty(obj, "key1", {
  get() {
    console.log(`obj对象的key1属性被访问了`);
  },
  set(newVal) {
    if (newVal !== val) {
      val = newVal;
      console.log(`obj对象的key1属性被更新了`);
      update(); //此处填写更新后的操作
    }
  },
});

       在Vue3版本,对于复杂类型数据的监听主要采用Object.Proxy方法来实现观察者模式,当使用watch函数时,Vue3会创建一个Proxy对象来包裹被观察的对象。

let p = new Proxy(target, {
    get(target, property, receiver) {
        console.log(`${target}的${property}属性被访问了`)
    },
    set(target, property, value, receiver) {
       console.log(`${target}的${property}属性被设置为了${value}`)
    }
 });

在Vue中使用watch能够实现对于数据的监听功能,但是有些场景下,仅通过watch函数并不能完成我们想要的功能。例如如果想在一个函数内部实现对一个变量的监听,当变量未发生变化时,程序要求在当前位置阻塞,直到变量发生变化时,程序才能往下进行,这种情景下,使用watch函数并不能满足要求,我们就需要自己写一个监听函数来实现我们当前的场景。

       为了达到在函数内部阻塞的要求,需要使用Promise对象,而为了达到监听的效果,可以使用setInterval启用定时器来循环监视变量的值是否变化。

const watchPromise = (variable, oldVal) => {
  return new Promise((resolve, reject) => {
    try {
      const intervalId = setInterval(() => {
        if (variable !== oldVal) {
          //监听对象的值变化后,取消定时器,并且将目前的值resolve出去
          clearInterval(intervalId);
          resolve(variable);
        }
      }, 100);
    } catch (err) {
      reject(err);
    }
  });
};

该函数传入两个参数,第一个参数为要监听的变量,第二个参数为变量的当前值。在函数内部启用了Promise和定时器,每间隔100ms对变量进行一次监听(间隔时间可以自定义),当监听到对象的值变化后,将定时器取消,并将修改后的值resolve出去,使外部函数接收。

        但是上述函数有个问题,就是只支持基本数据类型的监听,如果要监听引用类型,如对象、数组等,需要将函数改造一下。loadsh库提供了一个isEqual方法判断两个变量是否相等,该方法不仅支持基本类型,也支持引用类型的判断因此将上述监听函数进行一下改造,使用isEqual来判断变量前后的变化。

import _ from "loadsh"
const watchPromise = (variable, oldVal) => {
  return new Promise((resolve, reject) => {
    try {
      const intervalId = setInterval(() => {
        if (!_.isEqual(variable, oldVal)) {
          //监听对象的值变化后,取消定时器,并且将目前的值resolve出去
          clearInterval(intervalId);
          resolve(variable);
        }
      }, 100);
    } catch (err) {
      reject(err);
    }
  });
};

监听函数写完后,下面来看一个实际例子。在项目中,经常会遇到确认框来确认用户的操作,确认框有两个状态,分别是"确认"和"取消",当一个函数内部需要打开确认框来确认函数是否执行的时候,就需要采用上述的监听函数。

let confirmDialogVisible = false;
let confirmTag = "";  //确认框状态,点击"确认"为true,点击"取消"或关闭窗体为false,什么都不操作为空字符串
const showConfirmDialog = () => {
  confirmDialogVisible = true;
  confirmTag = "";
};
//实际运行的函数
const run =async () => {
  showConfirmDialog()   //打开对话框
  let canGoNext=""
  try{
    const res= await watchPromise(confirmTag,"")  //监听confirmTag状态变为true或false(用户操作确认框)
    confirmTag="" //重置确认框状态
    canGoNext = res   //将确认框状态返回
  }catch(err){
    return err
  }
  if(canGoNext){
    nextFunc()    //用户点击确认后要执行的函数,点击取消或不操作不进入该函数
  }
};

其中confirmTag表示确认框状态,点击"确认"为true,点击"取消"或关闭窗体为false,什么都不操作为空字符串。run为实际运行的函数,打开对话框后调用watchPromise方法,对confirmTag变量进行持续监听,当弹出确认框并且用户进行确认后(即confirmTag状态变为true),才能执行后续的代码。

文章来自个人专栏
文章 | 订阅
0条评论
0 / 1000
请输入你的评论
0
0