当前位置: 首页 > news >正文

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,};},
});

相关文章:

web前端之vue3

MENU vue3响应式数据的判断、isRef、isReactive、isReadonly、isProxy、ref、reactive、readonlyvue3的生命周期vue3手写isRef、isReactive、isReadonly、isProxyvue3手写ref、深的refvue3手写shallowRef、浅的refvue3customRefvue3readonly与shallowReadonlyvue3toRaw与markRa…...

原来在C++的类中声明函数时可以不写参数名只写参数类型

2023年12月6日&#xff0c;周三上午 今天才发现原来可以这样写 在C的类中声明函数时可以不写参数名只写参数类型&#xff0c; 但是&#xff0c;在实现时必须写出参数名。 #include<iostream>class People { public:void move(int);void say(std::string);void doSomet…...

独孤思维:这里有蓝海项目,你要吗?

很多人&#xff0c;一看到蓝海项目&#xff0c;就趋之若鹜。 觉得红海项目太卷了&#xff0c;根本赚不到钱。 凡是认为蓝海项目不卷&#xff0c;可以做起来&#xff0c;做的轻松的&#xff0c;都是弱智和无能的表现。 你所能接触到的蓝海&#xff0c;根本就不是蓝海。 能够…...

外卖平台推荐算法的优化与实践

目录 引言 一、推荐算法的原理 二、推荐算法的挑战 三、实际案例分析 四、优化推荐算法的策略 五、结论 引言 在当今数字化社会&#xff0c;外卖平台成为了人们生活中不可或缺的一部分。为了提供更加个性化、高效的服务&#xff0c;外卖平台使用推荐算法成为了一项关键技…...

CONTROLLING VISION-LANGUAGE MODELS FOR MULTI-TASK IMAGE RESTORATION

CONTROLLING VISION-LANGUAGE MODELS FOR MULTI-TASK IMAGE RESTORATION (Paper reading) Ziwei Luo, Uppsala University, ICLR under review(6663), Cited:None, Stars: 350, Code, Paper. 1. 前言 像CLIP这样的视觉语言模型已经显示出对零样本或无标签预测的各种下游任务…...

HarmonyOS应用开发——页面

我们将对于多页面以及更多有趣的功能展开叙述&#xff0c;这次我们对于 HarmonyOS 的很多有趣常用组件并引出一些其他概念以及解决方案、页面跳转传值、生命周期、启动模式&#xff08;UiAbility&#xff09;&#xff0c;样式的书写、状态管理以及动画等方面进行探讨 页面之间…...

Java流Stream使用详解(练习)

练习 第一题 数据过滤 定义一个集合&#xff0c;并添加一些整数1,2,3,4,5,6,7,8,9,10过滤奇数&#xff0c;只留下偶数&#xff0c;并将结果保存起来 import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Collectors…...

请介绍一下MySQL的存储引擎及其特点

问题&#xff1a;请介绍一下MySQL的存储引擎及其特点。 回答&#xff1a; MySQL是一个开源的关系型数据库管理系统&#xff0c;它支持多种存储引擎&#xff0c;每个存储引擎都有其自身的特点和适用场景。下面是对MySQL常见存储引擎的简要介绍&#xff1a; InnoDB&#xff1a; …...

Python---魔术方法

1、什么是魔术方法 在Python中&#xff0c;__xxx__()的函数叫做魔法方法&#xff0c;指的是具有特殊功能的函数。 2、__init__()方法(初始化方法或构造方法) 思考&#xff1a;人的姓名、年龄等信息都是与生俱来的属性&#xff0c;可不可以在生产过程中就赋予这些属性呢&…...

手把手教你注册意大利商标

在当今全球商业环境中&#xff0c;拥有一个独特的商标可以为企业在市场竞争中提供重要优势。商标作为品牌形象的核心&#xff0c;有助于吸引潜在客户&#xff0c;提升品牌价值&#xff0c;增加客户忠诚度。在意大利&#xff0c;商标注册同样具有重要意义&#xff0c;它能为企业…...

