vue3 API 笔迹

vue3 API 详解笔迹



createApp()

创建一个应用实例。

function createApp(rootComponent: Component, rootProps?: object): App

第一个参数是根组件。第二个参数可选,它是要传递给根组件的 props。
可以直接内联根组件:

import { createApp } from 'vue'

const app = createApp({
  /* 根组件选项 */
})

也可以使用从别处导入的组件:

import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

createSSRApp()

SSR 激活模式创建一个应用实例。用法与 createApp() 完全相同。
SSRServer Side Render的缩写,简单来讲:服务端渲染 就是网页上面呈现的内容在服务器端就已经生成好了,当用户浏览网页时,服务器把这个在服务端生成好的完整的html结构内容响应给浏览器,而浏览器拿到这个完整的html结构内容后直接显示(渲染)在页面上的过程。

app.mount()

将应用实例挂载在一个容器元素中。

interface App {
  mount(rootContainer: Element | string): ComponentPublicInstance
}

参数可以是一个实际的 DOM 元素或一个 CSS 选择器 (使用第一个匹配到的元素)。返回根组件的实例。

如果该组件有模板或定义了渲染函数,它将替换容器内所有现存的 DOM 节点。否则在运行时编译器可用的情况下,容器元素的 innerHTML 将被用作模板。

SSR 激活模式下,它将激活容器内现有的 DOM 节点。如果出现了激活不匹配,那么现有的 DOM 节点将会被修改以匹配客户端的实际渲染结果。

对于每个应用实例,mount() 仅能调用一次。

import { createApp } from 'vue'
const app = createApp(/* ... */)

app.mount('#app') || app.mount(document.body.firstChild)

app.unmount()

卸载一个已挂载的应用实例。卸载一个应用会触发该应用组件树内所有组件的卸载生命周期钩子。

const app =  createApp(App)
app.use(ElementPlus)
app.use(router)
app.use(pinia)
app.mount('#app')
let timer = setTimeout(()=>{
    app.unmount()
},2000)

app.component()

如果同时传递一个组件名字符串及其定义,则注册一个全局组件;如果只传递一个名字,则会返回用该名字注册的组件 (如果存在的话)。

import { createApp } from 'vue'

const app = createApp({})

// 注册一个选项对象
app.component('my-component', {
  /* ... */
})

// 得到一个已注册的组件
const MyComponent = app.component('my-component')

app.directive()

如果同时传递一个名字和一个指令定义,则注册一个全局指令;如果只传递一个名字,则会返回用该名字注册的指令 (如果存在的话)。

import { createApp } from 'vue'

const app = createApp({
  /* ... */
})

// 注册(对象形式的指令)
app.directive('my-directive', {
  /* 自定义指令钩子 */
})

// 注册(函数形式的指令)
app.directive('my-directive', () => {
  /* ... */
})

// 得到一个已注册的指令
const myDirective = app.directive('my-directive')

app.use()

安装一个插件
第一个参数应是插件本身,可选的第二个参数是要传递给插件的选项。

插件可以是一个带 install() 方法的对象,亦或直接是一个将被用作 install() 方法的函数。插件选项 (app.use() 的第二个参数) 将会传递给插件的 install()方法。

app.use() 对同一个插件多次调用,该插件只会被安装一次。

import { createApp } from 'vue'
import MyPlugin from './plugins/MyPlugin'

const app = createApp({
  /* ... */
})

app.use(MyPlugin)

app.mixin()

应用一个全局 mixin (适用于该应用的范围)。一个全局的 mixin 会作用于应用中的每个组件实例。
不推荐
MixinsVue 3 支持主要是为了向后兼容,因为生态中有许多库使用到。在新的应用中应尽量避免使用 mixin,特别是全局 mixin

若要进行逻辑复用,推荐用组合式函数来替代。

app.provide()

提供一个值,可以在应用中的所有后代组件中注入使用。
第一个参数应当是注入的 key,第二个参数则是提供的值。返回应用实例本身。

import { createApp } from 'vue'

const app = createApp(/* ... */)

