vue3之新特性

483 阅读3分钟

一、Ref 语法

ref 是一个函数,接受一个参数,返回的是一个响应式的对象,对象的 value 属性是真实存放值的地方(ref一般传入原始类型)

import { ref } from 'vue';
export default {
    const err = ref(null)
    return {
        err
    }
}

二、Reactive 语法

reactive 与 ref 相似,但其接受的参数不是原始类型,而是一个对象。reactive 定义对象属性单独拿出来使用,会丧失响应。

import { reactive } from "vue";
export default  {
    const data = reactive({
        x: 0,
        y: 0
    })
    return {
        data
    }
}

toRef 接受 reactive 对象参数,返回一个 ref 对象参数(ref对象参数可展开)。

import { reactive, toRefs } from "vue";
export default {
    const data = reactive({
        x: 0,
        y: 0
    })
    const refsData = toRefs(data)
    return {
        ...refsData
    }
}

三、生命周期

  • beforeMount -> onBeforeMount
  • mounted -> onMounted
  • beforeUpdate -> onBeforeUpdate
  • updated -> onUpdated
  • beforeUnmount -> onBeforeUnmount
  • unmounted -> onUnmounted
  • errorCaptured -> onErrorCaptured
  • renderTracked -> onRenderTracked
  • renderTriggered -> onRenderTriggered vue3 中 beforeCreate 和 created 生命周期消失。但因为其可以兼容 vue2 ,所以在 vue3 中仍可使用 vue2 中的生命周期。此外,vue3 hook 使用之前需要先引入。
import { onMounted } from 'vue';

四、setUp

setUp 运行beforeMount之前,并且不能访问 this 对象。其有两个参数props、context,props 是一个响应式对象包含了由父组件传递过来的参数,提供了vue2中this方法上的 attrs、slots、emit属性(返回的时最新的值)。

props: {
  isOpen: Boolean
},
emits: {
  'close-model': (payload: any) => {
    return payload.type === 'close'
  }
},
setup(props,context) {
  const buttonClick = () => {
    context.emit('close-model', {
      type: 'hello'
    })
  }
  return {
    buttonClick
  }
}

五、computed

接受一个函数回调参数,其使用如下:

import { computed } from 'vue';
setup (props, context) {
  const double = computed(()=> {
    return count.value *2;
  })
  return {
     double 
  }
}
// data 不指定类型,会报红,但是程序可以正常运行
// 使用 computed 过程,data.count造成了类型的循环,导致data 报红,解决方法给data显示的指定一个类型
const data: DataProps = reactive({
  count: 0,
  increase: () => {data.count ++},
  double: computed(()=> data.count *2 ),
});

六、watch

watch 第一个参数是一个响应式的对象或者一个函数(如果监听的是多个值,可以接受一个数组),第二个回调函数(回调函数中,两个参数和数组一一对应)。

import { defineComponent,ref, computed, reactive, toRefs, watch, onErrorCaptured } from 'vue';
export default defineComponent({
  setup (props, context) {
      const data = reactive({
          count: 0,
          increase: () => {data.count ++},
          double: computed(()=> data.count *2 )
      });
      const greetings = ref('');
      // 监听一个数据
      watch(greetings, (old, newVal) => {
          console.log(old)
          console.log(newVal)
      })
      // 监听多个数据
      watch([greetings, data], (old, newVal) => {
          console.log(old)
          console.log(newVal)
      })
      // 监听 data 下的 count 属性
      watch([greetings, ()=> data.count], (old, newVal) => {
          console.log(old)
          console.log(newVal)
      })
  }
})

七、defineComponent

defineComponent 并没有实现任何逻辑,为了让传入的对象获取对应的类型。 [官方文档](Global API | Vue.js (vuejs.org))

八、Teleport 传送门

Teleport 建立了一个传送门。其使用方法如下:

  • Model组件中
<template>
<Teleport to="#model">
  <div id="center" v-if="isOpen">
    <h2><slot>Model</slot></h2>
    <button @click="buttonClick">Close</button>
  </div>
</Teleport>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
export default defineComponent({
  props: {
    isOpen: Boolean
  },
  emits: {
    'close-model': (payload: any) => {
      return payload.type === 'close'
    }
  },
  setup(props,context) {
    const buttonClick = () => {
      context.emit('close-model', {
        type: 'hello'
      })
    }
    return {
      buttonClick
    }
  }
})
</script>
  • 页面中
<template>
  <div>
    <button @click="openModel">model</button>
    <model :is-open="modelIsOpen" @close-model="closeModel">this is me</model>
  </div>
</template>

<script lang="ts">
import { defineComponent,ref } from 'vue';
import Model from './components/Model.vue';
export default defineComponent({
  name: 'App',
  components: {
    Model
  },
  setup () {
    const modelIsOpen = ref(false)
    const openModel = () => {
      modelIsOpen.value = true
    }
    const closeModel = () => {
      modelIsOpen.value = false
    }
    return {
      modelIsOpen,
      openModel,
      closeModel
    }
  }
});
</script>
  • index.html
<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <div id="model"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

九、Suspense

Suspense 一个内置组件,解决异步请求的困境。如果要使用,需要在其包裹组件内的 setup 中返回一个 Promise。有两个具名插槽:default、fallback。

  • 父组件
<Suspense>
  <template #default>
     <async-show/>
  </template>
  <template #fallback>
    <h1>加载中</h1>
  </template>
</Suspense>
  • 子组件
<template>
  <div>{{result}}</div>
</template>

<script>
import { defineComponent } from 'vue'
export default defineComponent({
  name: "AsyncShow",
  setup() {
    return new Promise(resolve => {
      setTimeout(()=> {
        return resolve({
          result: 42
        })
      }, 3000)
    })
  }
})
</script>

注意:Suspense 中插槽只有一个根节点。如果一个插槽下如果个组件,需要用标签包裹。

<Suspense>
  <template #default>
    <div>
      <async-show/>
      <dog-show/>
    </div>
  </template>
  <template #fallback>
    <h1>加载中</h1>
  </template>
</Suspense>