web前端之vue3


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({
    
    }))); // true
    console.log(isProxy(reactive({
    
    }))); // true

    return {
    
    };
  },
});

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)) {
    
    
      // 数组的数据要进行遍历操作0
      target.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、函数实现

扫描二维码关注公众号,回复: 17148113 查看本文章
// 定义一个reactive函数,传入一个目标对象
function reactive(target) {
    
    
  // 判断当前的目标对象是不是object类型(对象/数组)
  if (target && typeof target === 'object') {
    
    
    // 对数组或者是对象中所有的数据进行reactive的递归处理
    // 先判断当前的数据是不是数组
    if (Array.isArray(target)) {
    
    
      // 数组的数据要进行遍历操作0
      target.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)) {
    
    
      // 数组的数据要进行遍历操作0
      target.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);
    // 页面加载后的生命周期组合API
    onMounted(() => {
    
    
      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)) {
    
    
      // 数组的数据要进行遍历操作0
      target.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,
    };
  },
});

猜你喜欢

转载自blog.csdn.net/weixin_51157081/article/details/123181627