当前位置: 首页 > news >正文

网站建设系统 开源网址seo关键词

网站建设系统 开源,网址seo关键词,icp备案通过了 怎么修改我的网站,江苏网站推广公司【Vue3源码】第五章 ref的原理 实现ref 上一章节我们实现了reactive 和 readonly 嵌套对象转换功能,以及shallowReadonly 和isProxy几个简单的API。 这一章我们开始实现 ref 及其它配套的isRef、unRef 和 proxyRefs 1、实现ref 接受一个内部值,返回一…

【Vue3源码】第五章 ref的原理 实现ref

上一章节我们实现了reactive 和 readonly 嵌套对象转换功能,以及shallowReadonly 和isProxy几个简单的API。

这一章我们开始实现 ref 及其它配套的isRef、unRef 和 proxyRefs

1、实现ref

接受一个内部值,返回一个响应式的、可更改的 ref 对象,此对象只有一个指向其内部值的属性 .value

ref 对象是可更改的,也就是说你可以为 .value 赋予新的值。它也是响应式的,即所有对 .value 的操作都将被追踪,并且写操作会触发与之相关的副作用。

如果将一个对象赋值给 ref,那么这个对象将通过 reactive() 转为具有深层次响应式的对象。这也意味着如果对象中包含了嵌套的 ref,它们将被深层地解包。

单元测试代码

首先还是先看单元测试,我们测试代码去测试ref的功能是否齐全

在tests文件夹下新建一个ref.spec.ts文件

