vue3新特性介绍和基本使用

1,532 阅读1分钟

新特性

vue-composition-api-rfc.netlify.app/zh/api.html…

  • ref、reactive、computed、watch
  • 新的生命周期
  • 自定义钩子函数
  • Teleport(组件位置替换)
  • Suspense(异步加载组件实现)
  • 全局Api、配置项的优化
  • 更好的支持typescript

全局api和初始化应用的变化

全局config

vue3将全局配置挂在了app实例上而不是构造函数上,好处是是的应用之间的配置互不影响

//vue2的全局config配置是直接挂在Vue构造函数上的
//例如
Vue.config.errorHandler = (err)=>console.log(err)

//vue3的全局api是在当前应用实例上修改的,不会影响其他应用
//例如
const app1 = createApp(AppComponent1)
const app2 = createApp(AppComponent2)

app1.config.errorHandler.(err)=>console.log(err,'app1')
app2.config.errorHandler.(err)=>console.log(err,'app2')

全局方法

vue3为了减小打包体积,将很多方法都采用了具名导出的方式(如 createAppnextTick等),这使得初始化实例的方式也有所区别

例如:

const app1 = createApp(AppComponent1)
const app2 = createApp(AppComponent2)

因为vue3不再有Vue构造函数,所以一些全局的自定义属性或者方法也没法通过Vue.prototype.xx挂在到vm实例上,这时候需要借助app.config.globalProperties来实现这一功能

例如:

//如果项目采用了typescript,那么就需要扩展一下`@vue/runtime-core`模块,否则在使用的时候会报找不到$http属性
//在main.ts加上如下代码
declare module '@vue/runtime-core' {
  interface ComponentCustomProperties {
    $http: any;
  }
}

app.config.globalProperties.$http = () => {
 //do something
}

vue3的中间件也是通过每个应用实例下的use方法去注册,且支持链式调用

app1.use(middleware1).use(middleware2).mount('#app')

composition Api

ref

需要注意的是setup返回的变量都是Ref类型,修改ref的值需要修改ref.value,在其他的方法中也能通过this.xx直接修改

使例子

<template>
  <div class="test-font">
    {{ msg }}
  </div>
  <button class="test-button" @click="changeMsg">修改msg</button>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
  setup() {
    const msg = ref("hello ref");
    setTimeout(() => {
      msg.value = "1000ms after";
    }, 1000);
    return {
      msg,
    };
  },
  methods: {
    changeMsg() {
      this.msg = "this is change msg";
    },
  },
});
</script>


computed

computed接收一个函数,改函数的返回值作为计算属性的值

<template>
  <div class="test-font">
    <div>num:{{ num }}</div>
    <div>double-num:{{ doubleNum }}</div>
    <button class="test-button" @click="addOne">+1</button>
  </div>
</template>
<script lang="ts">
import { defineComponent, ref, computed } from "vue";
export default defineComponent({
  setup() {
    const num = ref(0);
    const doubleNum = computed(() => {
      return num.value * 2;
    });
    const addOne = () => {
      num.value++;
    };
    return {
      num,
      doubleNum,
      addOne,
    };
  },
});
</script>

reactive

在setup中,reactive可以为我们集中定义属性

<template>
  <div class="test-font">
    <div>name:{{ name }}</div>
    <div>age:{{ age }}岁</div>
    <div>height:{{ height }}米</div>
    <div>weight:{{ weight }}公斤</div>
    <div>weight-2:{{ weight2 }}斤</div>
    <div>attr:{{ attr }}</div>
    <div>淦饭了没:{{ eat }}</div>
    <button class="test-button" @click="changeMsg">淦饭</button>
  </div>
</template>
<script lang="ts">
import { defineComponent, reactive, toRefs, computed } from "vue";
interface DataProps {
  name: string;
  age: number;
  height: number;
  weight: number;
  weight2: number;
  attr: string;
  eat: string;
  changeMsg: () => void;
}
export default defineComponent({
  setup() {
    const data: DataProps = reactive({
      name: "熊志强",
      age: 18,
      height: 1.85,
      weight: 135,
      weight2: computed(() => {
        return data.weight / 2;
      }),
      attr: "帅一批",
      eat: "没有",

      changeMsg: () => {
        data.eat = "淦了";
      },
    });
    return {
      ...toRefs(data),
    };
  },
});
</script>

watch监听

vue3提供了再setup中使用的数据监听函数watch,因为setup只是在初始化的时候调用一次,无法根据数据变化实时调用,所以提供了watch方法解决这个问题

下面是wacth方法的简单使用实例:


setup(){
  //监听单个的ref
  const  a = ref(0)
  watch(a,(newval,oldval)=>{
   console.log(newval,oldval)
  })

  //监听多个ref
  const  b = ref(0)
  watch([a,b],(newval,oldval)=>{
   console.log(newval,oldval)
  })

  //监听reactive
  const reactiveData = reactive({
   a:1,
   b:2,
   c:3
  })
  watch(data,(newVal,oldVal)=>{
   console.log(newVal,oldVal)
  })
  
  //监听reactive下的某一个属性
  watch([()=>data.a,()=>data.b],(newVal,oldVal)=>{
   console.log(newVal,oldVal)
  })
}

provide、inject

根组件注入

//parent Component
import {provide,ref} from 'vue'
setup(){
 const foo = ref('')
 provide('foo',foo)
}

//descendant component
import {inject} from 'vue'
setup(){
 const foo = inject('foo','默认值')
 return{
  foo
 }
}

ps:如果setup中有异步操作,inject必须在异步操作之前

路由相关

import {useRoute,useRouter} from ''vue-router
setup(){
 const route = useRoute()  //等同于vue2的this.$route
 const router = useRouter() //等同于vue2的this.$router
}

生命周期

有两个生命周期名称修改以及两个新增

// 修改的
beforeDestroy -> beforeUnmount
destroyed -> unmounted

//新增的
renderTracked
renderTriggered

vue3提供了在setup中使用的生命周期函数

  /*
    生命周期函数对应表
    beforeCreate -> 与setup并行
    created -> 与setup并行
    beforeMount -> onBeforeMount
    mounted -> onMounted
    beforeUpdate -> onBeforeUpdate
    updated -> onUpdated
    beforeUnmount -> onBeforeUnmount
    unmounted -> onUnmounted
    errorCaptured -> onErrorCaptured
    renderTracked -> onRenderTracked
    renderTriggered -> onRenderTriggered
  */
import { onMounted } from 'vue'
defineComponent({
  setup(){
	onMounted(() => { console.log('mounted') })
  }
})

变更

  • .sync修饰符 => v-model:propName

目前遇到的问题

  • keep-alive不可用