如何监听一个变量值的变化

如何监听一个变量值的变化

_
响应式系统架构:
┌─────────────────────────────────────────────────────────┐
│                    响应式状态管理器                        │
├─────────────────────────────────────────────────────────┤
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐   │
│  │   Watcher   │    │    Proxy    │    │ watchEffect │   │
│  │  (监听器)   │◄──►│ (代理对象)  │◄──►│  (副作用)   │   │
│  └─────────────┘    └─────────────┘    └─────────────┘   │
└─────────────────────────────────────────────────────────┘
           │                    │                    │
           ▼                    ▼                    ▼
┌─────────────────────────────────────────────────────────┐
│                     应用层                               │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐   │
│  │  Vue组件   │    │ React组件   │    │  普通JS代码  │   │
│  └─────────────┘    └─────────────┘    └─────────────┘   │
└─────────────────────────────────────────────────────────┘

Watcher - 监听器

基本概念

Watcher是观察者模式的具体实现,用于监听数据变化并执行相应操作。

核心作用

  • 监听特定数据的变化

  • 数据变化时自动执行回调

  • 实现数据和视图的自动同步

Proxy - 代理对象

基本概念

Proxy是ES6提供的元编程特性,可以拦截并自定义对象的操作。

核心特性

  • 拦截对象的所有操作(读取、设置、删除等)

  • 深度监听对象变化

  • 不需要遍历对象属性

 watchEffect - 副作用监听

基本概念

watchEffect是Vue 3的Composition API,用于自动追踪依赖的副作用函数。

核心特点

  • 自动收集依赖,无需指定监听属性

  • 立即执行一次

  • 依赖变化时自动重新执行

Vue.js 中的监听

1. watch 选项

export default {
  data() {
    return {
      count: 0,
      user: {
        name: '张三',
        age: 25
      }
    }
  },
  
  watch: {
    // 简单监听
    count(newVal, oldVal) {
      console.log('count 变化:', oldVal, '→', newVal);
    },
    
    // 对象深度监听
    user: {
      handler(newVal, oldVal) {
        console.log('user 变化:', newVal);
      },
      deep: true,  // 深度监听
      immediate: true  // 立即执行一次
    },
    
    // 监听对象的特定属性
    'user.name'(newVal, oldVal) {
      console.log('用户名变化:', oldVal, '→', newVal);
    }
  }
}

2. watchEffect

import { ref, watchEffect } from 'vue'

const count = ref(0);
const name = ref('张三');

// 自动追踪依赖
watchEffect(() => {
  console.log(`监听: count=${count.value}, name=${name.value}`);
});

// 当 count 或 name 变化时,自动重新执行
count.value = 10;  // 触发
name.value = '李四'; // 触发

3. watch API (Vue 3 Composition API)

import { ref, watch, reactive } from 'vue'

const count = ref(0);
const state = reactive({ name: '张三', age: 25 });

// 监听单个 ref
watch(count, (newVal, oldVal) => {
  console.log('count 变化:', oldVal, '→', newVal);
});

// 监听 getter 函数
watch(() => state.name, (newVal, oldVal) => {
  console.log('name 变化:', oldVal, '→', newVal);
});

// 监听多个源
watch([count, () => state.name], ([newCount, newName], [oldCount, oldName]) => {
  console.log('批量监听:', { newCount, newName, oldCount, oldName });
});

4.响应式状态管理器

class ReactiveStore {
  constructor(initialState = {}) {
    this.state = new Proxy(initialState, {
      set: (target, property, value) => {
        const oldValue = target[property];
        target[property] = value;
        this.notify(property, value, oldValue);
        return true;
      }
    });
    this.watchers = {};
  }
  
  watch(property, callback) {
    if (!this.watchers[property]) {
      this.watchers[property] = [];
    }
    this.watchers[property].push(callback);
  }
  
  notify(property, newValue, oldValue) {
    if (this.watchers[property]) {
      this.watchers[property].forEach(callback => callback(newValue, oldValue));
    }
  }
}

// 使用
const store = new ReactiveStore({ count: 0 });
store.watch('count', (newVal, oldVal) => {
  console.log('store.count 变化:', oldVal, '→', newVal);
});
store.state.count = 5;

前端构建工具-Vite、Webpack、ESLint、Prettier 2024-06-22
Vue组件Props传参 2024-06-18

评论区