app.provide('message', 'hello')
 let name = ref('name');
 function setName (str){
   name.value = str
 }

 provide('name',{name,setName})

app.runWithContext()

使用当前应用作为注入上下文执行回调函数。
App上增加了一个runWithContext()可以用于确保对应用程序级别的全局变量存在,比如通过provide的各个值,可以用于改进vue生态的各个包,pinia/vue-router之类的

需要一个回调函数并立即运行该回调。在回调同步调用期间,即使没有当前活动的组件实例,inject() 调用也可以从当前应用提供的值中查找注入。回调的返回值也将被返回。

import { inject } from 'vue'

app.provide('id', 1)

const injected = app.runWithContext(() => {
  return inject('id')
})

console.log(injected) // 1

app.version

提供当前应用所使用的 Vue 版本号。这在插件中很有用,因为可能需要根据不同的 Vue 版本执行不同的逻辑。

  console.log(app.version,'version')

app.config

每个应用实例都会暴露一个 config 对象,其中包含了对这个应用的配置设定。你可以在挂载应用前更改这些属性 (下面列举了每个属性的对应文档)。

import { createApp } from 'vue'

const app = createApp(/* ... */)

console.log(app.config)

app.config.errorHandler

用于为应用内抛出的未捕获错误指定一个全局处理函数。
错误处理器接收三个参数:错误对象、触发该错误的组件实例和一个指出错误来源类型信息的字符串。
它可以从下面这些来源中捕获错误:

  • 组件渲染器
  • 事件处理器
  • 生命周期钩子
  • setup() 函数
  • 侦听器
  • 自定义指令钩子
  • 过渡 (Transition) 钩子
app.config.errorHandler = (err, instance, info) => {
  // 处理错误,例如:报告给一个服务
}

app.config.warnHandler

用于为 Vue 的运行时警告指定一个自定义处理函数。

警告处理器将接受警告信息作为其第一个参数,来源组件实例为第二个参数,以及组件追踪字符串作为第三个参数。

这可以用户过滤筛选特定的警告信息,降低控制台输出的冗余。所有的 Vue 警告都需要在开发阶段得到解决,因此仅建议在调试期间选取部分特定警告,并且应该在调试完成之后立刻移除。

app.config.warnHandler = (msg, instance, trace) => {
  // `trace` 是组件层级结构的追踪
}

app.config.performance

设置此项为 true 可以在浏览器开发工具的“性能/时间线”页中启用对组件初始化、编译、渲染和修补的性能表现追踪。仅在开发模式和支持 performance.mark API 的浏览器中工作。

app.config.compilerOptions

配置运行时编译器的选项。设置在此对象上的值将会在浏览器内进行模板编译时使用,并会影响到所配置应用的所有组件。另外你也可以通过 compilerOptions 选项在每个组件的基础上覆盖这些选项。

此配置项仅在完整构建版本,即可以在浏览器中编译模板的 vue.js 文件中可用。如果你用的是带构建的项目配置,且使用的是仅含运行时的 Vue 文件版本,那么编译器选项必须通过构建工具的相关配置传递给 @vue/compiler-dom

  • vue-loader:通过 compilerOptions loader 的选项传递。并请阅读如何在 vue-cli 中配置它。
  • vite:通过 @vitejs/plugin-vue 的选项传递。

app.config.compilerOptions.isCustomElement

指定一个方法来识别 Vue 以外 (例如通过 Web Components API) 定义的自定义元素。如果一个组件匹配了这个条件,它就不需要在本地或全局注册,Vue 也不会抛出 Unknown custom element 的警告。

// 任何以 'ion-' 开头的元素都会被识别为自定义元素
app.config.compilerOptions.isCustomElement = tag => tag.startsWith('ion-')

app.config.compilerOptions.whitespace

默认情况下,Vue 会移除/压缩模板元素之间的空格以产生更高效的编译结果:

  • 元素内的多个开头/结尾空格会被压缩成一个空格
  • 元素之间的包括折行在内的多个空格会被移除
  • 文本结点之间可被压缩的空格都会被压缩成为一个空格
    将值设置为 preserve 可以禁用 (2) 和 (3)。
