学习Vue3

学习并使用Vue3

  • 学习 Vue3
    • 什么是 Vue3 ?
    • setup
    • 定义响应式数据
      • ref
      • reactive
      • 计算属性与监视
    • 生命周期
      • vue2 的生命周期
      • vue3 的生命周期
      • vue3较vue2生命周期的变化
    • hooks
    • toRef 和 toRefs
      • toRef
      • toRefs
    • 新增组件
      • Fragment(片断)
      • Teleport(瞬移)
      • Suspense(不确定的)

学习 Vue3

什么是 Vue3 ?

2020年9月发布正式版的 vue3,vue3 很好兼容了大部分 vue2 的特性,因此熟悉 vue2 的小伙伴能快速上手 vue3。

vue3 较 vue2 来说,有几个非常出色的改进:

  1. 体积
  2. 速度
  3. 易维护性
  4. 更好兼容 ts

接下来我们就聊聊关于 vue3 的部分知识点,其余知识点具体可查阅 vue3中文文档。

setup

vue3 新增的 option,只在组件初始化时执行一次, setup 功能很强大,vue3 中所有的组合 API 均在此使用。

以往 vue2 的功能基本都能在 setup 中实现,例如 state 定义响应式数据,methods 声明方法,还有之后说的生命周期组合 API 等等都可在 setup 中实现,所以 setup 非常重要!

  • setup 没有 this,故无法通过 this 访问 data / computed / methods / props

  • setup 返回值

    • 一般返回在 setup 中定义的响应式数据以及声明操作数据的方法。
    setup() {
           
        // 使用 reactive 定义一个引用类型的响应式数据
        const user = reactive({
           
          name: '小红',
          age: 18
        });
        // 声明操作数据的方法
        const changeName = () => {
           
          user.name = '小明'
        }
        // 返回响应式数据和方法
        return {
           
          user,
          changeName
        }
      }
    
    • vue3 中尽量不要使用setup 与 state 和 methods 一起混着使用
      • setup 返回的响应式数据会与 state 中定义的响应式数据合并成组件对象的属性
      • setup 返回的方法会与 methods 定义的方法合并成组件对象的方法
      • 如果 setup 返回的属性 / 方法 与 state / methods 中的重名,则 setup 中的属性 / 方法会覆盖 state / methods 中的重名属性 / 方法。
      • 最重要一点:setup 中没有 this,故无法操作 state 中的属性以及 methods 中的方法,但 methods 却可以访问 setup 中定义的属性和方法!
  • setup 参数

    • setup(props, context) / setup(props, {attrs, slots, emit})
    • props: 包含 props 配置声明且传入了的所有属性的对象
    • attrs: 包含没有在 props 配置中声明的属性的对象, 相当于 this.$attrs
    • slots: 包含所有传入的插槽内容的对象, 相当于 this.$slots
    • emit: 用来分发自定义事件的函数, 相当于 this.$emit

定义响应式数据

在 vue2 中定义响应式数据,我们都是在 state 中声明定义的,但在 vue3 中我们基本是不会再去使用 state 了。因为我们有了更好的定义方法:ref 和 reactive。

ref

  • 主要用来定义一个基本类型的响应式数据,例如 Number,String,Boolean。

  • 语法:const xxx = ref(基本类型数据);

    const name = ref('小明');
    
  • ref 也可以用来定义引用类型的响应式数据,内部会自动将引用类型数据转换为 reactive 的代理对象再存储在引用对象的 value 中,既然有 reactive,我们没必要使用 ref 来定义引用类型响应式数据。

  • ref 定义的响应式数据是一个引用对象(reference),数据值存储在引用对象的 value 中,故使用 ref 定义的响应式数据时有两点需要注意:

    1. js 中操作 ref 定义的响应式数据时需要用到 xxx.vaule
    2. template 中会自动处理 ref 定义的引用对象,所以在 tempalte 中可忽略 .value,直接使用 xxx来显示响应式数据值。
    <template>
      <div>
        <!-- tempalte 中可忽略 .value 而直接使用变量名 -->
        我是{
           {
           name}}
      </div>
    </template>
    
    <script lang="ts">
    import {
            defineComponent, ref } from 'vue';
    
    export default defineComponent({
           
      name: 'App',
      setup() {
           
        // 使用 ref 定义一个基本类型的响应式数据
        const name = ref('小明')
        // js 中操作 ref 定义的响应式数据需要用到 xxx.value
        name.value = '小红'
        return {
           
          name
        }
      }
    })
    </script>
    
  • ref 也可以用来获取元素

    <template>
        <!-- ref 设置为 myInputRef -->
        <input type="text" ref="myInputRef" />
    </template>
    <script lang="ts">
        import {
           
            defineComponent,
            onMounted,
            ref
        } from 'vue'
    
        export default defineComponent({
           
            name: 'App',
            setup() {
           
                // 直接通过 ref 获取 DOM 元素
                const myInputRef = ref<HTMLElement | null>(null)
    
                onMounted(() => {
           
                    myInputRef.value && myInputRef.value.focus()
                })
                return {
           
                    myInputRef
                }
            },
        })
    </script>
    

