Vue3.0的变化

2023-12-17  本文已影响0人  渚清与沙白
setup函数

RefImpl :引用对象,是一个对象,ref函数的返回值。


image.png
ref
reactive
ref与reactive对比

响应式原理

vue2的响应式
// 只能进行读取和修改,无法进行新增和删除属性
Object.defineProperty(data, 'count',{
  get(){},
  set(){}
})
vue3的响应式
<script>
  let person = { name: "张三", age: 10 };
  const p = new Proxy(person, {
        // 获取属性值
        get(target, key) {
          console.log(`监测到访问${key}属性`);
          // return target[key];
          return Reflect.get(target, key);
        },
        // 修改 或 新增 属性
        set(target, key, value) {
          console.log(`检测到 修改${key}属性`);
          // target[key] = value;
          Reflect.set(target, key, value);
        },
        // 删除属性
        deleteProperty(target, key) {
          console.log(`检测到 删除${key}属性`);
          // return delete target[key];
          return Reflect.deleteProperty(target, key);
        },
    });
</script>
计算属性 computed

import { computed } from 'vue'

export default{
    setup(){
      let person = reactive({
        firstName:'',
        lastName:'',
    });
    // 简写形式,只读  无法修改
    person.fullNmae = computed(()=>{
      return firstName + '-' + lastName;
    });
    // 完整写法 支持读和写
    person.fullNmae = computed(()=>{
      get(){
        return person.firstName + '-' + person.lastName;
      },
      set(value){
        const arr = value.split('-');
        person.firstName = arr[0];
        person.lastName = arr[1];
      }
    });
    return { person }
  }
}
监视属性 watch
export default{
  setup(){
    let sum = ref(0);
    let msg = ref('xx');
    let person = reactive({
      name: '',
      age: 10,
      job: {
        j1: {
          salary: 20
        }
       }
    });

    // 情况一:监视ref所定义的一个响应式数据
    watch(sum,(newVal, oldVal)=>{  }, { immediate :true });// 监视多个 可以调用多次watch函数
   
    // 情况二:监视ref所定义的多个响应式数据
    watch([sum, msg],(newVal, oldVal) =>{  }); // 监视多个 可以调用多次watch函数

    /*
      情况三:监视reactive所定义的一个响应式数据的全部属性。
      注意:此处无法正确地获取到oldVal,oldVal与newVal的属性值【一样】
      注意:深度监视 deep 参数配置无效(reactive本身就支持深度响应式)
    */
    watch(person,(newVal, oldVal)=>{  }, { deep :false });// deep配置无效
    
    // 情况四:监视reactive所定义的一个响应式数据中的某个属性。传递一个函数。
    watch(()=>person.name,(newVal, oldVal)=>{  }, { immediate :true });
    
    // 情况五:监视reactive所定义的一个响应式数据中的多个属性。传递一个数组,元素是函数。
    watch([ ()=>person.name, ()=>person.age ],(newVal, oldVal)=>{  }, { immediate :true });
    
    // 情况六:监视的reactive所定义的对象中的某个属性(对象类型),所以deep配置有效
    watch(()=>person.job,(newVal, oldVal)=>{  }, { deep :true }); 

    // 情况七:监视ref所定义的对象类型响应式数据
    let student = ref({
      name: '',
      age: 20,
    });
    // 监视方式一  student是RefImpl类型,student.value的类型是Proxy类型
    watch(student.value, (newVal, oldVal)=>{});
    // 监视方式二
    watch(student, (newVal, oldVal)=>{}, {deep: true});
  
    // watchEffect  这里监视了salary和sum
    watchEffect(()=>{
        const salary = person.job.salary;
        const s = sum.value;
    });
    
    return { sum, msg, person};
  }
}

watch:要指明监视的属性,也要指明监视的回调
watchEffect:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性
watchEffect类似computed:computed注重计算出来的值,必须要写 返回值;watchEffect注重的是过程,不必写返回值

生命周期

组合式API生命周期钩子,与Vue中钩子对应关系

引入
import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted} from 'vue'

<script>
  export default{
    setup(){
      onBeforeMount(()=>{});
      onMounted(()=>{});
      onBeforeUpdate(()=>{});
      onUpdated(()=>{});
      onBeforeUnmount(()=>{});
      onUnmounted(()=>{});
    }
  }
