web前端之vue3

MENU

  • vue3响应式数据的判断、isRef、isReactive、isReadonly、isProxy、ref、reactive、readonly
  • vue3的生命周期
  • vue3手写isRef、isReactive、isReadonly、isProxy
  • vue3手写ref、深的ref
  • vue3手写shallowRef、浅的ref
  • vue3customRef
  • vue3readonly与shallowReadonly
  • vue3toRaw与markRaw
  • vue3手写reactive、深的劫持、深的监视、深的响应数据
  • vue3之ref获取元素
  • vue3手写reactive、深的劫持、深的监视、深的响应数据
  • vue3手写readonly、深只读
  • vue3手写shallowReactive、浅的劫持、浅的监视、浅的响应数据
  • vue3provide和inject、实现跨层级组件间通信、祖孙组件
  • vue3shallowReactive与shallowRef
  • vue3toRefs


vue3响应式数据的判断、isRef、isReactive、isReadonly、isProxy、ref、reactive、readonly

import {defineComponent,isProxy,isReactive,isReadonly,isRef,reactive,readonly,ref,
} from "vue";
export default defineComponent({name: "App",// isRef: 检查一个值是否为一个 ref 对象// isReactive: 检查一个对象是否是由 reactive 创建的响应式代理// isReadonly: 检查一个对象是否是由 readonly 创建的只读代理// isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理setup() {// isRef: 检查一个值是否为一个 ref 对象console.log(isRef(ref({}))); // true// isReactive: 检查一个对象是否是由 reactive 创建的响应式代理console.log(isReactive(reactive({}))); // true// isReadonly: 检查一个对象是否是由 readonly 创建的只读代理console.log(isReadonly(readonly({}))); // true// isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理console.log(isProxy(readonly({}))); // trueconsole.log(isProxy(reactive({}))); // truereturn {};},
});

vue3的生命周期

1、父组件

<template><h2>App</h2><button @click="isShow=!isShow">切换</button><hr><Child v-if="isShow"/>
</template>

import Child from './Child.vue';export default {data () {return {isShow: true}},components: {Child}
};

2、子组件

<template><div class="about"><h2>msg: {{msg}}</h2><hr><button @click="update">更新</button></div>
</template>

import {ref,onMounted,onUpdated,onUnmounted, onBeforeMount, onBeforeUpdate,onBeforeUnmount
} from "vue";export default {beforeCreate () {console.log('2.xbeforeCreate()')},created () {console.log('2.xcreated')},beforeMount () {console.log('2.xbeforeMount')},mounted () {console.log('2.xmounted')},beforeUpdate () {console.log('2.xbeforeUpdate')},updated () {console.log('2.xupdated')},beforeUnmount () {console.log('2.xbeforeUnmount')},unmounted () {console.log('2.xunmounted')},setup() {const msg = ref('abc');const update = () => {msg.value += '--';};onBeforeMount(() => {console.log('3.0--onBeforeMount')});onMounted(() => {console.log('3.0--onMounted')});onBeforeUpdate(() => {console.log('3.0--onBeforeUpdate')});onUpdated(() => {console.log('3.0--onUpdated')});onBeforeUnmount(() => {console.log('3.0--onBeforeUnmount')});onUnmounted(() => {console.log('3.0--onUnmounted')});return {msg,update};}
};

3、2.x与3.x生命周期执行顺序

3.x中生命周期执行顺序比2.x快,也就是先于2.x的生命周期执行。


vue3手写isRef、isReactive、isReadonly、isProxy

1、包含的功能及函数

isRef、isReactive、isReadonly、isProxy、shallowReactive、reactive、shallowReadonly、readonly、shallowRef、ref


2、函数实现