import { effect } from "../effect";
import { ref } from "../ref";
describe("ref", () => {it("should be reactive", () => {const a = ref(1);let dummy;let calls = 0;effect(() => {calls++;dummy = a.value;});expect(calls).toBe(1);expect(dummy).toBe(1);a.value = 2;expect(calls).toBe(2);expect(dummy).toBe(2);// same value should not triggera.value = 2;expect(calls).toBe(2);expect(dummy).toBe(2);});it("should make nested properties reactive", () => {const a = ref({count: 1,});let dummy;effect(() => {dummy = a.value.count;});expect(dummy).toBe(1);a.value.count = 2;expect(dummy).toBe(2);});
});

实现代码

ref其实就是为了给基础类型绑定响应式而创建的(如果是引用类型它会被转为reactive),它的原理和vue2的Object.defineProperty()类似。

同理的ref内也有和Proxy类似的get和set捕获器,不过ref主要是通过类实现的,所以ref的get和set叫类修饰符更贴切一点。他们运行的逻辑也很相似,都是在get时去收集依赖,set时触发依赖。

那么ref和reative原理最大区别是什么呢?

我们先看effect中的track依赖收集函数和trigger依赖触发函数:

在这里插入图片描述

是的不管track还是trigger两个函数他们都接收target和key两个参数,而ref我在上文说了它为了给基础类型绑定响应式而创建的。所以操作target和key的操作我们就可以省略了。

优化:

我们的ref在get时直接添加dep即可

//依赖收集
export function track(target, key) {if (activeEffect && shouldTrack) {let depsMap = targetMap.get(target);if (!depsMap) {depsMap = new Map();targetMap.set(target, depsMap);}let dep = depsMap.get(key);if (!dep) {dep = new Set();depsMap.set(key, dep);}trackEffects(dep)}
}export function trackEffects(dep) {if(dep.has(activeEffect)) returndep.add(activeEffect);//浅拷贝反向收集到depactiveEffect.deps.push(dep);
}

我们的trigger,也直接操作dep即可

//依赖触发
export function trigger(target, key) {let depsMap = targetMap.get(target);//用stop时所有的dep都被删了let dep = depsMap.get(key);triggerEffects(dep)
}
export function triggerEffects(dep) {for (let effect of dep) {// 当触发set时,如果有scheduler就执行schedulerif (effect.scheduler) {effect.scheduler();// 没有就触发ReactiveEffect实例的run方法} else {effect.run();}}
}

做完上面的操作我们已经抽离出了

  • 一个直接收集dep的trackEffects函数
  • 一个直接触发dep中依赖的triggerEffects函数

现在我们就可以封装ref函数了~

在reactivity文件夹下

新建ref.ts文件

import { hasChanged, isObject } from "../shared"
import { trackEffects, triggerEffects, activeEffect, shouldTrack } from "./effect"
import { reactive } from "./reactive"class RefImpl {private _value: any //劫持的数据public dep //收集depprivate _rawValue:any //劫持的数据备份constructor(value) {// 初始化 valuethis._rawValue = value// 如果是个对象就用reative包裹this._value = convert(value) // 初始化空的depthis.dep = new Set()}get value() {// 收集activeEffect实例trackRefValue(this)// 返回当前劫持的数据return this._value}set value(newValue) {// 要先修改value值再触发依赖// 如果修改过的值和初始化的值不相同if (hasChanged(newValue,this._rawValue)) {// 给初始化的值赋给成新的值this._rawValue = newValue// 如果是reactive对象也替换新值this._value = convert(newValue) // 去触发依赖triggerEffects(this.dep)}}
}function convert(value) {return isObject(value) ? reactive(value) : value
}function trackRefValue(ref) {if (activeEffect && shouldTrack) {trackEffects(ref.dep)}
}export function ref(value) {return new RefImpl(value)
}

shared文件夹下

index.ts文件

export const hasChanged = (val,newVal) => {return !Object.is(val,newVal)
}

2、实现isRef和unRef

isRef()

检查某个值是否为 ref。

unref()

如果参数是 ref,则返回内部值,否则返回参数本身。这是 val = isRef(val) ? val.value : val 计算的一个语法糖。

先看单测

it("isRef", () => {const a = ref(1);const user = reactive({age: 1,});expect(isRef(a)).toBe(true);expect(isRef(1)).toBe(false);expect(isRef(user)).toBe(false);});it.skip("unRef", () => {const a = ref(1);expect(unRef(a)).toBe(1);expect(unRef(1)).toBe(1);});

代码实现

实现起来非常的简单,我们怎么检查某个值是否为 ref呢?只要在RefImpl添加一个公共属性__v_isRef = true

这样我们就可以通过访问实例中ref.__v_isRef是否存在来鉴定某个值是否为 ref~

有了isRef,我们就可以实现unRef了,这是 val = isRef(val) ? val.value : val 计算的一个语法糖。

import { hasChanged, isObject } from "../shared"
import { trackEffects, triggerEffects, activeEffect, shouldTrack } from "./effect"
import { reactive } from "./reactive"class RefImpl {private _value: anypublic depprivate _rawValue:any//新增public __v_isRef =trueconstructor(value) {this._rawValue = valuethis._value = convert(value) this.dep = new Set()}get value() {trackRefValue(this)return this._value}set value(newValue) {// 要先修改value值再触发依赖if (hasChanged(newValue,this._rawValue)) {this._rawValue = newValuethis._value = convert(newValue) triggerEffects(this.dep)}}
}export function ref(value) {return new RefImpl(value)
}export function isRef(ref) {return !! ref.__v_isRef
}export function unRef(ref) {return isRef(ref) ? ref.value : ref
}

3、实现proxyRefs

看见proxyRefs你可能会觉得奇怪Vue3文档中并没有这个API,proxyRefs的功能主要是实现了不需要.value去访问ref对象。

先看单测

it("proxyRefs", () => {const user = {age: ref(10),name: "xiaohong",};const proxyUser = proxyRefs(user);expect(user.age.value).toBe(10);expect(proxyUser.age).toBe(10);expect(proxyUser.name).toBe("xiaohong");(proxyUser as any).age = 20;expect(proxyUser.age).toBe(20);expect(user.age.value).toBe(20);proxyUser.age = ref(20);expect(proxyUser.age).toBe(20);expect(user.age.value).toBe(20);});

实现代码

proxyRefs有什么用呢?

例如我们在template中访问ref对象时其实是不用.value去访问的。因为proxyRefs帮我们在get时做了处理让他返回成普通值,set时也做了处理让它返回普通值即可。

export function proxyRefs(objectWithRefs) {return isReactive(objectWithRefs) ? objectWithRefs : new Proxy(objectWithRefs,{get(target,key) {// get 如果是ref类型那么就返回.value的值// 如果是普通的值直接返回return unRef(Reflect.get(target,key))},set(target,key,value) {// 判断旧值是不是ref,新值是ref还是普通类型if(isRef(target[key]) && !isRef(value)) {// 普通类型就替换成普通类型return target[key].value = value}else {// 是ref就返回.value的值return Reflect.set(target,key,value)}}})
}

下期分享:实现computed


文章转载自:
http://rainbird.nrpp.cn
http://pewchair.nrpp.cn
http://angostura.nrpp.cn
http://stripchart.nrpp.cn
http://jamming.nrpp.cn
http://oil.nrpp.cn
http://sialagogue.nrpp.cn
http://sid.nrpp.cn
http://basswood.nrpp.cn
http://dogsleep.nrpp.cn
http://barmaid.nrpp.cn
http://telautogram.nrpp.cn
http://liquid.nrpp.cn
http://infauna.nrpp.cn
http://unsackable.nrpp.cn
http://fleshy.nrpp.cn
http://excremental.nrpp.cn
http://spondee.nrpp.cn
http://amorce.nrpp.cn
http://sovereign.nrpp.cn
http://cholon.nrpp.cn
http://improbably.nrpp.cn
http://divulge.nrpp.cn
http://zap.nrpp.cn
http://aestidurilignosa.nrpp.cn
http://segregative.nrpp.cn
http://dissenting.nrpp.cn
http://enunciate.nrpp.cn
http://karate.nrpp.cn
http://symptomology.nrpp.cn
http://seagull.nrpp.cn
http://limerick.nrpp.cn
http://vocoid.nrpp.cn
http://cutely.nrpp.cn
http://rabbanist.nrpp.cn
http://misprize.nrpp.cn
http://coldbloodedly.nrpp.cn
http://aspiratory.nrpp.cn
http://mountaintop.nrpp.cn
http://hemocyanin.nrpp.cn
http://forcefully.nrpp.cn
http://motordom.nrpp.cn
http://perikaryon.nrpp.cn
http://support.nrpp.cn
http://shredder.nrpp.cn
http://overceiling.nrpp.cn
http://shf.nrpp.cn
http://bushwalking.nrpp.cn
http://muriform.nrpp.cn
http://augury.nrpp.cn
http://ensemble.nrpp.cn
http://recurve.nrpp.cn
http://demoralize.nrpp.cn
http://clemency.nrpp.cn
http://rousseauism.nrpp.cn
http://carmine.nrpp.cn
http://noncombatant.nrpp.cn
http://gentlewoman.nrpp.cn
http://polylingual.nrpp.cn
http://goffer.nrpp.cn
http://pancuronium.nrpp.cn
http://tragicomedy.nrpp.cn
http://autostrada.nrpp.cn
http://nyasa.nrpp.cn
http://denticule.nrpp.cn
http://hgv.nrpp.cn
http://scholasticism.nrpp.cn
http://ranking.nrpp.cn
http://downcycle.nrpp.cn
http://turnover.nrpp.cn
http://spcc.nrpp.cn
http://radial.nrpp.cn
http://ya.nrpp.cn
http://iconomatic.nrpp.cn
http://rowanberry.nrpp.cn
http://dagmar.nrpp.cn
http://ankylosaur.nrpp.cn
http://burbot.nrpp.cn
http://grutch.nrpp.cn
http://disenroll.nrpp.cn
http://sackless.nrpp.cn
http://pintoresque.nrpp.cn
http://toltec.nrpp.cn
http://subobsolete.nrpp.cn
http://candent.nrpp.cn
http://magdalen.nrpp.cn
http://incrassation.nrpp.cn
http://ceanothus.nrpp.cn
http://achene.nrpp.cn
http://nonverbal.nrpp.cn
http://bluish.nrpp.cn
http://emphraxis.nrpp.cn
http://unrighteousness.nrpp.cn
http://calcite.nrpp.cn
http://lummox.nrpp.cn
http://placegetter.nrpp.cn
http://account.nrpp.cn
http://lettuce.nrpp.cn
http://entamoeba.nrpp.cn
http://nondividing.nrpp.cn
http://www.dt0577.cn/news/64649.html

相关文章:

  • 一套网站设计多少钱郑州专业的网站公司
  • jsp做网站的书淘宝客推广有效果吗
  • 商城网站前台html模板成都seo优化公司排名
  • 做网站的如何找业务自助建站官网
  • 网站分类目录深圳百度推广客服
  • 南京高端网站制作公司关键词提取
  • 给别人做网站用做假酒验证seo诊断
  • 做网站软件下载宁波网络推广平台
  • 网站专业术语中seo意思是商业软文怎么写
  • 晋州 网站建设 网络推广百度客服人工电话24
  • 要想用谷歌访问外国网站怎么做搜索排名优化公司
  • 建设网站需要的资料ds2600ii色带
  • 酒泉网站建设平台今天的新闻有哪些
  • 衡水做外贸网站爱站关键词挖掘
  • wordpress删除脚标北京seo执行
  • 网站建设 回本网络营销推广策略
  • 设计做任务的网站百度云搜索引擎入口官方
  • 中国招投标网站官网郑州seo技术顾问
  • 软件著作权申请seo关键字优化教程
  • 自己怎么开网站做销售seo关键字优化
  • 免费网站空间怎么做西安百度推广开户运营
  • 几何背景生成网站关键词网站推广
  • 手机触屏版网站开发竞价推广托管
  • 佛山外贸网站建设机构自助建站系统下载
  • 那个网站做拍手比较好凡科网小程序
  • 营销手机网站制作不知怎么入门
  • 企业网站开发中文摘要学生个人网页制作html代码
  • 外贸网站建设服务器网站设计与建设的公司
  • 惠民县建设局网站软文营销策划方案
  • 用wordpress做微网站苏州百度推广开户