速懂vue3.0新特性及vue2.0区别

2022-08-02 10:56:25

欢迎点击:个人官网博客

2020年9月份beta版本出来后就一直追3.0,作为第一批吃螃蟹的人,这里把3.0的一些知识分享一下,良心之作。喜欢就收藏吧!

TypeScript传送门


从vue2.0到vue3.0必备知识

一、简单介绍vue3.0(性能比2.x快1.2~2倍)

  • Vue3支持大多数的Vue2的特性。如果3.0项目中2.0跟3.0混搭写法,方法重名的话3.0优先

  • Vue3中设计了一套强大的组合APi(Compostion API)代替了Vue2中的option API ,复用性更强了。可自定义hook函数,不需要代码都写在一个template(再也不怕代码多起来,滚轮滚到手发抖了)

  • 按需编译,体积比Vue2.x更小

  • Vue3更好的支持TypeScript(TS)

  • Vue3中使用了Proxy配合Reflect 代替了Vue2中Object.defineProperty()方法实现数据的响应式(数据代理)

  • 重写了虚拟DOM,速度更快了

  • 新的组件: Fragment(片段) / Teleport(瞬移) / Suspense(不确定)

  • 设计了一个新的脚手架工具—vite,npm run dev 秒开,热重载也很快。这种开发体验真是很爽,拒绝等待。

  • 全局 API 现在只能作为 ES 模块构建的命名导出进行访问

  • Vue3可多个根组件

  • Vue3中v-if优先于v-for,移除过滤器

二、常用Composition API