reactive

  • 主要用来定义一个引用类型的响应式数据,例如 Object。

  • 语法:const xxx = reactive(引用类型数据);

    // 使用 reactive 定义一个引用类型的响应式数据
        const user = reactive({
           
          name: '小红',
          age: 18
        });
    
  • 深层次的响应式,嵌套的数据也是响应式

  • 基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据

计算属性与监视

  • computed 函数:

    • 与 vue2 中的 computed 配置功能一致
    • 只有 getter
    • 有 getter 和 setter
    // 只有 getter 的计算属性
    const fullName = computed(() => {
           
      return user.firstName + '-' + user.lastName
    })
    
    // 有 getter 与 setter 的计算属性
    const fullName1 = computed({
           
      get() {
           
        return user.firstName + '-' + user.lastName
      },
      set(value: string) {
           
        const names = value.split('-')
        user.firstName = names[0]
        user.lastName = names[1]
      }
    })
    
  • watch 函数:

    • 与 vue2 中的 watch 配置功能一致
    • 监视指定的一个或多个响应式数据, 一旦数据变化, 就自动执行监视回调
    • 默认初始时不执行回调, 但可以通过配置 immediate 为 true, 来指定初始时立即执行第一次
    • 通过配置 deep 为 true, 来开启数据深度监视
    watch(
      user, // 监视的数据
      () => {
            // 监视的数据发生变化时触发的回调
        name.value = user.firstName + '-' + user.lastName
      },
      {
           
        immediate: true, // 设置是否初始化立即执行一次, 默认是 false
        deep: true // 设置是否开启深度监视, 默认是 false
      }
    )
    
    /*
    watch一个数据
      默认在数据发生改变时执行回调
    */
    watch(fullName3, value => {
           
      console.log('watch')
    })
    
     /*
     watch多个数据:
       使用数组来指定
       如果是 ref 对象, 直接指定
       如果是 reactive 对象中的属性,  必须通过函数来指定
    */
        watch([() => user.firstName, fullName], values => {
           
          console.log('监视多个数据', values)
        })
    
  • watchEffect 函数

    • 不用直接指定要监视的数据, 回调函数中使用的哪些响应式数据就监视哪些响应式数据
    • 默认初始时就会执行第一次, 从而可以收集需要监视的数据
    • 监视数据发生变化时回调
    watchEffect(() => {
           
      // 回调中使用了 user 中的 firstName, lastName 属性,故组件会直接监视这两个数据的变化
      fullName.value = user.firstName + '-' + user.lastName
    })
    

生命周期

让我们再来比较 vue3 与 vue2 的生命周期,看看有什么变化吧。

vue2 的生命周期

学习Vue3_第1张图片

vue3 的生命周期

学习Vue3_第2张图片

vue3较vue2生命周期的变化

vue3 中将生命周期函数改为对应的组合式 API。

  • beforeCreate -> setup()
  • create -> setup()
  • beforeMount -> onBeforeMount
  • mounted -> onMounted
  • beforeUpdate -> onBeforeUpdate
  • updated -> onUpdated
  • beforeDestroy -> onBeforeUnmount
  • destroyed -> onUnmounted
  • errorCaptured -> onErrorCaptured

