一、Application Config(app.config)
config是一个包含Vue应用程序全局配置的对象。可以在挂载应用程序之前修改下面列出的属性:
const app = Vue.createApp({})
app.config = {...}
1、devtools
- 类型: boolean
- 默认值: true (false in production builds)
- 使用:
app.config.devtools = true
配置是否允许vue-devtools检查。此选项的默认值在开发版本中为true,在生产版本中为false。您可以将其设置为true以启用对生产版本的检查。
2、errorHandler
- 类型: Function
- 默认值: undefined
- 使用:
app.config.errorHandler = (err, vm, info) => {
// handle error
// info是Vue特定的错误信息,例如 在哪个生命周期挂钩中发现错误
}
为组件渲染功能和观察程序期间的未捕获错误分配处理程序。
3、warnHandler
- 类型: Function
- 默认值: undefined
- 使用:
app.config.warnHandler = function(msg, vm, trace) {
// trace是组件层次结构跟踪
}
为运行时Vue警告分配自定义处理程序。这仅在开发期间有效,在生产中将被忽略。
4、globalProperties 全局属性
- 类型: [key: string]: any
- 默认值: undefined
- 使用:
app.config.globalProperties.foo = 'bar'
app.component('child-component', {
mounted() {
console.log(this.foo) // 'bar'
}
})
冲突时,组件的属性将具有优先权
在 vue2.x 中是 Vue.prototype
// 2.x
Vue.prototype.$http = () => {}
// 3.x
const app = Vue.createApp({})
app.config.globalProperties.$http = () => {}
5、isCustomElement
- 类型: (tag: string) => boolean
- 默认值: undefined
- 使用:
app.config.isCustomElement = tag => tag.startsWith('ion-')
指定一种方法来识别在Vue之外定义的自定义元素(例如,使用Web组件API)。 如果component符合此条件,则不需要本地或全局注册,并且Vue不会发出有关Unknown自定义元素的警告。
此功能不需要匹配所有HTML和SVG标签,Vue解析器会自动执行此检查
6、optionMergeStrategies
- 类型: { [key: string]: Function }
- 默认值: {}
- 使用:
const app = Vue.createApp({
mounted() {
console.log(this.$options.hello)
}
})
app.config.optionMergeStrategies.hello = (parent, child, vm) => {
return `Hello, ${child}`
}
app.mixin({
hello: 'Vue'
})
// 'Hello, Vue
自定义选项定义合并策略。
合并策略将分别在父实例和子实例上定义的该选项的值作为第一个参数和第二个参数。 上下文应用程序实例作为第三个参数传递。
7、performance
- 类型: boolean
- 默认值: false
- 使用:
app.config.performance = true
将其设置为true可在浏览器devtool性能/时间线面板中启用组件初始化,编译,渲染和补丁性能跟踪。 仅在开发模式和支持Performance.mark API的浏览器中工作。
二、Application API(app.xxx)
在Vue 3.x,全局改变Vue行为的API都在createApp方法所创建的应用程序实例中
import { createApp } from 'vue'
const app = createApp({})
1、component
- 参数:
- {string} name
- {Function | Object} definition (optional)
- 返回值:
- 如果传递定义参数,则为应用程序实例
- 如果没有传递定义参数,则为组件
- 使用:
- 注册或检索全局组件。 注册还会使用给定的name参数自动设置组件的名称。
import { createApp } from 'vue'
const app = createApp({})
// 注册一个 options 对象
app.component('my-component', {
/* ... */
})
// 检索注册的组件
const MyComponent = app.component('my-component')
2、config
包含应用程序配置的对象。(往上翻)
3、directive
-
参数:
- {string} name
- {Function | Object} definition (optional)
-
生命周期:
app.directive('my-directive', {
// 挂载前
beforeMount() {},
// 挂载后
mounted() {},
// 更新前
beforeUpdate() {},
// 更新后
updated() {},
// 卸载前
beforeUnmount() {},
// 卸载后
unmounted() {}
})
生命周期钩子函数所具有的参数
1、el
绑定的DOM元素
2、binding
- instance:使用伪指令的组件的实例。
- value:传递给指令的值。
- oldValue:以前的值,仅在beforeUpdate和updated中可用。
- arg:传递给指令的参数。
- modifiers:包含修饰符的对象。
- dir:一个对象,在注册指令时作为参数传递。
3、vnode
绑定的DOM所对应的虚拟节点
4、prevNode
之前的虚拟节点,仅在beforeUpdate和updated中可用
除el之外,您应该将这些参数视为只读,并且永远不要修改它们。
示例 自定义 drag 拖动指令
import { createApp } from 'vue'
import App from './App.vue'
let app = createApp(App)
app.directive('drag', {
beforeMount (el, binding) {
console.log(el, binding)
let oDiv = el; //当前元素
oDiv.onmousedown = function (e) {
//鼠标按下,计算当前元素距离可视区的距离
let disX = e.clientX - oDiv.offsetLeft;
let disY = e.clientY - oDiv.offsetTop;
document.onmousemove = function (e) {
//通过事件委托,计算移动的距离
let l = e.clientX - disX;
let t = e.clientY - disY;
//移动当前元素
oDiv.style.left = l + 'px';
oDiv.style.top = t + 'px';
//将此时的位置传出去
binding.value({x:e.pageX,y:e.pageY}, el)
};
document.onmouseup = function () {
document.onmousemove = null;
document.onmouseup = null;
};
};
}
})
app.mount('#app')
template中使用
<template>
<div v-drag="dragFun" class="div1"></div>
</template>
<script>
export default {
setup() {
let dragFun = (val, e) => {
console.log(val, e)
// val 是 在binging.value 的值
// e 是对应的element元素
}
return {
dragFun
}
}
}
</script>
4、mixin
- 参数: {Object} mixin
- 使用:
在整个应用范围内应用mixin。一旦注册,它们就可以在当前应用程序中任何组件的模板中使用。
5、mount
- 参数:
- {Element | string} rootContainer
- {boolean} isHydrate (optional)
挂载到跟组件上
import { createApp } from 'vue'
const app = createApp({})
app.mount('#app')
6、provide
- 参数:
- {string | Symbol} key
- value
设置一个可以注入到应用程序内组件中的值。组件应使用注入来接收提供的值。
provide 和 inject 不是反应性的
import {provide} from 'vue'
setup() {
provide('city', '杭州')
provide('person', {
name: 'Bob',
age: 18
})
}
7、inject
- 参数:
- {string | Symbol} key
- 没有获取到时的默认值
import {inject} from 'vue'
setup() {
let city = inject('city')
let person = inject('person')
let noProvide = inject('noProvide', 'noProvide hah')
}
8、unmount
- 参数: {Element | string} rootContainer
卸载
import { createApp } from 'vue'
const app = createApp({})
app.mount('#app')
// 5 秒钟之后卸载
setTimeout(() => app.unmount('#app'), 5000)
9、use
- 参数:
- {Object | Function} plugin
- …options (optional)
使用 Vue 其他插件
//2.x
Vue.use(router)
//3.x
import { createApp } from 'vue'
const app = createApp({})
app.use(router)
三、Global API(全局API)
1、createApp
返回一个组件实例
const app = Vue.createApp({})
接收根组件选项对象作为第一个参数:
const app = Vue.createApp({
data() {
return {}
},
methods: {},
computed: {}
})
第二个参数,我们可以将根 props 传递给应用程序
const app = Vue.createApp(
{
props: ['username']
},
{ username: 'Evan' }
)
<div id="app">
{{ username }}
</div>
2、h
返回一个返回的“虚拟节点”,通常缩写为VNode。
render() {
return Vue.h('h1', {}, 'Some title')
}
参数
- tag
- 类型:String | Object | Function | null
- 具体值:一个HTML的标签名、组件、异步组件、null;此参数是必须的。
- props
- 类型:Object
- 具体值:模版中将使用到的属性、props或者元素
- children
- 类型:String | Array | Object
- 具体值:子虚拟节点,使用h()返回的值,或者一个插槽
h('div', {}, [
'Some text comes first.',
h('h1', 'A headline'),
h(MyComponent, {
someProp: 'foobar'
})
])
3、defineComponent
参数
- 类型 一个 component options 的 对象
import { defineComponent } from 'vue'
const MyComponent = defineComponent({
data() {
return { count: 1 }
},
methods: {
increment() {
this.count++
}
}
})
4、defineAsyncComponent
异步组件
参数
对于基本用法,defineAsyncComponent可以接受返回Promise的工厂函数。
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() =>
import('./components/AsyncComponent.vue')
)
app.component('async-component', AsyncComp)
使用本地注册时,您还可以直接提供一个返回Promise的函数:
components: {
AsyncComponent: defineAsyncComponent(() =>
import('./components/AsyncComponent.vue')
)
}
对于高级用法,defineAsyncComponent可以接受一个对象:
const AsyncComp = defineAsyncComponent({
// 工厂函数
loader: () => import('./Foo.vue')
// 加载异步组件时要使用的组件
loadingComponent: LoadingComponent,
// 加载失败时使用的组件
errorComponent: ErrorComponent,
// 显示加载组件之前的延迟。 默认值:200ms。
delay: 200,
// 如果提供并超过了超时,则将显示错误组件。 默认值:无穷大
timeout: 3000,
// 一个返回布尔值的函数,该值指示加载程序承诺拒绝时异步组件是否应重试
retryWhen: error => error.code !== 404,
// 允许的最大重试次数
maxRetries: 3,
// 定义组件是否
suspensible: false
})
5、resolveComponent
resolveComponent 只能在 render 或者 setup 中使用
参数
一个 component
import { resolveComponent } from 'vue'
render() {
const MyComponent = resolveComponent('MyComponent')
}
6、resolveDynamicComponent
resolveDynamicComponent 只能在 render 或者 setup 中使用
参数
一个 component
import { resolveDynamicComponent } from 'vue'
render () {
const MyComponent = resolveDynamicComponent('MyComponent')
}
7、resolveDirective
resolveDirective 只能在 render 或者 setup 中使用
参数
接收一个 指令名称
const app = Vue.createApp({})
app.directive('highlight', {})
import { resolveDirective } from 'vue'
render () {
const highlightDirective = resolveDirective('highlight')
}
8、withDirectives
withDirectives 只能在 render 或者 setup 中使用
参数
- 虚拟节点 使用h()创建的虚拟节点
- 自定义指令 一个自定义指令数组
import { withDirectives, resolveDirective } from 'vue'
const foo = resolveDirective('foo')
const bar = resolveDirective('bar')
return withDirectives(h('div'), [
[foo, this.x],
[bar, this.y]
])
const MyDirective = resolveDirective('MyDirective')
const nodeWithDirectives = withDirectives(
h('div'),
[ [MyDirective, 100, 'click', { prevent: true }] ]
)
9、createRenderer
自定义渲染平台
参数
- HostNode
- HostElement
import { createRenderer } from 'vue'
const { render, createApp } = createRenderer<Node, Element>({
patchProp,
...nodeOps
})
10、nextTick
异步更新队列
import { createApp, nextTick } from 'vue'
const app = createApp({
setup() {
const message = ref('Hello!')
const changeMessage = async newMessage => {
message.value = newMessage
await nextTick()
console.log('Now DOM is updated')
}
},
methods: {
this.$nextTick(() => {
// ...
})
}
})
四、Options
1、Data
1. data
类型:Function
const data = { a: 1 }
const vm = Vue.createApp({
data() {
return data
}
}).mount('#app')
//或者
data: vm => ({ a: vm.myProp })
2. props
类型:Array | Object
当使用 Object 的时候:
- type: 传入的类型;[String, Number, Boolean, Array, Object, Date, Function, Symbol]
- default: 默认值;[any]
- required: 是否必须;[Boolean]
- validator: 验证是否满足;[Function] 返回true和false
props: {
age: {
type: Number,
default: 0,
required: true,
validator: value => {
return value >= 0
}
}
}
3. computed
计算属性
类型:{ [key: string]: Function | { get: Function, set: Function } }
计算的属性的值会被缓存,并且仅在响应性依赖项更改时重新计算。
computed: {
aDouble() {
return this.a * 2
}
}
4. methods
组件方法
类型:{ [key: string]: Function }
methods: {
checkVal () {
return true
}
}
5. watch
监听
类型:{ [key: string]: string | Function | Object | Array}
watch: {
dataA (val, oldVal) {
console.log(val, oldVal)
},
// 在 methods 里面的方法
dataB: 'someMethod',
// 深度监听
dataC: {
handler(val, oldVal) {
console.log('c changed')
},
deep: true
},
// 立即执行
dataD: {
handler(val, oldVal) {
console.log('d changed')
},
immediate: true
},
// 传入一个数组
dataE: [
'handle1',
function handle2(val, oldVal) {
console.log('handle2 triggered')
},
{
handler: function handle3(val, oldVal) {
console.log('handle3 triggered')
}
}
]
},
methods: {
someMethod() {
console.log('b changed')
},
handle1() {
console.log('handle 1 triggered')
}
}
不能使用箭头函数来定义watch
6. emits
自组件通过 emit 的事件列表
类型:Array | Object
当为对象时可以验证传入的值是否有效
const app = Vue.createApp({})
// 当为数组时
app.component('todo-item', {
emits: ['check'],
created() {
this.$emit('check')
}
})
// 当为一个对象时
app.component('reply-form', {
emits: {
click: null,
submit: payload => {
if (payload.email && payload.password) {
return true
} else {
console.warn(`Invalid submit event payload!`)
return false
}
}
}
})
2、生命周期钩子函数
1. beforeCreate
组件实例创建之前,data、event、watcher 不能调用
2. created
组件实例创建之后,data、event、watcher可以使用
$el属性不能调用,不能操作DOM
3. beforeMount
组件实例挂载之前立即被调用:render函数将被首次调用
在服务器端渲染期间不会调用此钩子函数。
4. mounted
组件实例挂载之后调用
mounted不能保证所有子组件也都已安装。 如果要等到整个视图渲染完毕,可以在mount的内部使用vm.$nextTick
在服务器端渲染期间不会调用此钩子函数。
5. beforeUpdate
组件实例更新之前
在服务器端渲染期间不会调用此钩子函数。
6. updated
组件更新之后
更新并不能保证所有子组件也都已重新呈现。如果要等到整个视图重新渲染后,可以在更新后使用vm.$nextTick
在服务器端渲染期间不会调用此钩子函数。
7. activated
kept-alive 组件激活时的钩子函数
在服务器端渲染期间不会调用此钩子函数。
8. deactivated
kept-alive 组件卸载时的钩子
在服务器端渲染期间不会调用此钩子函数
9. beforeUnmount
卸载之前调用
在服务器端渲染期间不会调用此钩子函数
10. unmounted
卸载之后调用,调用此钩子后,组件实例的所有指令均已解除绑定,所有事件侦听器均已删除,所有子组件实例也已卸载。
在服务器端渲染期间不会调用此钩子函数
11. errorCaptured
类型: (err: Error, instance: Component, info: string) => ?boolean
当捕获到任何后代组件的错误时调用。挂钩接收三个参数:错误,触发错误的组件实例以及包含有关捕获错误的位置信息的字符串。 挂钩可以返回false,以阻止错误进一步传播。
- 默认情况下,所有错误仍将发送到全局config.errorHandler(如果已定义)。
- 如果组件的继承链或父链上存在多个errorCaptured挂钩,则将在同一错误上调用所有它们。
- 如果errorCaptured挂钩本身抛出错误,则此错误和原始捕获的错误都将发送到全局config.errorHandler。
- errorCaptured挂钩可以返回false,以防止错误进一步传播。
12. renderTracked
虚拟dom 被 tracked 时调用
renderTracked({ key, target, type }) {}
13. renderTriggered
触发虚拟DOM重新呈现时调用
renderTriggered({ key, target, type }) {}
五、示例方法
1、$watch
参数
- {string | Function} source
- {Function | Object} callback
- {Object} options (optional)
- {boolean} deep
- {boolean} immediate
$watch返回一个unwatch函数,该函数停止触发监听
const unwatch = vm.$watch('a', cb)
// 5秒钟之后停止监听
setTimeout(() => {
unwatch()
}, 5000)
2、$emit
参数
- {string} eventName
- …args (optional)
<button v-on:click="$emit('give-advice', adviceText)">
Click but
</button>
3、$forceUpdate
强制重新渲染组件实例。它不会影响所有子组件,只会影响实例本身和插入了插槽内容的子组件。
触发之后 会触发 updated() 钩子函数
4、$nextTick
参数
- {Function} callback (optional)
在下一个DOM更新周期后执行的回调。
methods: {
example() {
this.$nextTick(() => {})
}
}
六、反应性API
1、Reactivity APIs
1. reactive
返回一个对象的反应性拷贝数据
const person = reactive({
name: 'Bob',
age: 18
})
基于 ES6 的Proxy代理实现
2. readonly
返回一个只读的对象,或者只读的ref
const ref1 = ref(0)
const read1 = readonly({
read: 'only'
})
const read2 = readonly(ref1)
read1.read = 'change'
// ⚠️ reactivity.esm-bundler.js?a1e9:301 Set operation on key "read" failed: target is readonly
read2.value = 10
// ⚠️ Set operation on key "value" failed: target is readonly.
3. isProxy
检查代理对象是由 reactive 还是 readonly 创建的,返回 true 和 false
const ref1 = ref(0)
const book = reactive({
title: 'this is vue3'
})
const read1 = readonly({
read: 'only'
})
console.log(isProxy(ref1), isProxy(book), isProxy(read1))
// false true true
4. isReactive
检查代理对象是否由 reactive 创建的,返回 true 和 false
const ref1 = ref(0)
const book = reactive({
title: 'this is vue3'
})
const read1 = readonly({
read: 'only'
})
console.log(isReactive(ref1), isReactive(book), isReactive(read1))
// false true false
如果一个对象是由 readonly 创建的 reactive 对象,则返回的也是 true
let react = reactive({
name: 'Bob'
})
let react1 = readonly(react)
console.log(isProxy(react1), isReactive(react1))
// true true
5. isReadonly
检查代理对象是不是 readonly,返回 true 和 false
const ref1 = ref(0)
const read1 = readonly({
read: 'only'
})
let react = reactive({
name: 'Bob'
})
let react1 = readonly(react)
const ref2 = readonly(ref1)
console.log(isReadonly(react1), isReadonly(read1), isReadonly(ref2))
// true true true
6. toRaw
返回反应式或只读代理的原始原始对象。可用于临时读取而不会产生代理访问/跟踪开销,也可用于写入而不会触发更改。 不建议保留对原始对象的持久引用。 请谨慎使用。
let obj = {a: 1}
let reactObj = reactive(obj)
let toRawObj = toRaw(obj)
let toRawObj1 = toRaw(reactObj)
console.log(obj, reactObj, toRawObj, toRawObj1, toRawObj === obj, toRawObj1 === obj, toRawObj === toRawObj1)
// {a: 1} Proxy {a: 1} {a: 1} {a: 1} true true true
setTimeout(() => {
obj.a = 2
console.log(obj, reactObj, toRawObj, toRawObj1, toRawObj === obj, toRawObj1 === obj, toRawObj === toRawObj1)
// {a: 2} Proxy {a: 2} {a: 2} {a: 2} true true true
}, 1000)
setTimeout(() => {
reactObj.a = 3
console.log(obj, reactObj, toRawObj, toRawObj1, toRawObj === obj, toRawObj1 === obj, toRawObj === toRawObj1)
// {a: 3} Proxy {a: 3} {a: 3} {a: 3} true true true
}, 2000)
7. markRaw
标记一个对象,使其永远不会转换为代理。 返回对象本身。
let obj = {a: 1}
let reactObj = reactive(obj)
let toRawObj = markRaw(obj)
let toRawObj1 = markRaw(reactObj)
console.log(obj, reactObj, toRawObj, toRawObj1, toRawObj === obj, toRawObj1 === obj, toRawObj === toRawObj1)
// {a: 1, __v_skip: true}a: 3__v_skip: true__proto__: Object Proxy {a: 1, __v_skip: true} {a: 1, __v_skip: true} Proxy {a: 1, __v_skip: true} true false false
setTimeout(() => {
obj.a = 2
console.log(obj, reactObj, toRawObj, toRawObj1, toRawObj === obj, toRawObj1 === obj, toRawObj === toRawObj1)
// {a: 2, __v_skip: true}a: 3__v_skip: true__proto__: Object Proxy {a: 2, __v_skip: true} {a: 2, __v_skip: true}a: 3__v_skip: true__proto__: Object Proxy {a: 2, __v_skip: true} true false false
}, 1000)
setTimeout(() => {
reactObj.a = 3
console.log(obj, reactObj, toRawObj, toRawObj1, toRawObj === obj, toRawObj1 === obj, toRawObj === toRawObj1)
// {a: 3, __v_skip: true} Proxy {a: 3, __v_skip: true} {a: 3, __v_skip: true} Proxy {a: 3, __v_skip: true} true false false
}, 2000)
8. shallowReactive
创建一个反应式代理,该反应式代理跟踪其自身属性的反应性,但不执行嵌套对象的深度反应式转换。
const book = reactive({
title: 'this is vue3',
address: {
city: 'hz',
area: 'bj'
}
})
console.log(isReactive(book.address))
// true
const obj = shallowReactive({
name: 'Bob',
age: 18,
address: {
city: 'hz',
area: 'bj'
}
})
console.log(isReactive(obj.address))
// false
9. shallowReadonly
创建一个代理,使其自身的属性为只读,但不执行嵌套对象的深度只读转换。
const book = readonly({
title: 'this is vue3',
address: {
city: 'hz',
area: 'bj'
}
})
console.log(isReadonly(book.address))
// true
const obj = shallowReadonly({
name: 'Bob',
age: 18,
address: {
city: 'hz',
area: 'bj'
}
})
console.log(isReadonly(obj.address))
// false
2、Refs
1. ref
接受一个值并返回一个反应性且可变的ref对象。ref对象具有指向内部值的单个属性.value。
const ref1 = ref(0)
__v_isRef: true
_rawValue: 0
_shallow: false
_value: 0
value: 0
const ref2 = ref({
name: 'Bob',
age: 18
})
__v_isRef: true
_rawValue: {name: "Alice", age: 18}
_shallow: false
_value: Proxy {name: "Alice", age: 18}
value: Proxy
[[Handler]]: Object
[[Target]]: Object
age: 18
name: "Alice"
__proto__: Object
[[IsRevoked]]: false
一般使用 ref 定义基本类型
2. unref
如果参数是 ref 则返回内部的 value 值,否则返回 参数本身,是 val = isRef(val) ? val.value : val
的语法糖
const ref1 = ref(0)
const ref2 = ref({
name: 'Bob',
age: 18
})
const obj = reactive({
name: 'Alice',
age: 20
})
console.log(unref(ref1), unref(ref2), unref(obj))
// 0
// Proxy
// Proxy
3. toRef
创建一个 reactive 的对象的属性 做为 ref 的引用,保持反应性连接
const obj = reactive({
name: 'Alice',
age: 20
})
const toR1 = toRef(obj, 'name')
const notoR2 = obj.name
setTimeout(() => {
obj.name = 'Jack'
}, 1000)
// 1000 毫秒之后 toR1.value 值为 Jack, notoR2 的值为 Alice
4. toRefs
将反应对象转换为普通对象,其中所得对象的每个属性都是指向原始对象相应属性的ref。
const obj = reactive({
name: 'Alice',
age: 20
})
const refs1 = toRefs(obj)
console.log(refs1)
{name: ObjectRefImpl, age: ObjectRefImpl}
age: ObjectRefImpl
__v_isRef: true
_key: "age"
_object: Proxy {name: "Jack", age: 20}
value: 20
__proto__: Object
name: ObjectRefImpl
__v_isRef: true
_key: "name"
_object: Proxy {name: "Jack", age: 20}
value: "Jack"
__proto__: Object
setTimeout(() => {
obj.name = 'Jack'
}, 1000)
// 1000 毫秒之后 refs1.name.value 的值也变为 Jack
5. isRef
检查是否是 ref 对象
const ref1 = ref(0)
const ref2 = ref({
name: 'Bob',
age: 18
})
const obj = reactive({
name: 'Alice',
age: 20
})
console.log(isRef(ref1), isRef(ref2), isRef(obj))
// true true false
6. customRef
<template>
<div class="my-com2">
<input v-model="text" />
</div>
</template>
<script>
import {customRef} from 'vue'
function useDebouncedRef(value, delay = 200) {
let timeout
return customRef((track, trigger) => {
return {
get() {
console.log(value)
track()
return value
},
set(newValue) {
console.log(newValue)
clearTimeout(timeout)
timeout = setTimeout(() => {
value = newValue
trigger()
}, delay)
}
}
})
}
export default{
setup () {
return {
text: useDebouncedRef('hello')
}
}
}
</script>
<style scoped>
</style>
7. shallowRef
const ref1 = ref(0)
const ref2 = ref({
name: 'Bob',
age: 18
})
const obj = reactive({
name: 'Alice',
age: 20
})
const a1 = shallowRef(ref1)
const a2 = shallowRef(ref2)
const a3 = shallowRef(obj)
console.log(isReactive(a1), isReactive(a2), isReactive(a3))
// false false false
8. triggerRef
const s1 = shallowRef({
name: 'Bob'
})
s1.value.name = 'Alice'
triggerRef(s1)
console.log(s1.value.name)
// Alice