import{
  defineComponent,//目的是定义一个组件,vue3如果用ts,导出时候要用 defineComponent,这俩是配对的,为了类型的审查正确
  defineAsyncComponent,//vue3中动态引入组件
  provide,//祖孙组件传参
  inject,//祖孙组件传参
  reactive,//定义多个数据的响应式,可配合torefs使用方便
  toRefs,//torefs函数可以将reavtive创建的响应式对象转换成普通对象,该普通对象的每个 property 都是一个 ref,html模板中直接使用变量显示数据
  ref,//定义一个数据的响应式(一般是基本数据类型),通过.value获取到值,如果是object之类会自动转化为reactive
  computed,//计算属性,如果只传入一个回调函数,表示的是get,可get,set
  watch,//监听一个或多个属性或对象,默认不执行---可加参数immediate表示默认执行一次,deep表示深度监视
  watchEffect,//不需要配置immediate,默认就会执行一次。监视所有回调中使用的数据
  onMounted,//生命周期
  onUnmounted,
  onUpdated,
  onBeforeUpdate,
  onBeforeMount,
  onBeforeUnmount,
  nextTick,//整个视图都渲染完毕后
  customRef,//追踪数据并告诉Vue去触发界面更新,可用于对页面更新进行一个防抖
  readonly,//数据只读
  shallowReactive,// 只处理了对象内最外层属性的响应式(也就是浅响应式)
  shallowRef,//只处理了value的响应式, 不进行对象的reactive处理
  toRaw,//返回由 reactive 或 readonly 方法转换成响应式代理的普通对象。}from"vue";

1.setup(props,context)

setup是组合api的入口函数,函数返回对象,html模板中可以直接使用。
setup细节问题:
1.setup在beforeCreate之前执行。
在这里插入图片描述

由此推断setup在执行的时候,当前组件还没有创建出来,也意味着组件实例对象this根本不能用(undefined)
2.setup中的返回值是一个对象,内部的属性和方法是给html模板使用的。

  1. props即为父组件传递过来的值,当你在steup函数中获取值不能像vue2.0中this.值,是获取不到的,要props.值
  2. context上下文对象,里面有attrs,slots,emit
    在这里插入图片描述
import{defineComponent}from"vue";exportdefaultdefineComponent({setup(props,{attrs,slots,emit}){
    	console.log("this=>",this);//undefined
    	console.log(props);//父组件传过来是值
    	console.log(slots);//插槽
    	console.log(attrs);//当前组件标签上的属性,不带冒号的,带冒号是props//如<Child :msg="count" text="我是src" />  text是attrs,mag是props---------------------constaddCount=()=>{emit("demoHander","我的子组件传来的");//向父组件传参,这种写法父组件@demoHander='函数'//或者
      	props.demoHander('我的子组件传来的')//这种写法父组件:demoHander='函数'};return{};//必须为一个对象}});

2.ref,reactive

<template><div>{{ count}}{{state.age}}<button @click="add"></button></div></template><script lang="ts">import{ defineComponent, ref, reactive}from"vue";exportdefaultdefineComponent({setup(){// let count = 0;//这个数据不是响应式数据,(响应式数据:数据变化,页面跟着渲染)let count=ref(0);//ref一般定义一个数据的响应式(一般是基本数据类型,单独定义某一个常量),方法中要通过count.value获取到值,如果ref是一个对象也可以,会自动转为reactive---------------------------------------------let obj={
      name:"tom",
      age:25,
      wife:{
        name:"marry",
        age:22,},};let state=reactive(obj);//reactive一般定义多个数据(复杂数据类型)的响应式,如果不使用torefs的话,html模板中要使用state.age显示数据//方法constadd=()=>{
      count.value++;//操作ref定义的值
      state.age++;//操作reactive定义的值------------------------// obj.age++;这种方式页面不会更新渲染,需要操作代理对象才有用// delete state.wife//删除某个属性,页面会更新};return{
      count,
      add,
      state//响应式数据//...state 不是响应式数据//...toRefs(state) 响应式数据};},});</script>

reactive不能处理简单数据类型。如reactive(10)是无法响应式的,必须是一个对象reactive({ })
ref 是一个对象也可以,会自动转为reactive。如ref({ id:10 })
注意: 解构state 或者 扩展运算符都会使数据失去响应性
在这里插入图片描述

reactive改用toRefs配合使用

toRefs()函数可以将reactive创建出来的响应式对象,转换为普通对象,只不过这个对象上的每个属性节点,都是ref()类型的响应式数据
(使用…操作符返回的对象,不会失去响应性)

<template><div><!-- 不使用toRefs:{{state.age}}--><!--使用toRefs-->{{ age}}</div></template><script lang="ts">import{ defineComponent,reactive,toRefs}from"vue";exportdefaultdefineComponent({setup(){let obj={
      name:"tom",
      age:25,
      wife:{
        name:"marry",
        age:22,},};let state=reactive(obj);return{//state...toRefs(state)};},});</script>

ref获取元素

<template><div><input type="text" ref="inputRef" name="" id=""/></div></template><script lang="ts">import{ defineComponent, ref,}from"vue";exportdefaultdefineComponent({setup(){//通过ref自动获取焦点const inputRef= ref<HTMLElement|null>(null);onMounted(()=>{
      inputRef.value&& inputRef.value.focus();});return{
      inputRef,};},});</script>

如果项目中方法比较多时,可以这样处理,方便看
在这里插入图片描述

3.watch,watchEffect

watch监听一个属性或对象

setup(){let state=reactive({
      fristName:"东方",
      laetName:"不败",
      fallName3:""});------------方法一watch(state,({fristName,laetName})=>{
        fallName3.value=fristName+'_'+laetName},{immediate:true,deep:true})//immediate表示默认执行一次//deep表示深度监视------------方法二const stop=watch(()=> state.fristName,(val,oldval)=>{
    	console.log(val);},{deep:true});//直接调用stop(),可以清除监听return{...toRefs(state)};}

watch监听多个属性

//监听reactive创造出来的数据使用箭头函数,ref直接放
 watch([() => state.fristName, () => state.laetName, fallName3], (val) => {
      console.log(val);
    });

watchEffect

//watchEffect不需要配置immediate,默认就会执行一次// watchEffect: 监视所有回调中使用的数据watchEffect(()=>{
          fallName3.value= state.fristName+'_'+state.laetName})

vue2.0写法

  watch:{/**
     * 监听路由变化刷新页面
     */$route(to){
      logger.log("watch router invoke", to.query);this.initPage();},
    configureList:{handler(newVale){
        logger.log("watch configureList invoke", newVale);},
      deep:true,
      immediate:false,},},

4.computed

注意:计算属性如果只传入一个回调函数,表示的是get。

场景:三个input任意一个值变化,其他两个也会变化

<input type="text" v-model="state.fristName"/><input type="text" v-model="state.laetName"/><input type="text" v-model="fallName"/>

计算属性如果只传入一个回调函数,表示的是get。即fristName或laetName改变,fallName发生改变。但是fallName发生改变,其他两个值不会变化

setup(){let state=reactive({
      fristName:"东方",
      laetName:"不败",});//fallName 返回的是一个ref对象const fallName=computed(()=>{return state.fristName+"_"+ state.laetName;});}

解决办法:

computed有不光有get,还有set

const fallName=computed({get(){return state.fristName+"_"+ state.laetName;},set(val: any){const names= val.split("_");
        state.fristName= names[0];
        state.laetName= names[1];},});

5.生命周期

在这里插入图片描述

6. provide 和 inject(实现跨层级组件(祖孙)间通信),也可放在main.ts里面进行全局挂载使用

父组件

<template><h1>父组件</h1><p>当前颜色:{{color}}</p><Son/></template><script lang="ts">import{ provide, ref}from'vue'import Sonfrom'./Son.vue'exportdefault{
  name:'ProvideInject',
  components:{
    Son},setup(){const color=ref('red')provide('color', color)return{
      color}}}</script>

子组件

<template><h2>子组件</h2><GrandSon/></template><script lang="ts">import GrandSonfrom'./GrandSon.vue'exportdefault{
  components:{
    GrandSon},}</script>

孙组件

<template><h3:style="{color}">孙子组件:{{color}}</h3></template><script lang="ts">import{ inject}from'vue'exportdefault{setup(){const color=inject('color')return{
      color}}}</script>

7.自定义hook函数(即把函数抽出来复用)

抽离前:

<template><button @click="add">add</button><img:src="src" alt=""></template><script>import{reactive, toRefs}from"vue";exportdefault{setup(){const state=reactive({
    	index:1,
    	src:''});constadd=()=>{
       console.log(state.index)
    	state.index++;
    	console.log(state.index)};return{...toRefs(state),
      add};},};

抽离后:

<template><button @click="add">add</button><img:src="src" alt=""></template><script>import handerfrom'./hooks/demo.ts'import{toRefs}from"vue";exportdefault{setup(){let{state,add}=hander()return{...toRefs(state),
      add};},};

demo.ts

import{reactive}from"vue";exportdefaultfunctionuseMousePosition(){const state=reactive({
    		index:1,
    		src:''});constadd=()=>{
       	console.log(state.index)
    	state.index++;
    	console.log(state.index)};return{state,add}}

8.defineAsyncComponent配合Suspense异步组件使用

<script  lang="ts">import{ defineComponent, defineAsyncComponent}from"vue";// vue正常引入组件import SuspensChildfrom'@/components/Suspense/Son.vue'// vue2中动态引入组件的写法:(在vue3中这种写法不行)constAsyncCompotent=()=>import('./Son.vue')//vue3中动态引入组件const SuspensChild=defineAsyncComponent(()=>import("./Son.vue"));</script>

注意:由于组件是异步引入的,会有一瞬间的空白,所以可以用Suspense配合loading填充,可以让我们创建一个平滑的用户体验

<template><Suspense>//v-slot:default也可以写成#default<template v-slot:default><!-- 组件加载完后显示--><SuspensChild/><!-- 异步组件--></template><template v-slot:fallback><!-- 组件加载完前显示--><h1>LOADING...</h1><!--LOADING的内容--></template></Suspense></template><script  lang="ts">import{ defineComponent, defineAsyncComponent}from"vue";const Sus
  • 作者:web前端小龚
  • 原文链接:https://blog.csdn.net/qq_41560520/article/details/116599724
    更新时间:2022-08-02 10:56:25