//默认 condense
app.config.compilerOptions.whitespace = 'preserve' 

app.config.compilerOptions.delimiters

用于配置模板内文本插值的分隔符。

这个选项一般会用于避免和同样使用双大括号语法的服务端框架发生冲突。

// 将分隔符设置为 ES6 模板字符串风格
app.config.compilerOptions.delimiters = ['${', '}'] 

app.config.compilerOptions.comments

默认情况下,Vue 会在生产环境下移除模板内的 HTML 注释。将这个选项设置为 true 可以强制 Vue 在生产环境下保留注释。而在开发环境下注释是始终被保留的。

这个选项一般会用于依赖 HTML 注释的其它库和 Vue 配合使用。

app.config.globalProperties

一个用于注册能够被应用内所有组件实例访问到的全局属性的对象。
这是对 Vue 2 Vue.prototype 使用方式的一种替代,此写法在 Vue 3 已经不存在了。与任何全局的东西一样,应该谨慎使用。

如果全局属性与组件自己的属性冲突,组件自己的属性将具有更高的优先级。

app.config.globalProperties.msg = 'hello'

在页面中获取globalProperties中的属性:

 

import { getCurrentInstance } from "vue";
const { appContext } = getCurrentInstance();

const callHello = ()=>{
 appContext.config.globalProperties.$hello('jay');
}

callHello() 

app.config.optionMergeStrategies

一个用于定义自定义组件选项的合并策略的对象。
一些插件或库对自定义组件选项添加了支持 (通过注入全局 mixin)。这些选项在有多个不同来源时可能需要特殊的合并策略 (例如 mixin 或组件继承)。

可以在 app.config.optionMergeStrategies 对象上以选项的名称作为 key,可以为一个自定义选项注册分配一个合并策略函数。

合并策略函数分别接受在父实例和子实例上定义的该选项的值作为第一和第二个参数。

defineComponent()

在定义 Vue 组件时提供类型推导的辅助函数。

// 选项语法
function defineComponent(
  component: ComponentOptions
): ComponentConstructor

// 函数语法 (需要 3.3+)
function defineComponent(
  setup: ComponentOptions['setup'],
  extraOptions?: ComponentOptions
): () => any

第一个参数是一个组件选项对象。返回值将是该选项对象本身,因为该函数实际上在运行时没有任何操作,仅用于提供类型推导。

注意返回值的类型有一点特别:它会是一个构造函数类型,它的实例类型是根据选项推断出的组件实例类型。这是为了能让该返回值在 TSX 中用作标签时提供类型推导支持。

你可以像这样从 defineComponent() 的返回类型中提取出一个组件的实例类型 (与其选项中的 this 的类型等价):

const Foo = defineComponent(/* ... */)

type FooInstance = InstanceType<typeof Foo>

函数签名

defineComponent() 还有一种备用签名,旨在与组合式 API渲染函数或 JSX 一起使用。

与传递选项对象不同的是,它需要传入一个函数。这个函数的工作方式与组合式 API 的 setup() 函数相同:它接收 propssetup 上下文。返回值应该是一个渲染函数——支持 h()JSX

import { ref, h } from 'vue'

const Comp = defineComponent(
  (props) => {
    // 就像在 <script setup> 中一样使用组合式 API
    const count = ref(0)

    return () => {
      // 渲染函数或 JSX
      return h('div', count.value)
    }
  },
  // 其他选项,例如声明 props 和 emits。
  {
    props: {
      /* ... */
    }
  }
)

defineAsyncComponent()

定义一个异步组件,它在运行时是懒加载的。参数可以是一个异步加载函数,或是对加载行为进行更具体定制的一个选项对象。

defineCustomElement()

这个方法和 defineComponent 接受的参数相同,不同的是会返回一个原生自定义元素类的构造器。
除了常规的组件选项,defineCustomElement() 还支持一个特别的选项 styles,它应该是一个内联 CSS 字符串的数组,所提供的 CSS 会被注入到该元素的 shadow root 上。

返回值是一个可以通过 customElements.define() 注册的自定义元素构造器。

setup()

