赞
踩
转载:https://blog.csdn.net/weixin_47521346/article/details/109185232?spm=1001.2014.3001.5501
下面讲述Vue3破坏性变更的地方
全局api已迁移至 createApp()创建的实例下:
2.x全局API | 3.x实例API(app) |
---|---|
Vue.config.production | 已经删除 |
Vue.component | app.component |
Vue.directive | app.directive |
Vue.mixin | app.mixin |
Vue.use | app.use |
const app = createApp(MyApp)
app.use(VueRouter)
代码如下(示例):
const app = createApp(MyApp)
app.component('button-counter', {
data: () => ({
count: 0
}),
template: '<button @click="count++">Clicked {{ count }} times.</button>'
})
app.directive('focus', {
mounted: el => el.focus()
})
app.mount('#app')
代码如下(示例):
// 在入口文件
app.provide('guide', 'Vue 3 Guide')
// 在子组件中
export default {
inject: {
book: {
from: 'guide'
}
},
template: `<div>{{ book }}</div>`
}
组件中使用 可参考组合式api中https://v3.cn.vuejs.org/guide/composition-api-provide-inject.html#%E4%BF%AE%E6%94%B9%E5%93%8D%E5%BA%94%E5%BC%8F-property
例如:有时我们需要在注入数据的组件内部更新 inject 的数据。在这种情况下,我们建议 provide 一个方法来负责改变响应式 property
代码如下(示例):
<!-- src/components/MyMap.vue --> <template> <MyMarker /> </template> <script> import { provide, reactive, ref } from 'vue' import MyMarker from './MyMarker.vue' export default { components: { MyMarker }, setup() { const location = ref('North Pole') const geolocation = reactive({ longitude: 90, latitude: 135 }) const updateLocation = () => { location.value = 'South Pole' } provide('location', location) provide('geolocation', geolocation) provide('updateLocation', updateLocation) } } </script> <!-- src/components/MyMarker.vue --> <script> import { inject } from 'vue' export default { setup() { const userLocation = inject('location', 'The Universe') const userGeolocation = inject('geolocation') const updateUserLocation = inject('updateLocation') return { userLocation, userGeolocation, updateUserLocation } } } </script>
后续更新 详情请看转载
reactive 基本等价于2.x中的Vue.observable(),返回一个响应式对象,就像2.x中定义在data选项里的数据一样,最终都会被转换成响应式对象。基于 ES2015 的 Proxy 实现。
import { reactive } from 'vue'
// state 现在是一个响应式的状态
const state = reactive({
count: 0,
})
接受一个参数值并返回一个响应式且可改变的 ref 对象。ref 对象拥有一个指向内部值的单一属性.value
const count = ref(0) // 相当于返回{value:0}
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
ref 适合基础类型值
reactive 适合对象类型的值
把变量全塞对象里直接用reactive,对象解构的时候,数据会丢失响应式特性
const pos = reactive({
x: 0,
y: 0,
})
function updatePosition(e) {
// 解构对象,导致响应式丢失,相当于重新将值赋给了一个变量,之后的更改不会改变原属性的值
let {x,y} = pos
x = e.pageX
y = e.pageY
}
正因为此,官方提供了toRefs与toRef的函数,来将一个响应式对象的基础类型属性值转换为ref对象
const state = reactive({
foo: 1,
bar: 2,
})
const fooRef = toRef(state, 'foo') // 转换单个的foo属性为ref对象
fooRef.value++
console.log(state.foo) // 2
state.foo++
console.log(fooRef.value) // 3
const state = reactive({ foo: 1, bar: 2, }) const stateAsRefs = toRefs(state) // 转换state对象的所有属性为ref对象 /* stateAsRefs 的类型如下: { foo: Ref<number>, bar: Ref<number> } */
vue3中reacitve函数如何声明一个响应式数组,如以下案例
<template> <div> <div v-for="item in arr.list" :key="item"> {{item}} </div> <button @click="change">change</button> </div> </template> <script> import { defineComponent, reactive,ref } from 'vue'; export default defineComponent({ setup(props,context) { let arr = reactive({ list:[] }) function change(){ console.log("change..."); let newArr = [1,2,3] arr.list = newArr } return{ arr, change } }, }); </script>
<template> <div> 名字:{{ name }} </div> <!-- toRefs 用于将一个 reactive 对象转化为属性全部为 ref 对象的普通对象 --> </template> <script lang="tsx" src="./script"></script> <style lang="less" src="./index.less" scoped></style> import { computed, defineComponent, reactive, ref, toRef, toRefs } from 'vue' import { copyValueObject } from '@/utils/util.ts' export default defineComponent({ setup(props, { emit }) { let testObj = reactive({ name: '咳咳咳', age: 56, }) setTimeout(() => { testObj = copyValueObject(testObj, { name: 'jajjaj', age: 50 }) }, 500) return { ...toRefs(testObj), } }, }) utils.js export const copyValueObject = (object: any, valueObject: any) => { for (const key in object) { if ( valueObject[key] || valueObject[key] === 0 || valueObject[key] === false ) { object[key] = valueObject[key] } } return object }
预期接收一个含有副作用的函数,仅当该过程中用到的响应式状态发生改变时,会重新执行该函数。
import { reactive, watchEffect } from 'vue'
const state = reactive({
count: 0,
})
onMounted(()=>{
// 立即执行一次,之后会在state.count发生改变的时候执行,组件卸载的时候销毁
watchEffect(() => {
document.body.innerHTML = `count is ${state.count}`
})
})
watch和watchEffect比较
watchEffect和computed比较像,都是通过执行副作用函数获取要监听的数据源,而watch是通过第一参数获取要监听的数据源
watch的参数有3个(数据源,副作用函数,配置),watchEffect只有两个(副作用函数,配置)
watch的副作用函数接收的参数比watchEffect多两个(新旧值)
deep和immediate只对watch有用
① watch可以访问新值和旧值,watchEffect不能
② watchEffect有副作用,DOM挂载或者更新之前就会触发****通过 flush:post可以避免副作用,在DOM更新后运行副作用,确保模板引用与DOM保持同步,并引入正确的元素在执行数据请求时,副作用函数往往是一个异步函数
// 同步的方式 const stop = watchEffect(() => { /* ... */ }) // 之后 stop() // 如果是回调里有异步,可以用回调的参数onInvalidate去取消监听 const data = ref(0) watchEffect((onInvalidate) => { // 立即执行,其后data改变,组件更新后执行 console.log(data.value) const timer = setInterval(()=>{ data.value ++ },1000) // 第一次初始化时候不执行该回调,仅注册回调,data改变时以及停止侦听时,会触发该回调 onInvalidate(() => { // 取消定时器 clearInterval(timer) }) }) // output: 0 1
onInvalidate 触发时机
副作用即将重新执行时(也就是追踪的依赖发生改变时)
侦听器被停止时(如果在 setup() 或 生命周期钩子函数中使用了 watchEffect, 则在卸载组件时)
customRef 用于自定义一个 ref,可以显式地控制依赖追踪和触发响应。
<template> <input v-model="text" /> </template> <script> function useDebouncedRef(value, delay = 200) { let timeout return customRef((track, trigger) => { return { get() { track() // 调用track收集依赖 return value }, set(newValue) { clearTimeout(timeout) timeout = setTimeout(() => { value = newValue trigger() // 调用trigger,触发响应 }, delay) }, } }) } export default { setup() { return { text: useDebouncedRef('hello'), } }, } </script>
显式标记一个对象为“永远不会转为响应式代理”,函数返回这个对象本身。作用有点类似Object.freeze, 去除响应式。
const foo = markRaw({})
console.log(isReactive(reactive(foo))) // false
// 如果被 markRaw 标记了,即使在响应式对象中作属性,也依然不是响应式的
const bar = reactive({ foo })
console.log(isReactive(bar.foo)) // false
与reactive类似,唯一的区别就是只创建“浅代理”,嵌套对象不会变成响应式
const state = shallowReactive({
foo: 1,
nested: {
bar: 2,
},
})
// 变更 state 的自有属性是响应式的
state.foo++
// ...但不会深层代理
isReactive(state.nested) // false
state.nested.bar++ // 非响应式
与readonly类似,唯一的区别就是只限制“浅只读”。嵌套对象仍然可以赋值
const state = shallowReadonly({
foo: 1,
nested: {
bar: 2,
},
})
// 变更 state 的自有属性会失败
state.foo++
// ...但是嵌套的对象是可以变更的
isReadonly(state.nested) // false
state.nested.bar++ // 嵌套属性依然可修改
与ref类似,唯一的区别只是“浅引用” ,只会追踪它的 .value 更改操作,但是如果赋值的是一个对象,则该对象不是可响应,并且后续的对象的属性更改均不会触发视图响应
const foo = shallowRef({})
foo.value.a = 1 // 这个a也不会响应到视图上去
isReactive(foo.value) // false
// 更改对操作会触发响应
foo.value = []
// 但上面新赋的这个对象并不会变为响应式对象,只是会同步这个值,视图上会同步显示[]
isReactive(foo.value) // false
const bar = shallowRef(0)
bar.value ++ // 1 , 这个是响应式的
返回由 reactive 或 readonly 方法转换成响应式代理的普通对象。简单来说就是返回代理之前的原始对象。
const foo = {}
const reactiveFoo = reactive(foo)
console.log(toRaw(reactiveFoo) === foo) // true
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。