快速掌握-vue3

是什么

vue2 的升级版, 使用 ts 重构了代码, 带来了 Composition API RFC。 类似于 react hook 的写法。

  1. ts 重构,代码可读性更强
  2. vue3.x 使用 Proxy 取代 Vue2.x 版本的 Object.defineProperty
  3. 实现了 TreeShaking (当 Javascript 项目达到一定体积时,将代码分成模块会更易于管理。但是,当这样做时,我们最终可能会导入实际上未使用的代码。Tree Shaking 是一种通过消除最终文件中未使用的代码来优化体积的方法。)
  4. 支持 hook 写法 CompositionAPI。受 ReactHook 启发
  5. 支持 jsx
  6. Vue 3 的 Template 支持多个根标签,Vue 2 不支持
  7. 对虚拟 DOM 进行了重写、对模板的编译进行了优化操作
  8. 在 Vue2.x 中具名插槽和作用域插槽分别使用 slot 和 slot-scope 来实现, 在 Vue3.0 中将 slot 和 slot-scope 进行了合并 v-slot
  9. 在 Vue 3 中对自定义指令的 API 进行了更加语义化的修改,名称和组件生命周期名称相同
  10. v-model 变更:在自定义组件上使用 v-model 时,同一组件可以同时设置多个 v-model, 开发者可以自定义 v-model 修饰符

学到什么

  1. vue3 与 vue2 的核心区别
  2. Tree-Shaking
  3. 函数 setup()
  4. 函数 ref()
  5. 函数 isRef()
  6. 函数 toRefs()
  7. 函数 reactive()
  8. 函数 computed()、watch()
  9. LifeCycle Hooks(新的生命周期)
  10. Template refs
  11. vue3 的全局配置
  12. vue3 组件模板结构
  13. 实现 自定义 Hook
  14. 组件 teleport 任意门
  15. 组件 异步组件

vue3 与 vue2 的核心区别

  1. vue3.x 将使用 Proxy 取代 Vue2.x 版本的 Object.defineProperty
  2. Object.defineProperty 只能劫持对象的属性, 而 Proxy 是直接代理对象,由于 Object.defineProperty 只能劫持对象属性,需要遍历对象的每一个属性,如果属性值也是对象,就需要递归进行深度遍历。但是 Proxy 直接代理对象,不需要遍历操作
  3. Object.defineProperty 对新增属性需要手动进行 Observe

Tree-Shaking

当 Javascript 项目达到一定体积时,将代码分成模块会更易于管理。但是,当这样做时,我们最终可能会导入实际上未使用的代码。Tree Shaking 是一种通过消除最终文件中未使用的代码来优化体积的方法。

为什么:因为 Vue 实例是作为单个对象导出的,打包器无法分辨出代码中使用了对象的哪些属性。所以,我们需要单独引用

抽离了 一部分 vue2 中的公用函数,需要单独引用。以前的全局 API 现在只能通过具名导入,这一更改会对以下 API 有影响:

  • Vue.nextTick
  • Vue.observable(用 Vue.reactive 替换)
  • Vue.version
  • Vue.compile(仅限完整版本时可用)
  • Vue.set(仅在 2.x 兼容版本中可用)
  • Vue.delete(与上同)

setup 函数

组件提供的新属性,为了使用 vue3 CompositionAPI 新特性而启用的函数,它有自己独立的生命周期

vue3 取消了 beforeCreate 、created 两个钩子函数,统一用 setup 代替

  1. props 用来接收 props 数据
  2. context 上下文对象
  3. return 返回模板中需要使用的函数
setup(props, context) {
    context.attrs
    context.slots
    context.emit

    return {

    }
  }

ref() 函数

组件提供的新特性函数

创建一个响应式的数据对象,这个对象是响应式的,只返回一个 { value: ""} 值

import { defineComponent, ref } from "vue";
export default defineComponent({
  setup() {
    const name = ref < string > "hello";
    // 在js 中获取ref 中定义的值, 需要通过value属性
    console.log(name.value);
    return {
      name,
    };
  },
});

isRef() 函数

组件提供的新特性函数

isRef() 用来判断某个值是否为 ref() 创建出来的对象

import { defineComponent, isRef, ref } from "vue";
export default defineComponent({
  setup(props, context) {
    const name: string = "vue";
    const age = ref(18);
    console.log(isRef(age)); // true
    console.log(isRef(name)); // false
    return {
      age,
      name,
    };
  },
});

toRefs() 函数

组件提供的新特性函数

toRefs() 函数可以将响应式对象,转换为普通的对象。只不过,这个对象上的每个属性节点,都是 ref() 类型的响应式数据

import { defineComponent, reactive, ref, toRefs } from "vue";
export default defineComponent({
  setup(props, context) {
    let state = reactive({
      name: "hello",
    });
    const age = ref(18);
    return {
      ...toRefs(state),
      age,
    };
  },
});

reactive() 函数

组件提供的新特性函数

reactive() 函数接收一个普通对象,返回一个响应式的数据对象, 想要使用创建的响应式数据也很简单,创建出来之后,在 setup 中 return 出去,直接在 template 中调用即可

