你知道为什么template中不用加.value吗?

Vue3 中定义的ref类型的变量,在setup中使用这些变量是需要带上.value才可以访问,但是在template中却可以直接使用。

询其原因,可能会说 Vue 自动进行ref解包了,那具体如何实现的呢?

你知道为什么template中不用加.value吗?

proxyRefs

其实 Vue3 中有个方法proxyRefs,这属于底层 API 方法,在官方文档中并没有阐述,但是 Vue 里是可以导出这个方法。

例如:

<script setup>
import { onMounted, proxyRefs, ref } from "vue";

const user = {
  name: "wendZzoo",
  age: ref(18),
};
const _user = proxyRefs(user);

onMounted(() => {
  console.log(_user.name);
  console.log(_user.age);
  console.log(user.age);
});
</script>

上面代码定义了一个普通对象user,其中age属性的值是ref类型。当访问age值的时候,需要通过user.age.value,而使用了proxyRefs,可以直接通过user.age来访问。

你知道为什么template中不用加.value吗?

这也就是为何template中不用加.value的原因,Vue3 源码中使用proxyRefs方法将setup返回的对象进行处理。

实现proxyRefs

单测

it("proxyRefs"() => {
  const user = {
    name: "jack",
    age: ref(10),
  };
  const proxyUser = proxyRefs(user);

  expect(user.age.value).toBe(10);
  expect(proxyUser.age).toBe(10);

  proxyUser.age = 20;
  expect(proxyUser.age).toBe(20);
  expect(user.age.value).toBe(20);

  proxyUser.age = ref(30);
  expect(proxyUser.age).toBe(30);
  expect(user.age.value).toBe(30);
});

定义一个age属性值为ref类型的普通对象userproxyRefs方法需要满足:

  1. proxyUser直接访问age是可以直接获取到 10 。
  2. 当修改proxyUserage值切这个值不是ref类型时,proxyUser和原数据user都会被修改。
  3. age值被修改为ref类型时,proxyUseruser也会都更新。

实现

既然是访问和修改对象内部的属性值,就可以使用Proxy来处理getset。先来实现get

export function proxyRefs(objectWithRefs{
  return new Proxy(objectWithRefs, {
    get(target, key) {}
  });
}

需要实现的是proxyUser.age能直接获取到数据,那原数据target[key]ref类型,只需要将ref.value转成value

使用unref即可实现,unref的实现参见本专栏上篇文章《Vue3源码中isRef & unref 也就两行代码》

get(target, key) {
  return unref(Reflect.get(target, key));
}

实现set

export function proxyRefs(objectWithRefs{
  return new Proxy(objectWithRefs, {
    get(target, key) {
      return unref(Reflect.get(target, key));
    },
    set(target, key, value) {},
  });
}

从单侧中可以看出,我们是测试了两种情况,一种是修改proxyUserageref类型, 一种是修改成不是ref类型的,但是结果都是同步更新proxyUseruser。那实现上也需要考虑这两种情况,需要判断原数据值是不是ref类型,新赋的值是不是ref类型。

使用isRef可以判断是否为ref类型,isRef的实现参见本专栏上篇文章《Vue3源码中isRef & unref 也就两行代码》

set(target, key, value) {
  if (isRef(target[key]) && !isRef(value)) {
    return (target[key].value = value);
  } else {
    return Reflect.set(target, key, value);
  }
}

当原数据值是ref类型且新赋的值不是ref类型,也就是单测中第 1 个情况赋值为 10,将ref类型的原值赋值为valueref类型值需要.value访问;否则,也就是单测中第 2 个情况,赋值为ref(30),就不需要额外处理,直接赋值即可。

验证

执行单测yarn test ref

你知道为什么template中不用加.value吗?

点个在看 ⬇ 感谢感谢

原文始发于微信公众号(前端一起学):你知道为什么template中不用加.value吗?

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/191242.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!