Vue Ref全家桶具体用法详解

 更新时间:2023年03月09日 09:58:44   作者:剑九 六千里  
ref用来辅助我们获取DOM元素或组件的引用实例对象,每个vue的组件实例上,都包含一个refs对象,里面存储着对应的DOM元素或组件的引用,默认情况下,组件的refs指向一个空对象

1. ref

在Vue3中,ref成为了一个全家桶,除了用于创建响应式数据之外,还可以用于引用DOM元素、组件实例和其他对象。以下是ref的具体用法:

1.1. 创建响应式数据

我们可以使用ref函数来创建响应式数据,例如:

<template>
  <div>{{ count }}</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const count = ref(0)
console.log(count.value) // 输出 0
count.value += 1
console.log(count.value) // 输出 1
</script>
<style scoped>
</style>

注意被ref包装之后需要.value 来进行赋值

在这个例子中,我们使用ref函数来创建一个响应式数据count,初始值为0。我们可以使用count.value来访问和修改这个值。

1.2. 引用DOM元素

我们可以使用ref函数来引用DOM元素,例如:

<template>
  <div ref="container"></div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
const container = ref(null) // 注意:此处的变量名必须和标签上的属性名一致
onMounted(() => {
  console.log(container.value) // 输出 <div></div>
})
</script>
<style scoped>
</style>

在这个例子中,我们使用ref函数来创建一个container引用,然后在模板中使用ref="container"来将这个引用绑定到一个<div>元素上。在setup函数中,我们使用onMounted钩子来访问这个引用的值。

1.3. 引用组件实例

我们可以使用ref函数来引用组件实例,例如:

<template>
  <Child ref="child" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import Child from './Child.vue'
const child = ref(null)
</script>
<style scoped>
</style>

在这个例子中,我们使用ref函数来创建一个child引用,然后将这个引用绑定到一个<Child>组件上。在script中,我们将这个引用暴露出去,以便在其他地方使用。

1.4. 引用其他对象

除了DOM元素和组件实例之外,我们还可以使用ref函数来引用其他对象,例如:

<template>
  <Child ref="child" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
const data = { name: 'John' }
const obj = ref(data)
console.log(obj.value.name) // 输出 'John'
obj.value.name = 'Mary'
console.log(data.name) // 输出 'Mary'
<script>
<style scoped>
</style>

在这个例子中,我们使用ref函数来引用一个对象data,然后将这个引用赋值给一个obj变量。我们可以使用obj.value来访问和修改这个对象。在这个例子中,我们将obj.value.name修改为Mary,然后发现data.name也被修改了。

1.5. ref源码

在Vue3中,ref函数的源码如下:

import { isObject } from '@vue/shared'
import { ReactiveFlags, reactive } from './reactive'
export function ref(value) {
  // 如果value已经是一个ref对象,直接返回它
  if (isRef(value)) {
    return value
  }
  // 创建一个响应式对象
  let valueIsObject = isObject(value)
  const ref = {
    // 标记这个对象是一个ref对象
    [ReactiveFlags.IS_REF]: true,
    // 获取ref的值
    get value() {
      // 如果value是一个对象,则返回一个响应式对象
      if (valueIsObject) {
        return reactive(value)
      }
      return value
    },
    // 设置ref的值
    set value(newVal) {
      if (valueIsObject) {
        value = newVal
        valueIsObject = isObject(newVal)
        return
      }
      // 如果value是一个基本类型的值,则直接修改它
      value = newVal
    }
  }
  return ref
}

在这个源码中,ref函数首先会判断传入的值是否已经是一个ref对象,如果是则直接返回它,否则会创建一个响应式对象来作为ref对象的值。然后ref函数会返回一个拥有value属性的对象,当读取这个属性时,如果它的值是一个对象,则会返回一个响应式对象,否则直接返回它的值;当修改这个属性时,如果它的值是一个对象,则会将新值转化为响应式对象,否则直接修改它的值。

2. isRef

在Vue3中,isRef函数用于判断一个对象是否为ref对象,它通过判断这个对象是否拥有一个特殊的属性IS_REF来进行判断。这个特殊属性的值为true,表示这个对象是一个ref对象。

2.1. isRef的使用

<template>
  <div class="wrapper"></div>
</template>
<script setup lang="ts">
import { isRef, ref } from 'vue';
const name: string = '张三';
console.log(isRef(name)); // false
const age = ref(10);
console.log(isRef(age)); // true
</script>
<style scoped>
</style>

2.2. isRef源码

// 判断一个对象是否为ref对象
export function isRef(r) {
  return Boolean(r && r[ReactiveFlags.IS_REF])
}

3. shallowRef

在Vue3中shallowRef函数,用于创建一个“浅层”的响应式对象。

