vue3学习笔记

在Vue3.0中创建响应式数据需要引用ref,reactive这两个方法,ref一般用来创建基本数据类型的响应式数据,reactive一般用来创建引用数据类型的响应式数据。
在模板中使用,跟之前没有区别,需要注意的是,ref属于将基本类型数据包装成应用类型,在模板中正常使用。在方法中访问的时候需要带上.value才能访问到。
为什么要这么写呢?是因为Proxy的原因,Proxy要进行数据劫持的时候需要接收一个对象,所以ref就对基本数据类型的数据进行了包装,使其可以进行响应式。
 
ref例子:
<template>
  <div>
    {{ count }}
    <button @click="add">+</button>
  </div>
</template>

<script>
import { ref } from "vue";

export default {
  /* 在Vue3.0中创建响应式数据需要引用ref,reactive这两个方法,ref一般用来创建基本数据类型的响应式数据,reactive一般用来创建引用数据类型的响应式数据。
在模板中使用,跟之前没有区别,需要注意的是,ref属于将基本类型数据包装成应用类型,在模板中正常使用。在方法中访问的时候需要带上.value才能访问到。为什么要这么写呢?是因为Proxy的原因,Proxy要进行数据劫持的时候需要接收一个对象,所以ref就对基本数据类型的数据进行了包装,使其可以进行响应式。 */

  name: "Test",
  setup(props, context) {
    const count = ref(0); // 定义响应式数据count
    const objData = {
      name: "erha",
      age: "1",
      skill: "拆家",
    };
    const add = ()=>{
      count.value++;  
    }
    return {
      count,
      add,
    };
  },
};
</script>
由于Proxy的机制原因,如果将reactive中的响应式数据进行解构,那么原先的响应式数据就变成不可响应的了。 
为什么将可观察对象中的属性解构出来后,变成不再可观察了呢?因为通过reactive方法创建的可观察对象,内部的属性本身并不是可观察的,而是通过Proxy代理实现的读写观察,如果将这些属性解构,这些属性就不再通过原对象的代理来访问了,就无法再进行观察。
Composition API提供了一种方法来解决此机制带来的问题,那就是toRefs,它可以将reactive创建的可观察对象,转换成可观察的ref对象
当使用了toRefs的时候在模板中只需要使用name即可
<template>
  <div>
    <!-- {{ data.age }} -->
    {{age}}
  </div>
</template>

<script>
import { reactive, toRefs } from "vue";

export default {
  /* 由于Proxy的机制原因,如果将reactive中的响应式数据进行解构,那么原先的响应式数据就变成不可响应的了。 为什么将可观察对象中的属性解构出来后,变成不再可观察了呢?因为通过reactive方法创建的可观察对象,内部的属性本身并不是可观察的,而是通过Proxy代理实现的读写观察,如果将这些属性解构,这些属性就不再通过原对象的代理来访问了,就无法再进行观察。Composition API提供了一种方法来解决此机制带来的问题,那就是toRefs,它可以将reactive创建的可观察对象,转换成可观察的ref对象 */
//   当使用了toRefs的时候在模板中只需要使用name即可

  name: "Test",
  setup(props, context) {
    const data = reactive({
      name: "lisa",
      age: 18,
    });
    let { name , age} = toRefs(data)
    // data.age = 20; //响应式
    // age = 30; //非响应式
    data.age = 30; //也是响应式
    return {
    //   data,
    ...toRefs(data)
    };
  },
};
</script>

Composition API提供的computed方法就相当于2.x版本中的计算属性。使用如下:

<template>
  <div>
    {{ count }}
    {{ doubeCount }}
  </div>
</template>

<script>
import { ref, computed } from "vue";

export default {
  /* Composition API提供的computed方法就相当于2.x版本中的计算属性。 */

  name: "Test",
  setup(props, context) {
    const count = ref(2);
    const doubeCount = computed(() => {
      return count.value * 2;
    });

    return { count, doubeCount };
  },
};
</script>

Composition API提供的watch方法相当于就是2.x的观察属性。

watch方法接收两个参数,第一个参数是一个函数,第二个参数也是个函数,第一个参数函数返回值表示要监听哪个数据,第二个参数函数,表示监听成功后的逻辑,该函数的第一个参数就是监听到目标数据变化后的值。同时watch可以监听多个数据。