vue3 也支持大部分 vue2 生命周期函数写法,需要注意的是:

  1. beforeDestroydestroyed两个生命周期需要改为 beforeUnmount
    unmounted

  2. vue3 中的组合式 API 较 vue2 传统生命周期函数先执行。

    // vue3 中需要引入组合式 API 才可使用
    import {
            defineComponent, onBeforeMount, onMounted } from 'vue';
    export default defineComponent({
           
      name: 'App',
      beforeCreate(){
           
        console.log('vue2: beforeCreate')
      },
      // vue3 中也支持大部分 vue2 生命周期函数的写法,只是执行慢于组合式 API
      create(){
           
        console.log('vue2: create')
      },
      beforeMount(){
           
        console.log('vue2: beforeMount')
      },
      mounted(){
           
        console.log('vue2: mounted')
      },
      // vue3 生命周期组合式 API 需要在 setup 中使用
      setup(){
           
        console.log('vue3: beforeCreate / create ')
        onBeforeMount(() => {
           
          console.log('vue3: onBeforeMount')
        })
        onMounted(() => {
           
          console.log('vue3: onMounted')
        })
      }
    })
    

执行结果:
学习Vue3_第3张图片

hooks

作用:封装可复用的功能函数,自定义 hook 可使复用功能代码更简洁清晰,易读性更强。

toRef 和 toRefs

toRef

  • toRef 用于为源响应式对象上的属性新建一个 ref,从而保持对其源对象属性的响应式连接。

  • toRef 后的 ref 数据不是原始数据的拷贝,而是引用,改变结果数据的值也会同时改变原始数据

  • 区别 ref : 拷贝了一份新的数据值单独操作, 更新时相互不影响

  • 应用: 当要将某个 prop 的 ref 传递给复合函数时,toRef 很有用

  • 接收两个参数:源响应式对象和属性名,返回一个 ref 数据

  • 语法:const xxx = toRef(obj, 属性名)

    const car = {
           
       price: '100w',
       count: 20
    }
    const price = toRef(car, "price")
    const count = toRef(car, "count")
    // 解构出来的属性均为 ref 属性,在 js 中操作需要添加 .value
    console.log(price.value)
    

toRefs

  • toRefs 用于将响应式对象转换为普通对象,该普通对象的每个属性都是指向原始对象相应属性的 ref。

  • 利用 toRefs 可以将一个响应式 reactive 对象的所有原始属性转换为响应式的 ref 属性。

  • 语法:const {属性名…} = toRefs(obj)

    const user = reactive({
           
        name: '小红',
        age: 18
    })
    // 结合 es6 的解构赋值,利用 toRefs 可以将一个响应式 reactive 对象的所有原始属性转换为响应式的 ref 属性。
    const {
           name, age} = toRefs(user)
    // 解构出来的属性均为 ref 属性,在 js 中操作需要添加 .value
    console.log(name.value)
    

新增组件

Fragment(片断)

  • vue2 中:组件必须有一个根标签

  • vue3 中:组件可以没有根标签,内部会将多个标签包含在一个 Fragment 虚拟元素中

  • 作用: 减少标签层级,减少内存占用

    <template>
      <!-- vue2 中需要根标签 -->
      <div>
      	<h2>vue2</h2>
      	<h2>vue2</h2>
      </div>
    </template>
    
    <template>
      <!-- vue3 中不需要根标签 -->
      <h2>vue3</h2>
      <h2>vue3</h2>
    </template>
    

Teleport(瞬移)

  • Teleport 提供了一种干净的方法, 让组件的 html 在父组件界面外的特定标签(很可能是 body)下插入显示。

    <template>
        <div class="container">
            外层 container
             <!-- 使用 Teleport,并设置 to 为 body 即可实现将包裹住的代码瞬移到 body 下  -->
            <Teleport to="body">
                <div class="inner">
                    内层 inner
                </div>
            </Teleport>
        </div>
    </template>
    

由下图不难看出 Teleport 包住的代码已经成为 body 的直接子标签了。
学习Vue3_第4张图片

Suspense(不确定的)

  • 主要用于应用程序在等待异步组件时渲染一些后备内容,例如 loading…从而提高用户体验。

    <template>
        <Suspense>
        	<!-- 异步组件加载完成显示异步组件内容 -->
            <template #default>
                <son></son>
            </template>
            <!-- 异步组件还未加载完时显示执行下方内容 -->
            <template v-slot:fallback>
                <h1>Loading...</h1>
            </template>
        </Suspense>
    </template>
    

你可能感兴趣的:(vue3,vue)