</script>
自定义hook函数

hook本质是一个函数,把setup函数中使用的组合式API进行了封装。类似与Vue2中的mixin。
src/hooks/xxx.js创建一个JS文件,导出一个函数

import { onBeforeMount, onMounted, reactive } from 'vue'
export default function() {
    let point = reactive({
        x: 0,
        y: 0
    });
    function setPoint(event) {
        point.x = event.pageX;
        point.y = event.pageY;
    }
    onMounted(()=>{
        window.addEventListener('click', setPoint);
    })
    onBeforeMount(()=>{
        window.removeEventListener('click', setPoint);
    })
    return point;
}

在组件中使用hook

<script>
    import { usePoint } from '../hooks/usePoint'
    export default {
        setup() {
            const point = usePoint();
            return { point }
        }
    }
</script>
toRef 和 toRefs
<scrip> 
  setup(){
     let person = reactive({
      name: 'John Doe',
      job:{
        jQuery:{
        salary: 100000,
      },
    }
  })

  // 一次性处理多个属性
  return {
    person,
    ...toRefs(person)
  };
  
  // 每次处理一个
  return {
    person,
    name:toRef(person,'name'),
    salary:toRef(person.job.jQuery,'salary')
  };
}
</script>
shallowReactive 和 shallowRef

shallowReactive:浅层次的响应式,只处理对象最外层的响应式。其他层次的数据就不是响应式了
shallowRef:只处理基本数据类型的响应式,不处理对象的响应式。shallowRef与ref传递的是基本数据类型,作用一样,如果传递的是对象类型,shallowRef不会把对象处理成响应式,ref则会将对象处理成响应式

readonly 和 shallowReadonly
toRaw 和 markRaw
customRef
<script> 
setup(){
  function myRef(value,delay){
   let timer;
    return customRef((track, trigger) => {
      return {
        get() {
          track()// 追踪 数据变化
          return value
        },
        set(newValue) {
          clearTimeout(timer)
          timer = setTimeout(() => {
            value = newValue
            trigger()// 触发数据变化
          },delay)// 延时触发
        }
      }
    })
  }
  let key = myRef('hello');
  return { key };
}

</script>
provide 与 inject

组件间的通信方式,实现祖孙间的通信。父组件有一个provide选项来提供数据,后代组件有一个inject选项来开始使用这些数据。

  1. 祖组件
setup(){
  let car = reactive({name:'ben', price:'40w'});
  provide('car',car)
}
  1. 后代组件
setup(){
  const car = inject('car');
  return { car }
}
响应式数据的判断
组合式api与选项式api

新组件

  1. Fragment
  1. Teleport
    Teleport是一种能够将我们的组件html结构移动到指定位置的技术
<teleport to="body">
  <h3> title </h3>
</teleport>
  1. Suspense
import { defineAsyncComponent } from 'vue'
const Child = defineAsyncComponent(()=> import('./component/Child.vue'))

使用Suspense 包裹组件,并配置好 default 与 fallback

<template>
  <div class="app">
    <Suspense>

      <template v-slot:default>
        <Child/>
      </template>

      <template v-slot:fallback>
        <h3>加载中...</h3>
      </template>

    </Suspense>
  </div>
</template>
其他API的变化
  1. 全局API的转移
    Vue.config.xxx -> app.config
    Vue.config.productionTip -> 移除
    Vue.component -> app.component
    Vue.directive -> app.directive
    Vue.mixin -> app.mixin
    Vue.use -> app.use
    Vue.prototype -> app.config.globalProperties

  2. data选项应该始终被声明为一个函数

  3. 过渡类名的更改
    .v-enter -> .v-enter-from
    .v-leave -> .v-leave-from

  4. 移除keyCode作为v-on的修饰符,同时 不再支持config.keyCodes

  5. 移除v-on.native修饰符

v-on:close=""
v-on:click=""

export default {
  emits: ['close']// 声明了close事件,是一个自定义事件。没有声明click事件,默认为原生事件
}
  1. 移除过滤器
    建议使用计算属性或方法调用去实现
上一篇 下一篇

猜你喜欢

热点阅读