使用如下:

<template>
  <div class="test">
    <div>watch: count+num:{{ countAddNum }}</div>
    <button @click="addCount">点击+1</button>
  </div>
</template>

<script>
import { ref, computed, watch } from "vue";
export default {
  /* watch方法接收两个参数,第一个参数是一个函数,第二个参数也是个函数,第一个参数函数返回值表示要监听哪个数据,第二个参数函数,表示监听成功后的逻辑,该函数的第一个参数就是监听到目标数据变化后的值。同时watch可以监听多个数据。 */
  name: "Test",
  setup() {
    const count = ref(0); // 定义响应式数据count
    const num = ref(1); // 定义响应式数据num

    const countAddNum = computed(() => {
      // 计算属性
      return count.value + num.value;
    });
    // 相当于watch
    watch(
      [() => count.value, () => num.value],
      ([count, num], [oldCount, oldNum]) => {
        // watch 同时观察count和num两个值
        console.log(
          `count:${count},num:${num} oldCount:${oldCount},oldNum:${oldNum}`
        );
      }
    );
    watch(
      () => {
        return count.value;
      },
      (newcount) => {
        console.log("count变啦", newcount);
      }
    );
    // 相当于methods
    const addCount = () => {
      // 定义增加count方法
      count.value++;
    };

    // 统一return出去
    return {
      count,
      num,
      addCount,
      countAddNum,
    };
  },
};
</script>
在Vue2.x版本中频繁出现的this,在Vue3.0中也消失了,取而代之的是Composition API提供的getCurrentInstance方法,用来获取当前组件实例,然后通过ctx获取当前上下文。
下面是路由跳转的例子:
<template>
  <button @click="pushRoute">push</button>
</template>

<script>
import { getCurrentInstance } from "vue";

export default {
  name: "Test",
  setup(props, context) {
    const { ctx } = getCurrentInstance();
    console.log(ctx);
    const pushRoute = () => {
      // 编程导航
      ctx.$router.push({
        path: "/",
      });
    };
    return {
      pushRoute,
    };
  },
};
</script>
 
 
最后看一下Vue3.0中的生命周期,生命周期也是有所改动,钩子函数名称均发生变化。
beforeCreate,created生命周期在setup方法中自动执行,其余生命周期钩子函数都是从Vue中引入使用(注意在setup方法中使用)
<template>
  <div>
    <h1>{{ msg }}</h1>
    <div>{{ a }}</div>
    <button @click="setA">加A</button>
  </div>
</template>
<script>
import {
  ref,
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
  onErrorCaptured,
  onRenderTracked,
  onRenderTriggered,
} from "vue";
export default {
  setup(props, context) {
    // console.log(props.msg, context)
    const a = ref(0);
    const setA = () => {
      return a.value++;
    };
    // 相当于 beforeMount
    onBeforeMount(() => {
      console.log("onBeforeMount");
    });
    // 相当于 mounted
    onMounted(() => {
      console.log("onMounted");
    });
    // 相当于 beforeUpdate
    onBeforeUpdate(() => {
      console.log("onBeforeUpdate");
    });
    // 相当于 updated
    onUpdated(() => {
      console.log("onUpdated");
    });
    // 相当于 beforeDestroy
    onBeforeUnmount(() => {
      console.log("onBeforeUnmount");
    });
    // 相当于 destroyed
    onUnmounted(() => {
      console.log("onUnmounted");
    });
    onErrorCaptured(() => {
      // 错误监控 参考文章 https://zhuanlan.zhihu.com/p/37404624
      console.log("onErrorCaptured");
    });
    onRenderTracked(() => {
      // 已渲染
      console.log("onRenderTracked");
    });
    onRenderTriggered(() => {
      // 当组件更新时会首先触发此生命周期钩子 onRenderTriggered->onRenderTracked->onBeforeUpdate->onUpdated
      console.log("onRenderTriggered");
    });
    return {
      a,
      setA,
    };
  },
  name: "HelloWorld",
  props: {
    msg: String,
  },
};
</script>

 参考:https://www.jianshu.com/p/b6ec99ff1cb5

原文地址:https://www.cnblogs.com/jervy/p/14081323.html