vue3新增特性学习

目录

一、ref和reactive

二、watch

三、生命周期

四、composition api模块化、逻辑重用 (自定义函数Hook)

4.1 捕捉鼠标位置demo

4.2 调用接口demo

五、vue3对ts的支持

六、jsx语法

七、teleport(瞬移组件的位置)+父子组件传参

八、异步组件

九、全局api更改


在Vue2.x中,我们实现一个功能,需要在data中新增数据,在methods/computed/watch中新增业务逻辑,数据和业务逻辑是分离的,不利于管理,为了解决这个弊端,Vue3.0推出了Composition API(组合API),也叫做注入API,实际上setup中定义的数据和业务逻辑,会注入到data和methods中

setup()是组合API的入口函数,可以直接在里面定义变量和方法(数据和业务逻辑),通过对象的形式返回暴露出去

composition api是vue3一系列新的api合集,主要有:

1、ref和reactive

2、computed和watch

3、新的生命周期函数

4、自定义函数Hook

关于vue3更多信息可以参考 https://v3.cn.vuejs.org/api/application-api.html

一、ref和reactive

setup()可以包含许多特性包括data、生命周期、watch、computed等等,注意该方法中无法访问this。

setup(){ 
    const count = ref(0) //data类型
    const increase = ()=>{
      count.value++ //不能直接更改count
    }
    const double = computed(()=>{ computed计算属性
      return count.value * 2
    })
    return { //需要将定义的数据返回
      count,
      increase,
      double
    }
}

多个数据可以使用reactive,但reactive数据不是响应式数据,需要用toRefs函数将其转化为ref格式/或者使用data.count等形式

setup(){
   
    const data: DataProps = reactive({
      count:0 ,
      increase:()=>{
        data.count++
      },
      double: computed(()=>{ //reactive更改变量值无需改变
        return data.count*2
      })
    })
    const refsData = toRefs(data)
    return {
      ...refsData
    }
  }

 报错,类型推断错误,需要给data设置定义接口

import { computed,reactive, toRefs } from 'vue'
interface DataProps {
  count: number;
  increase: () => void;
  double: number;
}

有利于逻辑整合

优点:vue2的data无法监听属性的增加移除,vue3内通过proxy监听到这些

二、watch

    const greetings = ref('')
    watch(greetings, ()=>{//单个
    //watch([data1,data2], ()=>{ //监听多个
    //watch(()=>data.val1, ()=>{ //监听单个信息需要使用函数     
         document.title = greetings.value
    })
    return {
      updateGreeting
    }

三、生命周期

1、beforeUnmoint、unmounted替代beforeDestory、destoryed

在setup函数中如何处理生命周期的函数调用

选项 APIsetup内部的钩子
beforeCreate不需要
created不需要
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeUnmountonBeforeUnmount
unmountedonUnmounted
errorCapturedonErrorCaptured
renderTrackedonRenderTracked
renderTriggeredonRenderTriggered

beforeCreate:表示组件刚刚被创建出来,组件的data和methods还没有初始化好setup
Created: 表示组件刚刚被创建出来,并且组件的data和methods已经初始化好
setup函数的注意点:
  1、由于在执行 setup函数的时候,还没有执行 Created 生命周期方法,所以在 setup 函数中,无法使用 data 和 methods 的变量和方法

  2、由于我们不能在 setup函数中使用 data 和 methods,所以 Vue 为了避免我们错误的使用,直接将 setup函数中的this修改成了 undefined

  3、setup函数只能是同步的不能是异步的

新增调试用的debug函数

onRenderTracked

  • 每次渲染后重新收集响应式依赖
  • 在onMounted前触发,页面更新后也会触发

跟踪虚拟 DOM 重新渲染时调用。钩子接收 debugger event 作为参数。此事件告诉你哪个操作跟踪了组件以及该操作的目标对象和键。

它会跟踪页面上所有响应式变量和方法的状态,也就是我们用return返回去的值,它都会跟踪。只要页面有update的情况,它就会跟踪,然后生成一个event对象,我们通过event对象来查找程序的问题所在。

onRenderTriggered

  • 每次触发页面重新渲染时自动执行

  • 在onBeforeUpdate之前触发

当虚拟 DOM 重新渲染被触发时调用。和 renderTracked 类似,接收 debugger event 作为参数。此事件告诉你是什么操作触发了重新渲染,以及该操作的目标对象和键。

它不会跟踪每一个值,而是给你变化值的信息,并且新值和旧值都会给你明确的展示出来。onRenderTracked是如aoe一般对每个值都进行跟踪,

emit、solt、attr 在setup中用 context.emit|solt|attr  方法来替代

setup(props, context){
    return {
        // 要绑定的数据和方法
    }
}

四、composition api模块化、逻辑重用 (自定义函数Hook)

  • Vue3 的 hook函数 相当于 vue2 的 mixin, 不同在与 hooks 是函数

4.1 捕捉鼠标位置demo

在新建文件夹hooks下新建userMousePosition.ts