import { defineComponent, reactive, ref, toRefs } from "vue";
export default defineComponent({
  setup(props, context) {
    let state = reactive({
      name: "hello",
    });

    return state;
  },
});

computed()、watch() 函数

组件提供的新特性函数

computed() 函数 ,用来计算属性,返回的值是一个 ref 对象。

import { computed, defineComponent, ref } from "vue";
export default defineComponent({
  setup(props, context) {
    const age = ref(18);

    const computedAge = computed({
      get: () => age.value + 1,
      set: (value) => age.value + value,
    });
    // 为计算属性赋值的操作,会触发 set 函数, 触发 set 函数后,age 的值会被更新
    age.value = 100;
    return {
      age,
      computedAge,
    };
  },
});

watch() 函数,用来监听属性, 当数据源变化的时候才会被执行。

import { computed, defineComponent, reactive, toRefs, watch } from "vue";
interface Person {
  name: string;
  age: number;
}
export default defineComponent({
  setup(props, context) {
    const state = reactive({ name: "vue", age: 10 });

    watch(
      [() => state.age, () => state.name],
      ([newName, newAge], [oldName, oldAge]) => {
        console.log(newName);
        console.log(newAge);

        console.log(oldName);
        console.log(oldAge);
      }
    );
    // 修改age 时会触发watch 的回调, 打印变更前后的值, 此时需要注意, 更改其中一个值, 都会执行watch的回调
    state.age = 100;
    state.name = "vue3";
    return {
      ...toRefs(state),
    };
  },
});

LifeCycle Hooks 生命周期

组件提供的新特性函数

生命周期组件中新的写法

import { set } from "lodash";
import {
  defineComponent,
  onBeforeMount,
  onBeforeUnmount,
  onBeforeUpdate,
  onErrorCaptured,
  onMounted,
  onUnmounted,
  onUpdated,
} from "vue";
export default defineComponent({
  setup(props, context) {
    onBeforeMount(() => {
      console.log("beformounted!");
    });
    onMounted(() => {
      console.log("mounted!");
    });

    onBeforeUpdate(() => {
      console.log("beforupdated!");
    });
    onUpdated(() => {
      console.log("updated!");
    });

    onBeforeUnmount(() => {
      console.log("beforunmounted!");
    });
    onUnmounted(() => {
      console.log("unmounted!");
    });

    onErrorCaptured(() => {
      console.log("errorCaptured!");
    });

    return {};
  },
});

模板 Template refs

组件提供的新特性函数

通过 refs 来回去真实 dom 元素,onMounted 中可以得到 ref 的 RefImpl 的对象, 通过.value 获取真实 dom




vue 的全局配置

Vue3 可以在组件用通过 getCurrentInstance() 来获取全局 globalProperties 中配置的信息

const app = Vue.createApp({});
app.config.globalProperties.$http = "axios";

setup( ) {
  const { ctx } = getCurrentInstance();
  ctx.$http
}

vue3 组件模板结构




实现 自定义 Hook

功能性组件可以封装成 hook, 以 use 作为前缀,和普通的函数区分

import { ref, Ref, computed } from "vue";

type CountResultProps = {
  count: Ref;
  multiple: Ref;
  increase: (delta?: number) => void;
  decrease: (delta?: number) => void;
};

export default function useCount(initValue = 1): CountResultProps {
  const count = ref(initValue);

  const increase = (delta?: number): void => {
    if (typeof delta !== "undefined") {
      count.value += delta;
    } else {
      count.value += 1;
    }
  };
  const multiple = computed(() => count.value * 2);

  const decrease = (delta?: number): void => {
    if (typeof delta !== "undefined") {
      count.value -= delta;
    } else {
      count.value -= 1;
    }
  };

  return {
    count,
    multiple,
    increase,
    decrease,
  };
}

使用 hook




组件 teleport 任意门

目的: 即希望继续在组件内部使用 Dialog, 又希望渲染的 DOM 结构不嵌套在组件的 DOM 中

场景: 弹框

我们可以用包裹 Dialog, 此时就建立了一个传送门,可以将 Dialog 渲染的内容传送到任何指定的地方。使用 teleport 组件,通过 to 属性,指定该组件渲染的位置与

同级,也就是在 body 下,但是 Dialog 的状态 dialogVisible 又是完全由内部 Vue 组件控制.


  
// Dialog.vue


// Footer.vue 子组件


组件 异步组件

Vue3 中 使用 defineAsyncComponent 定义异步组件,配置选项 component 替换为 loader ,Loader 函数本身不再接收 resolve 和 reject 参数,且必须返回一个 Promise。




参考

  1. vue3 官网 https://v3.vuejs.org/
  2. 构建 vite https://github.com/vitejs/vite
  3. vue3 源码 https://github.com/vuejs/vue-next
  4. vue-cli https://cli.vuejs.org/
  5. vue-router https://github.com/vuejs/vue-router-next

你可能感兴趣的:(快速掌握-vue3)