setup() 钩子是在组件中使用组合式 API 的入口,通常只在以下情况下使用:

  • 需要在非单文件组件中使用组合式 API 时。
  • 需要在基于选项式 API 的组件中集成基于组合式 API 的代码时。

我们可以使用响应式 API 来声明响应式的状态,在 setup() 函数中返回的对象会暴露给模板和组件实例。其他的选项也可以通过组件实例来获取 setup() 暴露的属性:

<template>
  <p>{{ count }}</p>
  <button @click="handleAdd">handleAdd</button>
</template>

<script>
import {ref} from "vue";

export default {
  name: "page",
  setup() {
    let count = ref(0)
    const handleAdd = function () {
      count.value++
    }
    return {
      count, handleAdd
    }
  },

}
</script>

<style scoped>

</style>

在模板中访问从 setup 返回的 ref 时,它会自动浅层解包,因此你无须再在模板中为它写 .value。当通过 this 访问时也会同样如此解包。
setup() 自身并不含对组件实例的访问权,即在 setup() 中访问 this 会是 undefined。你可以在选项式 API中访问组合式 API 暴露的值,但反过来则不行。
setup() 应该同步地返回一个对象。唯一可以使用 async setup() 的情况是,该组件是 Suspense 组件的后裔。

访问 Props

setup 函数的第一个参数是组件的 props。和标准的组件一致,一个 setup 函数的 props 是响应式的,并且会在传入新的 props 时同步更新。

export default {
  props: {
    title: String
  },
  setup(props) {
    console.log(props.title)
  }
}

请注意如果你解构了 props 对象,解构出的变量将会丢失响应性。因此我们推荐通过 props.xxx 的形式来使用其中的 props
如果你确实需要解构 props 对象,或者需要将某个 prop 传到一个外部函数中并保持响应性,那么你可以使用 toRefs()toRef()这两个工具函数:

import { toRefs, toRef } from 'vue'

export default {
  setup(props) {
    // 将 `props` 转为一个其中全是 ref 的对象,然后解构
    const { title } = toRefs(props)
    // `title` 是一个追踪着 `props.title` 的 ref
    console.log(title.value)

    // 或者,将 `props` 的单个属性转为一个 ref
    const title = toRef(props, 'title')
  }
}

传入 setup 函数的第二个参数是一个 Setup 上下文对象。上下文对象暴露了其他一些在 setup 中可能会用到的值:

export default {
  setup(props, context) {
    // 透传 Attributes(非响应式的对象,等价于 $attrs)
    console.log(context.attrs)

    // 插槽(非响应式的对象,等价于 $slots)
    console.log(context.slots)

    // 触发事件(函数,等价于 $emit)
    console.log(context.emit)

    // 暴露公共属性(函数)
    console.log(context.expose)
  }
}

该上下文对象是非响应式的,可以安全地解构:

export default {
  setup(props, { attrs, slots, emit, expose }) {
    ...
  }
}

attrsslots 都是有状态的对象,它们总是会随着组件自身的更新而更新。这意味着你应当避免解构它们,并始终通过 attrs.xslots.x 的形式使用其中的属性。此外还需注意,和 props 不同,attrsslots 的属性都不是响应式的。如果你想要基于 attrsslots 的改变来执行副作用,那么你应该在 onBeforeUpdate 生命周期钩子中编写相关逻辑。

暴露公共属性

expose 函数用于显式地限制该组件暴露出的属性,当父组件通过模板引用访问该组件的实例时,将仅能访问 expose 函数暴露出的内容:

export default {
  setup(props, { expose }) {
    // 让组件实例处于 “关闭状态”
    // 即不向父组件暴露任何东西
    expose()

    const publicCount = ref(0)
    const privateCount = ref(0)
    // 有选择地暴露局部状态
    expose({ count: publicCount })
  }
}

与渲染函数一起使用

setup 也可以返回一个渲染函数,此时在渲染函数中可以直接使用在同一作用域下声明的响应式状态:
返回一个渲染函数将会阻止我们返回其他东西。对于组件内部来说,这样没有问题,但如果我们想通过模板引用将这个组件的方法暴露给父组件,那就有问题了。