import {ref, onMounted, onUnmounted } from 'vue'
function userMousePosition(){
    const x = ref(0)
    const y = ref(0)
    const updateMouse  = (e: MouseEvent) =>{
        x.value = e.pageX
        y.value = e.pageY
    }
    onMounted(()=>{
        document.addEventListener('click',updateMouse)
    })
    onUnmounted(()=>{
        document.removeEventListener('click',updateMouse)
    })
    return {
        x,
        y
    }
}
export default userMousePosition

页面引用,并导出x、y的值

import  userMousePosition  from '../hooks/userMousePosition'
export default {
    name: 'Home',
    setup(){
        const {x , y} = userMousePosition()
        return {
            x,
            y
        }
    }
};

4.2 调用接口demo

创建useURLLoader.ts文件

import { reactive, toRefs } from 'vue'
import axios from 'axios'

interface dataProps {
    result: any;
    loading: boolean;
    loaded: boolean;
    error: any;
}
function useURLLoader (url: string) {
  const data: dataProps = reactive({
    result: null,
    loading: false,
    loaded: true,
    error: null
  })
  axios.get(url).then((rawData) => {
    data.loading = false
    data.loaded = true
    data.result = rawData.data
  }).catch(e => {
    data.error = e
    data.loading = true
    data.loaded = false
  })
  const refsData = toRefs(data)
  return {
    ...refsData
  }
}
export default useURLLoader

页面引用 

<template>
  <div class="home">
      <img v-if="loaded" :src="result.message" alt="">
  </div>
</template>

<script lang="ts">
import useURLLoader from '../utils/useURLLoader'
import { computed, defineComponent, ref, reactive, toRefs, onRenderTracked, watch } from 'vue'
// import HelloWorld from '@/components/HelloWorld.vue' // @ is an alias to /src
interface DataProps {
  count: number;
  increase: ()=> void;
  double: number;
}
export default defineComponent({
  name: 'Home',
  components: {
    // HelloWorld
  },
  setup () {

    const { result, loading, loaded } = useURLLoader('https://dog.ceo/api/breeds/image/random')
    return {
      result,
      loaded
    }
  }
})
</script>

五、vue3对ts的支持

 1、defineComponent定义组件

defineComponent函数,只是对setup函数进行封装,返回options的对象;

export function defineComponent(options: unknown) {
  return isFunction(options) ? { setup: options } : options
}

defineComponent最重要的是:在TypeScript下,给予了组件 正确的参数类型推断 。

六、jsx语法

比如defineComponent实现

import { defineComponent } from 'vue'
const component = defineComponent({
    name:'mouse',
    setup(props, content) {
        
    }
})

七、teleport(瞬移组件的位置)+父子组件传参

指定被包裹组件挂载在何处

      <teleport to="#id"></teleport>

父子组件传参

<template> 
    <teleport to="#to">
        <div id="center" v-if="isOpen">
            <h2><slot>this is a model </slot></h2>
            <button @click="buttonClick">关闭(向父组件传递数据)</button>
        </div>
    </teleport>
    
</template>

<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
    name:'Modal',
    props:{
        isOpen: Boolean
    },
    
    emits: {
        'close-modal':(payload: any)=>{
            return payload.type === 'close'
        }
    },
    setup(props, context) {
        const buttonClick = ()=>{
            return context.emit('close-modal', {
                type: 'hello'
            })
        }
        return {
            buttonClick
        }
    },
})
</script>

<style>
</style>
<template>
    <div id="to" class="to">
        <button @click="openModal">打开吧点数去</button>
        <Modal :isOpen="modalIsOPen" @closeModal="closeModal">solt展示</Modal>
    </div>
</template>

<script lang="ts">
import { ref } from 'vue';
import Modal from '../components/Modal.vue';
export default {
    name:'DefineComponent',
    setup() {
        const modalIsOPen = ref(false)
        const openModal = ()=>{
            modalIsOPen.value = true
            console.log('触发openModal',modalIsOPen.value )
        }
        const closeModal = ()=>{
            modalIsOPen.value = false
        }
        return{
            openModal,
            modalIsOPen,
            closeModal
        }
    },
    components:{
      Modal: Modal,
    }
}
</script>

<style>

</style>

八、异步组件

如果要是用suspense,需要返回一个promise 。suspense希望能够处理异步问题,可以根据不同的情况渲染组件。

<template>
  <h1>asyncshow组件</h1>
</template>

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

<style>

</style>

<template>
  <div>
      <Suspense>
        <template #default>
            <AsyncSHow   ></AsyncSHow>
        </template>
        <template #fallback>
            <Modal :isOpen="true"></Modal>
        </template>
      </Suspense>
  </div>
</template>

<script>
import AsyncSHow from '../components/asyncShow'
import Modal from '../components/Modal.vue';

export default {
    components: {
        AsyncSHow,
        Modal
    }
}
</script>

<style>

</style>

九、全局api更改

vue2的全局配置在一定程度上修改了vue的属性,容易污染环境。

vue.component =>app.component

vue.directive     =>app.directive

vue.nextTick     =>nextTick(()=>{})//需要从vue中引入nextTick

vue.mixin          =>app.mixin

vue.use             =>app.use

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值