ref函数不同的是,shallowRef函数不会将其值转化为响应式对象,而是直接将其作为普通的对象或数组来处理。这意味着,当修改shallowRef对象的属性或数组的元素时,Vue3将不会追踪这些变化。这种“浅层”的响应式对象对于一些不需要完全响应式的场景非常有用,例如缓存一些数据或跟踪某些状态。

3.1. shallowRef的使用

下面是一个使用shallowRef函数的示例:

<template>
  <div>{{ obj.name }}</div>
</template>
<script setup lang="ts">
import { shallowRef } from 'vue'
const obj = { name: 'John', age: 30 }
const ref = shallowRef(obj)
console.log(ref.value.name) // 输出 'John'
ref.value.name = 'Mary'
console.log(obj.name) // 输出 'Mary'
</script>
<style scoped>
</style>

在这个示例中,我们使用shallowRef函数来创建一个“浅层”的响应式对象ref,并将其值设置为obj对象。当我们修改ref.value.name属性的值时,obj.name属性的值也发生了改变。这是因为obj对象和ref对象共享同一个引用。

3.2. shallowRef的源码

在Vue3中,shallowRef函数的源码如下:

import { isObject, toRawType } from '@vue/shared'
import { track, trigger } from './effect'
import { ReactiveFlags } from './reactive'
const shallowGet = (value) => value
const shallowSet = () => {
  console.warn(
    `Value assigned to a shallow ref ${String(value)} is not reactive, ` +
    `expecting explicitly passing deep: true in ref() options`
  )
}
class ShallowRefImpl {
  public readonly __v_isRef = true
  public readonly [ReactiveFlags.IS_SHALLOW] = true
  constructor(public _value) {}
  get value() {
    track(this, 'get', 'value')
    return this._value
  }
  set value(newValue) {
    if (newValue !== this._value) {
      this._value = newValue
      trigger(this, 'set', 'value', newValue)
    }
  }
}
export function shallowRef(value) {
  return new ShallowRefImpl(value)
}
export function isShallowRef(value) {
  return !!value[ReactiveFlags.IS_SHALLOW]
}

shallowRef函数会创建一个ShallowRefImpl对象,并将传入的值作为其内部的_value属性的值。ShallowRefImpl对象是一个带有getset方法的普通对象,当读取value属性时,get方法会返回_value属性的值;当修改value属性时,set方法会将新值赋值给_value属性,并触发相应的依赖。

4.triggerRef

强制更新DOM

4.1. triggerRef的使用

triggerRef的使用非常简单,只需要传递一个Ref对象作为参数即可。例如:

import { ref, triggerRef } from 'vue'
const count = ref(0)
// 在某些情况下需要手动更新count,可以使用triggerRef
triggerRef(count)

在这个例子中,我们使用ref函数创建了一个名为count的响应式引用,它的初始值为0。然后我们在某些情况下需要手动更新count,这时我们可以使用triggerRef函数来触发它的更新。

需要注意的是,当使用triggerRef函数触发更新时,它只会更新Ref对象本身,而不会更新与之相关联的组件。因此,我们应该在明确知道需要手动更新时使用triggerRef函数,而在普通情况下使用Vue自身的响应式系统来自动更新相关组件。

4.2. triggerRef的源码实现

在Vue3中,triggerRef函数用于触发一个ref对象的依赖更新。其源码如下:

import { effect } from './effect'
import { track, trigger } from './operations'
export function triggerRef(ref) {
  if (ref.__v_isRef) {
    const value = ref.value
    if (isTracking()) {
      track(ref, 'set', 'value')
    }
    ref.value = value
    trigger(ref, 'set', 'value', value)
  } else {
    console.warn(`triggerRef() expects a ref object passed as its argument.`)
  }
}

在这个源码中,首先判断传入的对象是否为ref对象,如果是则获取它的值,并使用track函数追踪这个ref对象的依赖。然后将这个ref对象的值赋值给它自己的value属性,并使用trigger函数触发这个ref对象的依赖更新。如果传入的对象不是ref对象,则会输出一个警告信息。

5. customRef

在 Vue 3 中,提供了一个 customRef 函数,用于创建一个自定义的、可响应的引用对象。与 refshallowRef 不同的是,customRef 可以自定义 getset 方法的实现逻辑,从而实现更加灵活的响应式行为。

使用 customRef 函数创建的引用对象与 ref 对象类似,也具有 value 属性,当读取这个属性时,会触发 get 方法的执行;当修改这个属性时,会触发 set 方法的执行,并且会触发相应的依赖更新。与 ref 对象不同的是,customRef 函数本身并不会对传入的初始值进行处理,而是将其直接作为 get 方法的返回值,需要自己手动处理。

下面是 customRef 函数的使用示例:

