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. 不会创建对它…...
获取网络ppt资源
背景: 某度上有很多优质的PPT资源和文档资源,但是大多数需要付费才能获取。对于一些经济有限的用户来说,这无疑是个遗憾,因为我们更倾向于以免费的方式获取所需资源。 解决方案: 然而,幸运的是&am…...
从0到1构建智能分布式大数据爬虫系统
文章目录 1. 写在前面2. 数据获取挑战3. 基础架构4. 爬取管理5. 数据采集6. 增量与去重设计 【作者主页】:吴秋霖 【作者介绍】:Python领域优质创作者、阿里云博客专家、华为云享专家。长期致力于Python与爬虫领域研究与开发工作! 【作者推荐…...
C语言速通笔记(41-62)
40.十六进制转义字符:\x6d才是合法的,前面的0不能写,而且 x 是小写 41.字符型和整型是近亲:两个具有很大的相似之处,所有的字符都有一个它对应的整形数 据的 ASCLL 的数值。如 char a 65 % …...
Python 调用企业微信群机器人发送消息及文件
Python 操作企业微信群机器人。 企业微信群创建机器人 : 安装 requests json : pip install requests pip install json发送消息(markdown) import requests import json# 企业微信机器人发送文字 def send_markdown (message, …...
数据结构:链表应用:第6关:链表的分解
任务描述 本关任务:利用单链表A表示一个非零整数序列,把A分解为两个具有相同结构的链表B和C,其中B表的结点为A表中值小于零的结点,而C表的结点为A表中值大于零的结点。要求空间复杂度为O(1),链表B和C均利用链表A的结点…...
10折交叉验证(10-fold Cross Validation)与留一法(Leave-One-Out)
概念: 交叉验证法,就是把一个大的数据集分为 k个小数据集,其中 k − 1 个作为训练集,剩下的 1 个作为测试集,在训练和测试的时候依次选择训练集和它对应的测试集。这种方法也被叫做 k 折交叉验证法(k-fold…...
中小企业:理解CRM与ERP系统的区别与联系,提升业务效能
许多中小型企业正面临着客户递增,市场营销,货存流通等递增数据整合的困扰。这个时候需要根据自身企业的实际情况去选择适合自己的系统。那么,中小企业使用CRM系统和erp系统的区别是什么? 一、含义和目标区别 CRM系统旨在帮助企业…...
01数仓平台 Hadoop介绍与安装
Hadoop概述 Hadoop 是数仓平台的核心组件。 在 Hadoop1.x 时代,Hadoop 中的 MapReduce 同时处理业务逻辑运算和资源调度,耦合性较大。在 Hadoop2.x 时代,增加了 Yarn。Yarn 只负责资源的调度,MapReduce 只负责运算。Hadoop3.x 在…...
网络编程HTTP协议进化史
一、Http报文格式 具有约定格式的数据块 请求报文 request 状态行:本次请求的请求方式(post get)资源路径url http 协议的版本号,中间用空格划分 本次请求的请求方式(post get)资源路径url http 协议…...
第17章 匿名函数
第17.1节 匿名函数的基本语法 [捕获列表](参数列表) mutable(可选) 异常属性 -> 返回类型 { // 函数体 }语法规则:lambda表达式可以看成是一般函数的函数名被略去,返回值使用了一个 -> 的形式表示。唯一与普通函数不同的是增加了“捕获列表”。 …...
四川微信网站建设/游戏推广员好做吗
下图中,我画出了Spring MVC中,跟异常处理相关的主要类和接口。 1.包含文件 spring.xmlmessages_zh_CN.propertiesmessages_en_US.propertiesExceptionHandle.javaXXController.java2.文件内容 spring.xml <mvc:annotation-driven validator"vali…...
网站策划书格式/全网品牌推广
Elasticsearch.安装(单节点) 环境Linux 7.x jdk 1.8 elasticsearch 5.x 环境目录结构(根目录多了两个文件夹): /resources /** 存放下载的文件 **/ /u01/app /** 安装elasticsearch的目录. **/ 在linux的终端执行指令: …...
上海网站se0优化/营销类网站
作者 | Tina & Jenny专栏 | 九章算法 到了职业发展的中后期, 程序员多将面临一个艰难的抉择: 是继续从事编程开发走的技术路线, 还是转为管理层面的发展路线? 开发人员的职业发展能否避开向管理层面的转变? 这是一…...
杭州网站建设代理商/今日军事新闻头条
pip更新及Requirement already up-to-date解决方法参考文章: (1)pip更新及Requirement already up-to-date解决方法 (2)https://www.cnblogs.com/tielemao/p/9628754.html 备忘一下。...
专业APP客户端做网站/国产搜什么关键词最好看
转自:https://juejin.cn/post/68982703130505379971.索引类型 keyof 索引类型查询操作符,可以获取泛型T上所有的 public 属性名构成联合类型class Person { name: string "胡先生" age: number 18 private UserId: number 123}typ…...
网站开发中所需要的绘图工具/百度账号安全中心
349. 两个数组的交集 给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 简单难度。使用两个Hashset,首先遍历一个数组加入到第一个set集合,然后遍历第二个数组看是否…...