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日,周三上午 今天才发现原来可以这样写 在C的类中声明函数时可以不写参数名只写参数类型, 但是,在实现时必须写出参数名。 #include<iostream>class People { public:void move(int);void say(std::string);void doSomet…...
独孤思维:这里有蓝海项目,你要吗?
很多人,一看到蓝海项目,就趋之若鹜。 觉得红海项目太卷了,根本赚不到钱。 凡是认为蓝海项目不卷,可以做起来,做的轻松的,都是弱智和无能的表现。 你所能接触到的蓝海,根本就不是蓝海。 能够…...

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

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应用开发——页面
我们将对于多页面以及更多有趣的功能展开叙述,这次我们对于 HarmonyOS 的很多有趣常用组件并引出一些其他概念以及解决方案、页面跳转传值、生命周期、启动模式(UiAbility),样式的书写、状态管理以及动画等方面进行探讨 页面之间…...
Java流Stream使用详解(练习)
练习 第一题 数据过滤 定义一个集合,并添加一些整数1,2,3,4,5,6,7,8,9,10过滤奇数,只留下偶数,并将结果保存起来 import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Collectors…...
请介绍一下MySQL的存储引擎及其特点
问题:请介绍一下MySQL的存储引擎及其特点。 回答: MySQL是一个开源的关系型数据库管理系统,它支持多种存储引擎,每个存储引擎都有其自身的特点和适用场景。下面是对MySQL常见存储引擎的简要介绍: InnoDB: …...
Python---魔术方法
1、什么是魔术方法 在Python中,__xxx__()的函数叫做魔法方法,指的是具有特殊功能的函数。 2、__init__()方法(初始化方法或构造方法) 思考:人的姓名、年龄等信息都是与生俱来的属性,可不可以在生产过程中就赋予这些属性呢&…...
手把手教你注册意大利商标
在当今全球商业环境中,拥有一个独特的商标可以为企业在市场竞争中提供重要优势。商标作为品牌形象的核心,有助于吸引潜在客户,提升品牌价值,增加客户忠诚度。在意大利,商标注册同样具有重要意义,它能为企业…...

pandas详细笔记
一:什么是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)二:索引 三:切片 位置索引切片(左闭…...

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

python之记录程序运行时长工具
python之记录程序运行时长工具 废话不多话,上代码 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 更新不同套件版本 更新后结果如下:...

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

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

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

HalconDotNet.HTupleAccessException:Index out of range
原因可能是没有生成hv_Qx的值,我这里是没有生成该值的区域。...

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

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

使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...

C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...

三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...