pandas详细笔记

一&#xff1a;什么是Pandas from matplotlib import pyplot import numpy as np import pandas as pdarange np.arange(1, 10, 2) series pd.Series(arange,indexlist("ABCDE")) print(series)二&#xff1a;索引 三&#xff1a;切片 位置索引切片&#xff08;左闭…...

win11安装(未完待续)

学习补丁 test.bat 运行后需要重启 slmgr /ipk W269N-WFGWX-YVC9B-4J6C9-T83GX slmgr /skms kms.03k.org slmgr /ato 文件扩展名 主题 性能设置 开始按钮靠左 任务栏对齐方式-靠左 必备软件 f.lux redshift 360管家 驱动精灵 edge c*lash&#xff08;v2*ray不支持w…...

python之记录程序运行时长工具

python之记录程序运行时长工具 废话不多话&#xff0c;上代码 from datetime import datetime, timedelta import timestart_time datetime.now()while True:current_time datetime.now()elapsed_time current_time - start_timeformatted_time str(elapsed_time).split(…...

.Net core 6.0 升8.0

1 Update Visual Studio 2 3 用Nutget 更新不同套件版本 更新后结果如下&#xff1a;...

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

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

【EtherCAT详解】基于Wireshark的EtherCAT帧结构解析

写在前面 EtherCAT的报文比较繁琐,且一些参考书籍错误较多,且晦涩难懂,对于初学者,很难快速的入门。本文适用于有一定基础的研究者,如对报文有一些研究、对canopen协议有一定了解、并且对TwinCAT有了解的研究者。当然,对于初学者来说,也是很好的引导,少走很多弯路。本…...

C语言之程序的组成和元素格式

目录 关键字 运算符 标识符 姓名和标识符 分隔符 常量和字符串常量 自由的书写格式 书写限制 连接相邻的字符串常量 缩进 本节我们来学习程序的各组成元素&#xff08;关键字、运算符等&#xff09;和格式相关的内容。 关键字 在C语言中&#xff0c;相if和else这样的标识…...

HalconDotNet.HTupleAccessException:Index out of range

原因可能是没有生成hv_Qx的值&#xff0c;我这里是没有生成该值的区域。...

Delphi-线程

碰到身份证阅读器项目&#xff0c;直接放进trimmer里面读卡&#xff0c;导致主页面卡顿&#xff0c;就打算放进子线程里试一下&#xff0c;就有了这个尝试。 1.创建线程文件 直接点击左上角file新建other&#xff0c;delphi有自带的模版 这个勾选了&#xff0c;就是他会给你…...

WeakMap

WeakMap简介 作为es6一种新的数据结构&#xff0c;他是一种键值对的集合。与Map最大的区别有两个 1. 是其中的键必须是对象或非全局注册的符号。 全局注册的符号 const s1 Symbol.for(mySymbol) 非全局注册的符号 const s1 Symbol(mySymbol)了解Symbol.for 2. 不会创建对它…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

synchronized 学习

学习源&#xff1a; https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖&#xff0c;也要考虑性能问题&#xff08;场景&#xff09; 2.常见面试问题&#xff1a; sync出…...

VB.net复制Ntag213卡写入UID

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互

引擎版本&#xff1a; 3.8.1 语言&#xff1a; JavaScript/TypeScript、C、Java 环境&#xff1a;Window 参考&#xff1a;Java原生反射机制 您好&#xff0c;我是鹤九日&#xff01; 回顾 在上篇文章中&#xff1a;CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

今日科技热点速览

&#x1f525; 今日科技热点速览 &#x1f3ae; 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售&#xff0c;主打更强图形性能与沉浸式体验&#xff0c;支持多模态交互&#xff0c;受到全球玩家热捧 。 &#x1f916; 人工智能持续突破 DeepSeek-R1&…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...