5.1. customRef使用

import { customRef } from 'vue'
const myRef = customRef((track, trigger) => ({
  value: 0,
  get() {
    track()
    return this.value
  },
  set(newValue) {
    this.value = newValue
    trigger()
  }
}))
console.log(myRef.value) // 输出 0
myRef.value = 1
console.log(myRef.value) // 输出 1

在这个示例中,使用 customRef 函数创建了一个自定义的引用对象 myRef,它的 get 方法用于追踪依赖,返回 value 属性的值;set 方法用于修改 value 属性的值,并触发相应的依赖更新。当读取和修改 myRef 对象的 value 属性时,会分别触发它的 getset 方法。

注意:customRef 函数的参数是一个函数,这个函数接收两个参数,分别是 tracktrigger 函数,它们用于追踪依赖和触发依赖更新。

5.2. customRef 函数的源代码

import { track, trigger } from './effect'
export function customRef(factory) {
  const ref = {
    __v_isRef: true,
    get value() {
      return factory().get()
    },
    set value(newValue) {
      factory().set(newValue)
    }
  }
  return ref
}
export function triggerRef(ref) {
  trigger(ref, 'set', 'value', ref.value)
}

在这个源码中,定义了一个 customRef 函数,它接收一个工厂函数作为参数,用于创建一个自定义的引用对象。在函数内部,创建了一个普通的对象 ref,它有一个只读的 __v_isRef 属性,用于标识它是一个 ref 对象;还有一个名为 value 的属性,用于存储引用对象的值,并且在读取和修改时会触发工厂函数的 getset 方法。在 customRef 函数的最后,返回这个 ref 对象。

总结:这篇文章介绍了Vue3中的ref函数、isRef函数、shallowRef函数和customRef函数。ref函数主要用于创建响应式对象,引用DOM实例,引用组件实例等。isRef函数主要用于判断传入的数据是不是响应式对象。shallowRef函数创建一个“浅层”的响应式对象,只追踪值的属性变化,而不追踪对象内部属性的变化。customRef函数可以创建自定义的引用对象,可以自定义getset方法的实现逻辑。此外,文章还介绍了triggerRef函数,用于触发ref对象的依赖更新。

到此这篇关于Vue Ref全家桶具体用法详解的文章就介绍到这了,更多相关Vue Ref内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Element Plus暗黑模式及模式自由切换的实现

    Element Plus暗黑模式及模式自由切换的实现

    本文详细介绍了如何在使用Vite构建的Vue项目中实现ElementPlus暗黑模式及模式切换,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-11-11
  • vue异步加载高德地图的实现

    vue异步加载高德地图的实现

    这篇文章主要介绍了vue异步加载高德地图的实现,详细的介绍了异步加载的实现方法。小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-06-06
  • vue项目中跳转到外部链接的实例讲解

    vue项目中跳转到外部链接的实例讲解

    今天小编就为大家分享一篇vue项目中跳转到外部链接的实例讲解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-09-09
  • 在vue中安装使用sass的实现方法

    在vue中安装使用sass的实现方法

    这篇文章主要介绍了在vue中安装使用sass的实现方法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • vue如何动态实时的显示时间浅析

    vue如何动态实时的显示时间浅析

    这篇文章主要给大家介绍了关于vue如何动态实时的显示时间,以及vue时间戳 获取本地时间实时更新的相关资料,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05
  • vue-router传递参数的几种方式实例详解

    vue-router传递参数的几种方式实例详解

    vue-router传递参数分为两大类,一类是编程式的导航 router.push另一类是声明式的导航 <router-link>,本文通过实例代码给大家介绍vue-router传递参数的几种方式,感兴趣的朋友跟随小编一起看看吧
    2018-11-11
  • vue实现跨页面定位锚点区域方式

    vue实现跨页面定位锚点区域方式

    这篇文章主要介绍了vue实现跨页面定位锚点区域方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • vue打包部署到springboot并通过tomcat运行的操作方法

    vue打包部署到springboot并通过tomcat运行的操作方法

    这篇文章主要介绍了vue打包部署到springboot并通过tomcat运行的操作方法,本文通过实例图文并茂的形式给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2024-05-05
  • Vue如何通过浏览器控制台查看全局data值

    Vue如何通过浏览器控制台查看全局data值

    在写vue项目时想到一个问题,项目里面的文件都是一个个的组件,如何在控制台中修改,查看组件data里的值呢,下面这篇文章主要给大家介绍了关于Vue如何通过浏览器控制台查看全局data值的相关资料,需要的朋友可以参考下
    2023-04-04
  • vue实现列表无缝滚动

    vue实现列表无缝滚动

    这篇文章主要为大家详细介绍了vue实现列表无缝滚动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06

最新评论