我们可以通过调用 expose() 解决这个问题:

import { h, ref } from 'vue'

export default {
  setup(props, { expose }) {
    const count = ref(0)
    const increment = () => ++count.value

    expose({
      increment
    })

    return () => h('div', count.value)
  }
}

此时父组件可以通过模板引用来访问这个 increment 方法。

ref()

接受一个内部值,返回一个响应式的、可更改的 ref 对象,此对象只有一个指向其内部值的属性 .value
ref 对象是可更改的,也就是说你可以为 .value 赋予新的值。它也是响应式的,即所有对 .value 的操作都将被追踪,并且写操作会触发与之相关的副作用。

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

若要避免这种深层次的转换,请使用 shallowRef() 来替代。

const count = ref(0)
console.log(count.value) // 0

count.value++
console.log(count.value) // 1

computed()

接受一个 getter 函数,返回一个只读的响应式 ref 对象。该 ref 通过 .value 暴露 getter 函数的返回值。它也可以接受一个带有 getset 函数的对象来创建一个可写的 ref 对象。

const count = ref(1)
const plusOne = computed(() => count.value + 1)

console.log(plusOne.value) // 2

plusOne.value++ // 错误

创建一个可写的计算属性 ref:

const count = ref(1)
const plusOne = computed({
  get: () => count.value + 1,
  set: (val) => {
    count.value = val - 1
  }
})

plusOne.value = 1
console.log(count.value) // 0

调试:

const plusOne = computed(() => count.value + 1, {
  onTrack(e) {
    debugger
  },
  onTrigger(e) {
    debugger
  }
})

reactive()

返回一个对象的响应式代理。
响应式转换是“深层”的:它会影响到所有嵌套的属性。一个响应式对象也将深层地解包任何 ref 属性,同时保持响应性。

值得注意的是,当访问到某个响应式数组或 Map这样的原生集合类型中的 ref 元素时,不会执行 ref 的解包。

若要避免深层响应式转换,只想保留对这个对象顶层次访问的响应性,请使用 shallowReactive() 作替代。

返回的对象以及其中嵌套的对象都会通过 ES Proxy 包裹,因此不等于源对象,建议只使用响应式代理,避免使用原始对象。
创建一个响应式对象:

const obj = reactive({ count: 0 })
obj.count++

ref 的解包:

const count = ref(1)
const obj = reactive({ count })

// ref 会被解包
console.log(obj.count === count.value) // true

// 会更新 `obj.count`
count.value++
console.log(count.value) // 2
console.log(obj.count) // 2

// 也会更新 `count` ref
obj.count++
console.log(obj.count) // 3
console.log(count.value) // 3

注意当访问到某个响应式数组或 Map 这样的原生集合类型中的 ref 元素时,不会执行 ref 的解包:

const books = reactive([ref('Vue 3 Guide')])
// 这里需要 .value
console.log(books[0].value)

const map = reactive(new Map([['count', ref(0)]]))
// 这里需要 .value
console.log(map.get('count').value)

将一个 ref 赋值给一个 reactive 属性时,该 ref 会被自动解包:

const count = ref(1)
const obj = reactive({})

obj.count = count

console.log(obj.count) // 1
console.log(obj.count === count.value) // true

readonly()

接受一个对象 (不论是响应式还是普通的) 或是一个 ref,返回一个原值的只读代理。
只读代理是深层的:对任何嵌套属性的访问都将是只读的。它的 ref 解包行为与 reactive() 相同,但解包得到的值是只读的。

要避免深层级的转换行为,请使用 shallowReadonly() 作替代。

const original = reactive({ count: 0 })

const copy = readonly(original)

watchEffect(() => {
  // 用来做响应性追踪
  console.log(copy.count)
})

// 更改源属性会触发其依赖的侦听器
original.count++

// 更改该只读副本将会失败,并会得到一个警告
copy.count++ // warning!

watchEffect()

立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行。
第一个参数就是要运行的副作用函数。这个副作用函数的参数也是一个函数,用来注册清理回调。清理回调会在该副作用下一次执行前被调用,可以用来清理无效的副作用,例如等待中的异步请求 (参见下面的示例)。