// 定义一个reactiveHandler处理对象
const reactiveHandler = {// 获取属性值get(target, prop) {if (prop === '_is_reactive') return true;const result = Reflect.get(target, prop);console.log('拦截了读取数据', prop, result);return result;},// 修改属性值或者是添加属性set(target, prop, value) {const result = Reflect.set(target, prop, value);console.log('拦截了修改数据或者是添加属性', prop, value);return result;},// 删除某个属性deleteProperty(target, prop) {const result = Reflect.deleteProperty(target, prop);console.log('拦截了删除数据', prop);return result;}
}// 01--------------------------------------
// shallowReactive
// 定义一个shallowReactive函数,传入一个目标对象
function shallowReactive(target) {// 判断当前的目标对象是不是object类型(对象/数组)if (target && typeof target === 'object') {return new Proxy(target, reactiveHandler);}// 如果传入的数据是基本类型的数据,那么就直接返回return target;
}// 02--------------------------------------
// reactive
// 定义一个reactive函数,传入一个目标对象
function reactive(target) {// 判断当前的目标对象是不是object类型(对象/数组)if (target && typeof target === 'object') {// 对数组或者是对象中所有的数据进行reactive的递归处理// 先判断当前的数据是不是数组if (Array.isArray(target)) {// 数组的数据要进行遍历操作0target.forEach((item, index) => {// 如果数组中还有数组// 使用递归target[index] = reactive(item);});} else {// 再判断当前的数据是不是对象// 对象的数据也要进行遍历的操作Object.keys(target).forEach(key => {target[key] = reactive(target[key]);});}return new Proxy(target, reactiveHandler);}// 如果传入的数据是基本类型的数据,那么就直接返回return target;
}// ===============================================================
// 定义了一个readonlyHandler处理器
const readonlyHandler = {get(target, prop) {if (prop === '_is_readonly') return true;const result = Reflect.get(target, prop);console.log('拦截到了读取数据了', prop, result);return result;},set(target, prop, value) {console.warn('只能读取数据,不能修改数据或者添加数据');return true;},deleteProperty(target, prop) {console.warn('只能读取数据,不能删除数据');return true;}
}// 03--------------------------------------
// shallowReadonly
// 定义一个shallowReadonly函数
function shallowReadonly(target) {// 需要判断当前的数据是不是对象if (target && typeof target === 'object') {return new Proxy(target, readonlyHandler);}return target;
}// 04--------------------------------------
// readonly
// 定义一个readonly函数
function readonly(target) {// 需要判断当前的数据是不是对象if (target && typeof target === 'object') {// 判断target是不是数组if (Array.isArray(target)) {// 遍历数组target.forEach((item, index) => {target[index] = readonly(item);});} else {// 判断target是不是对象// 遍历对象Object.keys(target).forEach(key => {target[key] = readonly(target[key]);});}return new Proxy(target, readonlyHandler);}// 如果不是对象或者数组,那么直接返回return target;
}// ===============================================================
// 05--------------------------------------
// shallowRef
// 定义一个shallowRef函数
function shallowRef(target) {return {// 保存target数据保存起来_value: target,get value() {console.log('劫持到了读取数据');return this._value;},set value(val) {console.log('劫持到了修改数据,准备更新界面', val);this._value = val;}}
}// 06--------------------------------------
// ref
// 定义一个ref函数
function ref(target) {target = reactive(target);return {_is_ref: true, // 标识当前的对象是ref对象// 保存target数据保存起来_value: target,get value() {console.log('劫持到了读取数据');return this._value;},set value(val) {console.log('劫持到了修改数据,准备更新界面', val);this._value = val;}}
}// ===============================================================
// 定义一个函数isRef,判断当前的对象是不是ref对象
function isRef(obj) {return obj && obj._is_ref;
}// 定义一个函数isReactive,判断当前的对象是不是reactive对象
function isReactive(obj) {return obj && obj._is_reactive;
}// 定义一个函数isReadonly,判断当前的对象是不是readonly对象
function isReadonly(obj) {return obj && obj._is_readonly;
}// 定义一个函数isProxy,判断当前的对象是不是reactive对象或者readonly对象
function isProxy(obj) {return isReactive(obj) || isReadonly(obj);
}

3、函数调用

// 01--------------------------------------
// shallowReactive
const proxyUser1 = shallowReactive({name: '小明',car: {color: 'red'}
});
// 拦截到了读和写的数据
proxyUser1.name += '==';
// 拦截到了读取数据,但是拦截不到写的数据
proxyUser1.car.color + '==';
// 拦截到了删除数据
delete proxyUser1.name;
// 只拦截到了读,但是拦截不到删除
delete proxyUser1.car.color;// 02--------------------------------------
// reactive
const proxyUser2 = reactive({name: '小明',car: {color: 'red'}
});
// 拦截到了读和修改的数据
proxyUser2.name += '==';
// 拦截到了读和修改的数据
proxyUser2.car.color = '==';
// 拦截了删除
delete proxyUser2.name;
// 拦截到了读和拦截到了删除
delete proxyUser2.car.color;// 03--------------------------------------
// shallowReadonly
const proxyUser3 = shallowReadonly({name: '小明',cars: ['奔驰', '宝马']
});
// 可以读取
console.log(proxyUser3.name);
// 不能修改
proxyUser3.name = '==';
// 不能删除
delete proxyUser3.name;
// 拦截到了读取,可以修改
proxyUser3.cars[0] = '奥迪';
// 拦截到了读取,可以删除
delete proxyUser3.cars[0];// 04--------------------------------------
// readonly
const proxyUser4 = readonly({name: '小明',cars: ['奔驰', '宝马']
});
// 拦截到了读取
console.log(proxyUser4.name);
console.log(proxyUser4.cars[0]);
// 只读的
proxyUser4.name = '哈哈';
// 只读的
proxyUser4.cars[0] = '哈哈';
delete proxyUser4.name;
delete proxyUser4.cars[0];// 05--------------------------------------
// shallowRef
const ref1 = shallowRef({name: '小明',car: {color: 'red'}
});
console.log(ref1.value);
// 劫持到
ref1.value = '==';
// 劫持不到
ref1.value.car = '==';// 06--------------------------------------
// ref
const ref2 = ref({name: '小明',car: {color: 'red'}
});
console.log(ref2.value);
// 劫持到
ref2.value = '==';
// 劫持到
ref2.value.car = '==';// 07--------------------------------------
console.log(isRef(ref({})));
console.log(isReactive(reactive({})));
console.log(isReadonly(readonly({})));
console.log(isProxy(reactive({})));
console.log(isProxy(readonly({})));

vue3手写ref、深的ref

1、函数实现

// 定义一个reactive函数,传入一个目标对象
function reactive(target) {// 判断当前的目标对象是不是object类型(对象/数组)if (target && typeof target === 'object') {// 对数组或者是对象中所有的数据进行reactive的递归处理// 先判断当前的数据是不是数组if (Array.isArray(target)) {// 数组的数据要进行遍历操作0target.forEach((item, index) => {// 如果数组中还有数组// 使用递归target[index] = reactive(item);});} else {// 再判断当前的数据是不是对象// 对象的数据也要进行遍历的操作Object.keys(target).forEach(key => {target[key] = reactive(target[key]);});}return new Proxy(target, reactiveHandler);}// 如果传入的数据是基本类型的数据,那么就直接返回return target;
}// 定义一个ref函数
function ref(target) {target = reactive(target);return {_is_ref: true, // 标识当前的对象是ref对象// 保存target数据保存起来_value: target,get value() {console.log('劫持到了读取数据');return this._value;},set value(val) {console.log('劫持到了修改数据,准备更新界面', val);this._value = val;}}
}

2、函数调用

const ref2 = ref({name: '小明',car: {color: 'red'}
});
console.log(ref2.value);
// 劫持到
ref2.value = '==';
// 劫持到
ref2.value.car = '==';

vue3手写shallowRef、浅的ref

1、函数实现

// 定义一个shallowRef函数
function shallowRef(target) {return {// 保存target数据保存起来_value: target,get value() {console.log('劫持到了读取数据');return this._value;},set value(val) {console.log('劫持到了修改数据,准备更新界面', val);this._value = val;}}
}

2、函数调用

const ref1 = shallowRef({name: '小明',car: {color: 'red'}
});
console.log(ref1.value);
// 劫持到
ref1.value = '==';
// 劫持不到
ref1.value.car = '==';

vue3customRef

1、概念

创建一个自定义的ref,并对其依赖项跟踪和更新触发进行显式控制。


2、代码示例
需求

使用customRef实现debounce的示例。


<template><h2>CustomRef的使用</h2><input type="text" v-model="keyword" /><p>{{ keyword }}</p>
</template>

import { customRef, defineComponent, ref } from "vue";
// 自定义hook防抖的函数
// value传入的数据,将来数据的类型不确定,所以,用泛型,delay防抖的间隔时间.默认是200毫秒
function useDebouncedRef<T>(value: T, delay = 200) {// 准备一个存储定时器的id的变量let timeOutId: number;return customRef((track, trigger) => {return {// 返回数据的get() {// 告诉Vue追踪数据track();return value;},// 设置数据的set(newValue: T) {// 清理定时器clearTimeout(timeOutId);// 开启定时器timeOutId = setTimeout(() => {value = newValue;// 告诉Vue更新界面trigger();}, delay);},};});
}export default defineComponent({name: "App",setup() {// const keyword = ref('abc')const keyword = useDebouncedRef("abc", 500);return {keyword,};},
});

vue3readonly与shallowReadonly

1、概念

readonly
○深度只读数据。
○获取一个对象 (响应式或纯对象) 或 ref 并返回原始代理的只读代理。
○只读代理是深层的:访问的任何嵌套 property 也是只读的。
shallowReadonly
○浅只读数据。
○创建一个代理,使其自身的 property 为只读,但不执行嵌套对象的深度只读转换。
应用场景
○在某些特定情况下, 我们可能不希望对数据进行更新的操作, 那就可以包装生成一个只读代理对象来读取数据, 而不能修改或删除。


2、示例代码

<template><h2>readonly和shallowReadonly</h2><h3>state:{{ state2 }}</h3><hr /><button @click="update">更新数据</button>
</template>

import { defineComponent, reactive, readonly, shallowReadonly } from "vue";export default defineComponent({name: "App",setup() {const state = reactive({name: "佐助",age: 20,car: {name: "奔驰",color: "yellow",},});// 只读的数据---深度的只读// const state2 = readonly(state)// 只读的数据---浅只读的const state2 = shallowReadonly(state);const update = () => {// state2.name += '==='// state2.car.name += '=='// state2.name+='==='state2.car.name += "===";};return {state2,update,};},
});

vue3toRaw与markRaw

1、概念

toRaw
返回由 reactive 或 readonly 方法转换成响应式代理的普通对象。
这是一个还原方法,可用于临时读取,访问不会被代理/跟踪,写入时也不会触发界面更新。
markRaw
标记一个对象,使其永远不会转换为代理。返回对象本身。
应用场景
有些值不应被设置为响应式的,例如复杂的第三方类实例或 Vue 组件对象。
当渲染具有不可变数据源的大列表时,跳过代理转换可以提高性能。


2、示例代码
html

<template><h2>toRaw和markRaw</h2><h3>state:{{ state }}</h3><hr /><button @click="testToRaw">测试toRaw</button><button @click="testMarkRaw">测试markRaw</button>
</template>

JavaScrip

import { defineComponent, markRaw, reactive, toRaw } from "vue";interface UserInfo {name: string;age: number;likes?: string[];
}export default defineComponent({name: "App",setup() {const state = reactive<UserInfo>({name: "小明",age: 20,});const testToRaw = () => {// 把代理对象变成了普通对象了,数据变化,界面不变化const user = toRaw(state);user.name += "==";console.log("哈哈,我好帅哦");};const testMarkRaw = () => {// state.likes = ['吃', '喝']// state.likes[0] += '=='// console.log(state)const likes = ["吃", "喝"];// markRaw标记的对象数据,从此以后都不能再成为代理对象了state.likes = markRaw(likes);setInterval(() => {if (state.likes) {state.likes[0] += "=";console.log("定时器走起来");}}, 1000);};return {state,testToRaw,testMarkRaw,};},
});

vue3手写reactive、深的劫持、深的监视、深的响应数据

1、函数实现

// 定义一个reactive函数,传入一个目标对象
function reactive(target) {// 判断当前的目标对象是不是object类型(对象/数组)if (target && typeof target === 'object') {// 对数组或者是对象中所有的数据进行reactive的递归处理// 先判断当前的数据是不是数组if (Array.isArray(target)) {// 数组的数据要进行遍历操作0target.forEach((item, index) => {// 如果数组中还有数组// 使用递归target[index] = reactive(item);});} else {// 再判断当前的数据是不是对象// 对象的数据也要进行遍历的操作Object.keys(target).forEach(key => {target[key] = reactive(target[key]);});}return new Proxy(target, reactiveHandler);}// 如果传入的数据是基本类型的数据,那么就直接返回return target;
}// 定义一个reactiveHandler处理对象
const reactiveHandler = {// 获取属性值get(target, prop) {if (prop === '_is_reactive') return true;const result = Reflect.get(target, prop);console.log('拦截了读取数据', prop, result);return result;},// 修改属性值或者是添加属性set(target, prop, value) {const result = Reflect.set(target, prop, value);console.log('拦截了修改数据或者是添加属性', prop, value);return result;},// 删除某个属性deleteProperty(target, prop) {const result = Reflect.deleteProperty(target, prop);console.log('拦截了删除数据', prop);return result;}
}

2、调用函数

const proxyUser2 = reactive({name: '小明',car: {color: 'red'}
});
// 拦截到了读和修改的数据
proxyUser2.name += '==';
// 拦截到了读和修改的数据
proxyUser2.car.color = '==';
// 拦截了删除
delete proxyUser2.name;
// 拦截到了读和拦截到了删除
delete proxyUser2.car.color;

vue3之ref获取元素

1、概念

利用ref函数获取组件中的标签元素。


2、示例代码
功能需求

让输入框自动获取焦点。


<template><h2>ref的另一个作用:可以获取页面中的元素</h2><input type="text" ref="inputRef" />
</template>

import { defineComponent, onMounted, ref } from "vue";
export default defineComponent({name: "App",// 需求:当页面加载完毕后,页面中的文本框可以直接获取焦点(自动获取焦点)setup() {// 默认是空的,页面加载完毕,说明组件已经存在了,获取文本框元素const inputRef = ref<HTMLElement | null>(null);// 页面加载后的生命周期组合APIonMounted(() => {inputRef.value && inputRef.value.focus(); // 自动获取焦点});return {inputRef,};},
});

vue3手写reactive、深的劫持、深的监视、深的响应数据

1、函数实现

// 定义一个reactive函数,传入一个目标对象
function reactive(target) {// 判断当前的目标对象是不是object类型(对象/数组)if (target && typeof target === 'object') {// 对数组或者是对象中所有的数据进行reactive的递归处理// 先判断当前的数据是不是数组if (Array.isArray(target)) {// 数组的数据要进行遍历操作0target.forEach((item, index) => {// 如果数组中还有数组// 使用递归target[index] = reactive(item);});} else {// 再判断当前的数据是不是对象// 对象的数据也要进行遍历的操作Object.keys(target).forEach(key => {target[key] = reactive(target[key]);});}return new Proxy(target, reactiveHandler);}// 如果传入的数据是基本类型的数据,那么就直接返回return target;
}// 定义一个reactiveHandler处理对象
const reactiveHandler = {// 获取属性值get(target, prop) {if (prop === '_is_reactive') return true;const result = Reflect.get(target, prop);console.log('拦截了读取数据', prop, result);return result;},// 修改属性值或者是添加属性set(target, prop, value) {const result = Reflect.set(target, prop, value);console.log('拦截了修改数据或者是添加属性', prop, value);return result;},// 删除某个属性deleteProperty(target, prop) {const result = Reflect.deleteProperty(target, prop);console.log('拦截了删除数据', prop);return result;}
}

2、调用函数

const proxyUser2 = reactive({name: '小明',car: {color: 'red'}
});
// 拦截到了读和修改的数据
proxyUser2.name += '==';
// 拦截到了读和修改的数据
proxyUser2.car.color = '==';
// 拦截了删除
delete proxyUser2.name;
// 拦截到了读和拦截到了删除
delete proxyUser2.car.color;

vue3手写readonly、深只读

1、函数实现

// 定义了一个readonlyHandler处理器
const readonlyHandler = {get(target, prop) {if (prop === '_is_readonly') return true;const result = Reflect.get(target, prop);console.log('拦截到了读取数据了', prop, result);return result;},set(target, prop, value) {console.warn('只能读取数据,不能修改数据或者添加数据');return true;},deleteProperty(target, prop) {console.warn('只能读取数据,不能删除数据');return true;}
}// 定义一个readonly函数
function readonly(target) {// 需要判断当前的数据是不是对象if (target && typeof target === 'object') {// 判断target是不是数组if (Array.isArray(target)) {// 遍历数组target.forEach((item, index) => {target[index] = readonly(item);});} else {// 判断target是不是对象// 遍历对象Object.keys(target).forEach(key => {target[key] = readonly(target[key]);});}return new Proxy(target, readonlyHandler);}// 如果不是对象或者数组,那么直接返回return target;
}

2、函数调用

const proxyUser4 = readonly({name: '小明',cars: ['奔驰', '宝马']
});
// 拦截到了读取
console.log(proxyUser4.name);
console.log(proxyUser4.cars[0]);
// 只读的
proxyUser4.name = '哈哈';
// 只读的
proxyUser4.cars[0] = '哈哈';
delete proxyUser4.name;
delete proxyUser4.cars[0];

vue3手写shallowReactive、浅的劫持、浅的监视、浅的响应数据

1、函数实现

// 定义一个reactiveHandler处理对象
const reactiveHandler = {// 获取属性值get(target, prop) {if (prop === '_is_reactive') return true;const result = Reflect.get(target, prop);console.log('拦截了读取数据', prop, result);return result;},// 修改属性值或者是添加属性set(target, prop, value) {const result = Reflect.set(target, prop, value);console.log('拦截了修改数据或者是添加属性', prop, value);return result;},// 删除某个属性deleteProperty(target, prop) {const result = Reflect.deleteProperty(target, prop);console.log('拦截了删除数据', prop);return result;}
}// 定义一个shallowReactive函数,传入一个目标对象
function shallowReactive(target) {// 判断当前的目标对象是不是object类型(对象/数组)if (target && typeof target === 'object') {return new Proxy(target, reactiveHandler);}// 如果传入的数据是基本类型的数据,那么就直接返回return target;
}

2、函数调用

const proxyUser1 = shallowReactive({name: '小明',car: {color: 'red'}
});
// 拦截到了读和写的数据
proxyUser1.name += '==';
// 拦截到了读取数据,但是拦截不到写的数据
proxyUser1.car.color + '==';
// 拦截到了删除数据
delete proxyUser1.name;
// 只拦截到了读,但是拦截不到删除
delete proxyUser1.car.color;

vue3provide和inject、实现跨层级组件间通信、祖孙组件

1、爷爷组件(页面)
1.1、html部分

<template><h2>provide 与 inject</h2><p>当前的颜色:{{ color }}</p><button @click="color = 'red'">红色</button><button @click="color = 'yellow'">黄色</button><button @click="color = 'green'">绿色</button><hr /><Son />
</template>

1.2、typescript部分

import { defineComponent, provide, ref } from "vue";
import Son from "./components/Son.vue";
export default defineComponent({name: "App",components: {Son,},setup() {// 响应式的数据const color = ref("red");// 提供数据provide("color", color);return {color,};},
});

2、父组件
2.1、html部分

<template><h3>Son子级组件</h3><hr /><GrandSon />
</template>

2.2、typescript部分

import { defineComponent } from "vue";
import GrandSon from "./GrandSon.vue";
export default defineComponent({name: "Son",components: {GrandSon,},
});

3、孙子组件
3.1、html部分

<template><h3 :style="{ color }">GrandSon孙子组件</h3>
</template>

3.2、typescript部分

import { defineComponent, inject } from "vue";
export default defineComponent({name: "GrandSon",setup() {// 注入的操作const color = inject("color");return {color,};},
});

vue3shallowReactive与shallowRef

1、概念

shallowReactive:只处理对象内最外层属性的响应式,也就是浅响应式。
shallowRef:只处理value的响应式, 不进行对象的reactive处理。
●什么时候用浅响应式呢?
○一般情况下使用ref和reactive即可。
○如果一个对象数据, 结构比较深, 但变化时只是外层属性变化使用shallowReactive
○如果一个对象数据, 后面会产生新的对象来替换使用shallowRef


2、示例代码

<template><h2>shallowReactive和shallowRef</h2><h3>m1:{{ m1 }}</h3><h3>m2:{{ m2 }}</h3><h3>m3:{{ m3 }}</h3><h3>m4:{{ m4 }}</h3><hr /><button @click="update">更新数据</button>
</template>

import {defineComponent,reactive,ref,shallowReactive,shallowRef,
} from "vue";export default defineComponent({name: "App",setup() {// 深度劫持(深监视)----深度响应式const m1 = reactive({name: "鸣人",age: 20,car: {name: "奔驰",color: "red",},});// 浅劫持(浅监视)----浅响应式const m2 = shallowReactive({name: "鸣人",age: 20,car: {name: "奔驰",color: "red",},});// 深度劫持(深监视)----深度响应式----做了reactive的处理const m3 = ref({name: "鸣人",age: 20,car: {name: "奔驰",color: "red",},});// 浅劫持(浅监视)----浅响应式const m4 = shallowRef({name: "鸣人",age: 20,car: {name: "奔驰",color: "red",},});const update = () => {// 更改m1的数据---reactive方式// m1.name += '=='// m1.car.name += '=='// 更改m2的数据---shallowReactive// m2.name += '=='// m2.car.name += '==='// 更改m3的数据---ref方式// m3.value.name += '==='// m3.value.car.name += '==='// 更改m4的数据---shallowRef方式// m4.value.name += '==='// m4.value.name += '==='console.log(m3, m4);};return {m1,m2,m3,m4,update,};},
});

vue3toRefs

1、概念

把一个响应式对象转换成普通对象,该普通对象的每个property都是一个ref。
应用:当从合成函数返回响应式对象时,toRefs非常有用,这样消费组件就可以在不丢失响应式的情况下对返回的对象进行分解使用。
问题:reactive对象取出的所有属性值都是非响应式。
解决:利用toRefs可以将一个响应式reactive对象的所有原始属性转换为响应式的ref属性。


2、示例代码

<template><h2>toRefs的使用</h2><!-- <h3>name:{{ state.name }}</h3><h3>age:{{ state.age }}</h3> --><h3>name:{{ name }}</h3><h3>age:{{ age }}</h3><h3>name2:{{ name2 }}</h3><h3>age2:{{ age2 }}</h3>
</template>

import { defineComponent, reactive, toRefs } from "vue";function useFeatureX() {const state = reactive({name2: "自来也",age2: 47,});return {...toRefs(state),};
}export default defineComponent({name: "App",setup() {const state = reactive({name: "自来也",age: 47,});// toRefs可以把一个响应式对象转换成普通对象,该普通对象的每个 property 都是一个 ref// const state2 = toRefs(state)const { name, age } = toRefs(state);// console.log(state2)// 定时器,更新数据,(如果数据变化了,界面也会随之变化,肯定是响应式的数据)setInterval(() => {// state.name += '=='// state2.name.value+='==='name.value += "===";console.log("======");}, 1000);const { name2, age2 } = useFeatureX();return {// state,// 下面的方式不行啊// ...state // 不是响应式的数据了---->{name:'自来也',age:47}// ...state2  toRefs返回来的对象name,age,name2,age2,};},
});

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/192223.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

BearPi Std 板从入门到放弃 - 1 引气入体篇

安装相关开发工具 Keil MDK 工具下载 略, 自行体会 Keil 芯片支持包下载 Keil 包 网址 https://www.keil.com/pack 此处下载的是STM32L4xx的支持包 https://www.keil.com/pack/Keil.STM32L4xx_DFP.2.6.2.pack STM32CubeMX 下载与包下载 i. 下载&#xff08;需要使用用户&…

DouyinAPI接口系列丨Douyin商品详情数据接口丨Douyin视频详情数据接口

抖音商品详情API是抖音开放平台提供的一套API接口&#xff0c;用于获取商品详情信息。通过该API&#xff0c;开发者可以获取到商品的详细信息&#xff0c;包括商品ID、名称、描述、价格、销量、评价等信息。 在使用抖音商品详情API之前&#xff0c;需要先注册并登录抖音开放平…

fl studio21.2最新汉化中文完整版网盘下载

fl studio 21中文版是Image-Line公司继20版本之后更新的水果音乐制作软件&#xff0c;很多用户不太理解&#xff0c;为什么新版本不叫fl studio 21或fl studio2024&#xff0c;非得直接跳到21.2版本&#xff0c;其实该版本是为了纪念该公司22周年&#xff0c;所以该版本也是推出…

系统监控:使用日志文件 journalctl的使用

journalctl 显示最近登录的&#xff1a; 上面有最近登录的时间&#xff0c;和系统操作 几十年来&#xff0c;Linux日志记录一直由syslogd守护进程管理。Syslogd将收集系统处理和应用程序发送到/dev/log伪设备的日志消息。然后&#xff0c;它会将消息定向到/var/log/目录中适当…

MacDroid Pro for Mac – 安卓设备文件传输助手,实现无缝连接与传输!

想要在Mac电脑上轻松管理和传输您的安卓设备文件吗&#xff1f;MacDroid Pro for Mac 是您的最佳选择&#xff01;这款强大的文件传输助手可以让您在Mac上与安卓设备之间实现快速、方便的文件传输。 MacDroid Pro for Mac 提供了简单易用的界面&#xff0c;让您能够直接在Mac上…

人工智能和网络安全:坏与好

人工智能似乎可以并且已经被用来帮助网络犯罪和网络攻击的各个方面。 人工智能可以用来令人信服地模仿真人的声音。人工智能工具可以帮助诈骗者制作更好、语法正确的网络钓鱼消息&#xff08;而糟糕的语法往往会暴露出漏洞&#xff09;&#xff0c;并将其翻译成多种语言&…

字符函数 和 字符串函数

今天我打算介绍一些字符函数和字符串函数&#xff0c;有一些字符串函数我实现了模拟&#xff0c;但文章中没有放出来&#xff0c;如果需要的欢迎来到我的gitee里面拿取&#xff08;在test.c11-23里面&#xff09; 这是我的gitee:小汐 (lhysxx) - Gitee.com 字符函数 1. islow…

matlab操作方法(一)——向量及其操作

1.向量及其操作 matlab是英文Matrix Laboratory&#xff08;矩阵实验室&#xff09;的简称&#xff0c;是基于矩阵运算的操作环境。matlab中的所有数据都是以矩阵或多维数组的形式存储的。向量和标量是矩阵的两种特殊形式 向量是指单行或者单列的矩阵&#xff0c;它是构成矩阵…

C语言易错知识点八(结构体)

结构体 世间万物&#xff0c;上至飞禽&#xff0c;下至走兽&#xff0c;全都知道一件事&#xff1a;三个臭皮匠&#xff0c;顶个诸葛亮。&#xff08;假的&#xff09;即使是处于人类前沿的编程语言也知道要把数据联合在一起&#xff0c;于是便有了数组&#xff0c;结构体&…

org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource

DynamicDataSource-CSDN博客 /** Copyright 2002-2020 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the L…

鸿蒙工具DevEco Studio调试Build task failed. Open the Run window to view details.

DevEco Studio 预览代码时候出现的问题 1.进入设置 2.打开设置&#xff0c;构建&#xff0c;执行&#xff0c;部署下面的Hvigor&#xff0c; 把构建守护进程关掉就行。 然后重启启动一下就好了

破解app思路

1.会看smali代码逻辑 一.快速定位关键代码 1.分析流程 搜索特征字符串 搜索关键 api 通过方法名来判断方法的功能 2.快速定位关键代码 反编译 APK 程序 AndroidManifest.xml>包名/系统版本/组件 程序的主 activity(程序入口界面) 每个 Android 程序…

Redis SDS 源码

底层数据结构的好处&#xff1a; 杜绝缓冲区溢出。减少修改字符串长度时所需的内存重分配次数。二进制安全。兼容部分C字符串函数。 常用命令&#xff1a; set key value、get key 等 应用场景&#xff1a;共享 session、分布式锁&#xff0c;计数器、限流。 1、给char*定义…

前端请求patch接口,只传入已修改字段值的字段

目录 前端仅传递发生更改的字段 为什么 数据举例 递归对比函数 从回显数据到提交更新接口的模拟操作 前端仅传递发生更改的字段 在实际开发中前端肯定会遇到一个更新需求&#xff0c;回显数据 > 修改数据 > 请求更新接口这个步骤。 通常建议前端仅传递发生更改的字…

【重点】【哈希】128.最长连续序列

题目 思路&#xff1a;https://leetcode.cn/problems/longest-consecutive-sequence/solutions/2362995/javapython3cha-xi-biao-ding-wei-mei-ge-l-xk4c/?envTypestudy-plan-v2&envIdtop-100-liked class Solution {public int longestConsecutive(int[] nums) {Set<…

<JavaEE> volatile关键字 -- 保证内存可见性、禁止指令重排序

目录 一、内存可见性 1.1 Java内存模型(JMM) 1.2 内存可见性演示 二、指令重排序 三、关键字 volatile 一、内存可见性 1.1 Java内存模型(JMM) 1&#xff09;什么是Java内存模型&#xff08;JMM&#xff09;&#xff1f;Java内存模型即Java Memory Model&#xff0c;简…

如何使用注解实现接口的幂等性校验

如何使用注解实现接口的幂等性校验 背景什么是幂等性为什么要实现幂等性校验如何实现接口的幂等性校验1. 数据库唯一主键2. 数据库乐观锁3. 防重 Token 令牌4. redis 如何将这几种方式都组装到一起结语 背景 最近在小组同学卷的受不了的情况下&#xff0c;我决定换一个方向卷去…

在 MySQL 中创建用户和分配权限

在 MySQL 中创建用户和分配权限 登录到 MySQL&#xff1a; 首先&#xff0c;使用 root 用户或其他具有足够权限的用户登录到 MySQL&#xff1a; mysql -u root -p创建新用户&#xff1a; 在 MySQL 提示符下&#xff0c;使用以下命令创建新用户&#xff1a; CREATE USER newuser…

基于景区智慧灯杆、智能指路牌基础设施的景区建设应用

智慧景区是指运用现代信息技术手段&#xff0c;将景区内的资源、服务、管理等进行数字化、网络化和智能化整合&#xff0c;打造出高效便捷、安全舒适、互动体验和可持续发展的景区。智慧景区可以从以下几个方面进行体现&#xff1a; 智慧导览&#xff1a;通过使用智能化的导览…

二分查找:LeetCode2035:将数组分成两个数组并最小化数组和的差

本文涉及的基础知识点 二分查找算法合集 作者推荐 动态规划LeetCode2552&#xff1a;优化了6版的1324模式 题目 给你一个长度为 2 * n 的整数数组。你需要将 nums 分成 两个 长度为 n 的数组&#xff0c;分别求出两个数组的和&#xff0c;并 最小化 两个数组和之 差的绝对…