vue3 中 Ref 简单数据类型监听与依赖触发

根据源码抽离了部分ref 实现简单数据类型双向绑定的原理,不考虑引用类型

1. 先创建RefImpl 实例

    1> 通过 get 和 set 关键字可以使函数 value() 触发的方式调整为 .value 的形式触发

    2> 通过实例中定义的 __v_isRef 变量判断是否为RefImpl 实例数据

    3> dep 用来缓存当前实例的 effect ,用于记录依赖与触发依赖,当数据改变从而刷新视图

class RefImpl {
			__v_isRef = true;
			dep = new Set();

			constructor(value) {
				this._value = value;
			}

			get value() {
				// 收集依赖
				trackRefValue(this);
				return this._value;
			}

			set value(newValue) {
				// 判断值是否发生改变
				if (!Object.is(newValue, this._value)) {
					this._value = newValue;
                    // 触发依赖
					triggerRefValue(this);
				}
			}
		}
2. 定义 ref 函数

    定义 ref 函数 如果是 <script> 中方便直接export 将该方法暴露出去


    function isRef(value) {
		return value && value.__v_isRef;
	}


	function ref(value) {
        // 用于判断入参是否为RefImfl数据 如果是则直接返回
		if (isRef(value)) {
			return value;
		}

        // 否则生成一个 RefImfl 实例
		return new RefImpl(value);
	}

	const flag = ref(true);

3. 定义 ReactiveEffect 实例与 effect函数

class ReactiveEffect {
	constructor(fn) {
		this.fn = fn;
	}

	run() {
		activeEffect = this;
		return this.fn();
	}
}

function effect(fn) {
	const effect = new ReactiveEffect(fn);
	effect.run();
}

effect(() => {
	const creatDiv = `<div class='test'>${flag.value ? "是" : "否"}</div>`;
	app.innerHTML = creatDiv;
});

4. 收集依赖与触发依赖的函数

	// 用于收集依赖
    function trackRefValue(ref) {
		if (activeEffect) {
			ref.dep.add(activeEffect);
		}
	}


    // 用于触发依赖
	function triggerRefValue(ref) {
		ref.dep.forEach((effect) => {
			effect.run();
		});
	}

5. 全部实现代码(不包含引用数据类型)

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>ref 简单数据类型监听</title>
	</head>
	<body>
		<div id="app"></div>
	</body>
	<script>
		const app = document.getElementById("app");
		let activeEffect; // 缓存执行函数

		class RefImpl {
			__v_isRef = true;
			dep = new Set();

			constructor(value) {
				this._value = value;
			}

			get value() {
				// 收集依赖
				trackRefValue(this);
				return this._value;
			}

			set value(newValue) {
				// 判断值是否发生改变
				if (!Object.is(newValue, this._value)) {
					this._value = newValue;
					triggerRefValue(this);
				}
			}
		}

		function isRef(value) {
			return value && value.__v_isRef;
		}

		function ref(value) {
			if (isRef(value)) {
				return value;
			}

			return new RefImpl(value);
		}
		const flag = ref(true);

		class ReactiveEffect {
			constructor(fn) {
				this.fn = fn;
			}

			run() {
				activeEffect = this;
				return this.fn();
			}
		}

		function effect(fn) {
			const effect = new ReactiveEffect(fn);
			effect.run();
		}

		effect(() => {
			const creatDiv = `<div class='test'>${flag.value ? "是" : "否"}</div>`;
			app.innerHTML = creatDiv;
		});

		function trackRefValue(ref) {
			if (activeEffect) {
				ref.dep.add(activeEffect);
			}
		}

		function triggerRefValue(ref) {
			ref.dep.forEach((effect) => {
				effect.run();
			});
		}

		setInterval(() => {
			flag.value = !flag.value;
		}, 1000);
	</script>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值