第二个参数是一个可选的选项,可以用来调整副作用的刷新时机或调试副作用的依赖。

默认情况下,侦听器将在组件渲染之前执行。设置 flush: 'post' 将会使侦听器延迟到组件渲染之后再执行。详见回调的触发时机。在某些特殊情况下 (例如要使缓存失效),可能有必要在响应式依赖发生改变时立即触发侦听器。这可以通过设置 flush: 'sync' 来实现。然而,该设置应谨慎使用,因为如果有多个属性同时更新,这将导致一些性能和数据一致性的问题。

有时副作用函数会执行一些异步的副作用,这些响应需要在其失效时清除 (场景:有一个页码组件里面有5个页码,点击就会异步请求数据。于是做一个监听,监听当前页码,只要有变化就请求一次。问题:如果点击的比较快,从1到5全点了一遍,那么会有5个请求,最终页面会显示第几页的内容?第5页?那是假定请求第5页的ajax响应的最晚,事实呢?并不一定。于是这就会导致错乱。还有一个问题,连续快速点5次页码,等于我并不想看前4页的内容,那么是不是前4次的请求都属于带宽浪费?这也不好。
于是官方就给出了一种解决办法:
侦听副作用传入的函数可以接收一个 onInvalidate 函数作入参,用来注册清理失效时的回调。
当以下情况发生时,这个失效回调会被触发:

  • 侦听器被停止 (如果在 setup() 或生命周期钩子函数中使用了 watchEffect,则在组件卸载时)
  • 副作用即将重新执行时;
    返回值是一个用来停止该副作用的函数。
<template>
  <input type="text" v-model="obj.name">
  <button @click="handleStop">停止监听</button>
</template>

<script setup>
import {ref, defineAsyncComponent, onMounted, computed, reactive, shallowReactive, readonly, watchEffect} from "vue";
import DemoBox from '@/components/DemoBox/index.vue'
const obj = reactive({name:'张三'})
const storeName =  watchEffect(()=>{
  console.log(obj,'obj')
  console.log(obj.name,'obj.name')
})
function handleStop(){
  //关闭
  storeName()
}
</script>

<style scoped>

</style>

watchPostEffect()

watchEffect() 使用 flush: 'post' 选项时的别名。

watchSyncEffect()

watchEffect() 使用 flush: 'sync' 选项时的别名。

watch()

侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。
watch() 默认是懒侦听的,即仅在侦听源发生变化时才执行回调函数。

第一个参数是侦听器的源。这个来源可以是以下几种:

  • 一个函数,返回一个值
  • 一个 ref
  • 一个响应式对象
  • …或是由以上类型的值组成的数组

第二个参数是在发生变化时要调用的回调函数。这个回调函数接受三个参数:新值、旧值,以及一个用于注册副作用清理的回调函数。该回调函数会在副作用下一次重新执行前调用,可以用来清除无效的副作用,例如等待中的异步请求。

当侦听多个来源时,回调函数接受两个数组,分别对应来源数组中的新值和旧值。

  • immediate:在侦听器创建时立即触发回调。第一次调用时旧值是 undefined
  • deep:如果源是对象,强制深度遍历,以便在深层级变更时触发回调。
  • flush:调整回调函数的刷新时机。
  • onTrack / onTrigger:调试侦听器的依赖。

watchEffect() 相比,watch() 使我们可以:

  • 懒执行副作用;
  • 更加明确是应该由哪个状态触发侦听器重新执行;
  • 可以访问所侦听状态的前一个值和当前值。
<template>
  <input type="text" v-model="obj.name">
  <input type="text" v-model="str">
  {{obj.name}}
</template>

<script setup>
import {
  ref,
  defineAsyncComponent,
  onMounted,
  computed,
  reactive,
  shallowReactive,
  readonly,
  watchEffect,
  watch
} from "vue";
import DemoBox from '@/components/DemoBox/index.vue'
const obj = reactive({name:'张三'})
const str = ref(0)
// watch(obj,(newVal,oldVal)=>{
//   console.log(newVal,oldVal)
// })
// watch(()=>obj.name,(newVal,oldVal)=>{
//   console.log(newVal,oldVal)
// })
watch([()=>obj.name,str],([newVal1,newVal2],[oldVal1,oldVal2])=>{
  console.log(newVal1,oldVal1,'reactive')
  console.log(newVal2,oldVal2,'ref')
})
</script>

<style scoped>

</style>

停止侦听器

const stop = watch(source, callback)

// 当已不再需要该侦听器时:
stop()

副作用清理:

watch(id, async (newId, oldId, onCleanup) => {
  const { response, cancel } = doAsyncWork(newId)
  // 当 `id` 变化时,`cancel` 将被调用,
  // 取消之前的未完成的请求
  onCleanup(cancel)
  data.value = await response
})

isRef()

检查某个值是否为 ref
请注意,返回值是一个类型判定 (type predicate),这意味着 isRef 可以被用作类型守卫:

const obj = reactive({name:'张三'})
const str = ref(0)
 
console.log(isRef(str)) true
console.log(isRef(obj)) false

unref()

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

const obj = reactive({name:'张三'})
const str = ref(0)

console.log(unref(str)) 0 
console.log(unref(obj)) {   "name": "张三" }

toRef()

可以将refsgetters 规范化为 refs (3.3+)

也可以基于响应式对象上的一个属性,创建一个对应的 ref。这样创建的 ref 与其源属性保持同步:改变源属性的值将更新 ref的值,反之亦然。
在这里插入图片描述

<template>
  <input type="text" v-model="obj.name">
  {{obj.name}}--{{obj1}}--{{obj2}}--{{obj3}}
</template>

<script setup>
import {
  reactive, toRef
} from "vue";
const obj = reactive({name:'张三'})
const obj1 = toRef(obj,'name')
const obj2 = toRef(obj.name)
const obj3 = toRef(()=>obj.name)
obj1.value = '李四'


obj.name='王五'
console.log(obj.name,'obj')
console.log(obj1,'obj1')

console.log(obj2)
</script>

toValue()

值、refs 或 getters 规范化为值。这与 unref() 类似,不同的是此函数也会规范化 getter 函数。如果参数是一个 getter,它将会被调用并且返回它的返回值。

这可以在组合式函数中使用,用来规范化一个可以是值、refgetter 的参数。


 const str1 = ref('123')
 console.log(str1)
 console.log(toValue(str1))

在这里插入图片描述

toRefs()

将一个响应式对象转换为一个普通对象,这个普通对象的每个属性都是指向源对象相应属性的 ref。每个单独的 ref 都是使用 toRef() 创建的。

  • template 要想访问 toRefs 的值,需要带上 .value 如果不带上,就会出现双引号。
  • template 要想访问 toRef 的值,不需要带上 .value
<template>
  {{arr.name}}--{{arr1}}--{{arr2.name.value}}
</template>

<script setup>
import {reactive, ref, toRef, toRefs, toValue} from "vue";

 const str1 = ref('123')
 const arr = reactive({name:'张三'})
const arr1 = toRef(arr,'name')
const arr2 = toRefs(arr)
</script>

<style scoped>

</style>

在这里插入图片描述

isProxy()

检查一个对象是否是由 reactive()readonly()shallowReactive()shallowReadonly() 创建的代理。

const str1 = ref('123')
 const arr = reactive({name:'张三'})
  const str2 = readonly(ref(23))
const str3 = shallowReactive(reactive({name:'李四'}))
const str4 =  shallowReadonly(ref(45))
let str5 = 5
console.log(isProxy(str1))
console.log(isProxy(arr))
console.log(isProxy(str2))
console.log(isProxy(str3))
console.log(isProxy(str4))
console.log(isProxy(str5))

在这里插入图片描述

​isReactive()

检查一个对象是否是由 reactive() shallowReactive() 创建的代理。

isReadonly()

检查传入的值是否为只读对象。只读对象的属性可以更改,但他们不能通过传入的对象直接赋值。

通过 readonly()shallowReadonly() 创建的代理都是只读的,因为他们是没有 set 函数的 computed() ref

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值