vue.js基础学习(组合式 API:setup() 基本使用)

基础入门:vue.js 组合式 API:setup() 基本使用

1、在setup中使用watch

  • watch():侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。
  • 详细信息:watch() 默认是懒侦听的,即仅在侦听源发生变化时才执行回调函数。第一个参数是侦听器的。watch(侦听的响应式引用,回调函数),这个来源可以是以下几种:
    • 一个函数,返回一个值
    • 一个 ref
    • 一个响应式对象
    • ...或是由以上类型的值组成的数组
    • 第二个参数是在发生变化时要调用的回调函数。这个回调函数接受三个参数:新值、旧值,以及一个用于注册副作用清理的回调函数。该回调函数会在副作用下一次重新执行前调用,可以用来清除无效的副作用,例如等待中的异步请求。

      当侦听多个来源时,回调函数接受两个数组,分别对应来源数组中的新值和旧值。

      第三个可选的参数是一个对象,支持以下这些选项:

    • immediate:在侦听器创建时立即触发回调。第一次调用时旧值是 undefined
    • deep:如果源是对象,强制深度遍历,以便在深层级变更时触发回调。参考深层侦听器
    • flush:调整回调函数的刷新时机。参考回调的刷新时机watchEffect()
    • onTrack / onTrigger:调试侦听器的依赖。参考调试侦听器
  • watchEffect():立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行。 
    • 第一个参数就是要运行的副作用函数。这个副作用函数的参数也是一个函数,用来注册清理回调。清理回调会在该副作用下一次执行前被调用,可以用来清理无效的副作用,例如等待中的异步请求 (参见下面的示例)。

    • 第二个参数是一个可选的选项,可以用来调整副作用的刷新时机或调试副作用的依赖。

      默认情况下,侦听器将在组件渲染之前执行。设置 flush: 'post' 将会使侦听器延迟到组件渲染之后再执行。详见回调的触发时机。在某些特殊情况下 (例如要使缓存失效),可能有必要在响应式依赖发生改变时立即触发侦听器。这可以通过设置 flush: 'sync' 来实现。然而,该设置应谨慎使用,因为如果有多个属性同时更新,这将导致一些性能和数据一致性的问题。

    • 返回值是一个用来停止该副作用的函数。

  • watch()和watchEffect()的区别:
    • watchEffect()不需要指定监听的属性,自动收集依赖,只要在回调中引用响应式的属性,只要这些属性发生改变回调就会执行;watch()只能监听指定属性,做出回调函数的执行,从vue3开始可以监听多个。

    • watch()可以获得新值和旧值,watchEffect()不可以拿到。

    • watchEffect()在组件初始化的时候就会执行一次,用来收集依赖,watch()不需要,一开始就指定。 

 源代码:

<script>
  import Hello from './components/Hello.vue';
  import { ref,reactive, toRefs, watch, watchEffect,} from 'vue';//ref定义响应式变量,reactive 可以定义引用数据类型
  export default{
    data(){
      return{
        message:'hello word!'
      }
    },
    setup(){
      //counter逻辑代码
      const counter=ref(0)
      function changCoun(){
        counter.value++
      }
      //watch(侦听的响应式引用,回调函数)
      watch(counter,(newVal,oldVal)=>{
        console.log("newVal----",newVal);
        console.log("oldVal----",oldVal);
      })

      //use逻辑代码
      const use=reactive({
        name:'xueysr',
        age:18
      })
      function changeName(){
        use.name='x-ysr'
      }
      // watch(use,(newVal,oldVal)=>{
      //   console.log("newVal---",newVal);
      //   console.log("oldVal---",oldVal)
      // })
      //watchEffect(回调函数),不需要指定监听的属性,自动收集依赖
      watchEffect(()=>{
        console.log(use.name)
      })
      /*
      watch()和watchEffect()的区别
      1、watchEffect()不需要指定监听的属性,自动收集依赖,只要在回调中引用响应式的属性,只要这些属性发生改变回调就会执行
      watch()只能监听指定属性,做出回调函数的执行,从vue3开始可以监听多个。
      2、watch()可以获得新值和旧值,watchEffect()不可以拿到。
      3、watchEffect()在组件初始化的时候就会执行一次,用来收集依赖,watch()不需要,一开始就指定。
      */

      return{
        counter,
        use,
        changCoun,
        changeName
      }
    },
    //选项式API
    watch:{
      message:function(newVal,oldVal){

      }
    },
    components:{
      Hello
    }
  }

</script>

<template>
  <h2>{{counter}}</h2>
  <h2>{{use.name}}</h2>
  <button @click="changCoun">改变counter</button>
  <button @click="changeName">改变名字</button>
  <Hello></Hello>
</template>

<style>

</style>

2、生命周期钩子函数在setup中使用

  • onMounted():注册一个回调函数,在组件挂载完成后执行。

  • onUpdated():注册一个回调函数,在组件因为响应式状态变更而更新其 DOM 树之后调用。

  • onUnmounted():注册一个回调函数,在组件实例被卸载之后调用。

  • onBeforeMount():注册一个钩子,在组件被挂载之前被调用。

  • onBeforeUpdate():注册一个钩子,在组件即将因为响应式状态变更而更新其 DOM 树之前调用。

  • onBeforeUnmount():注册一个钩子,在组件实例被卸载之前调用。

  • onErrorCaptured():注册一个钩子,在捕获了后代组件传递的错误时调用。

  • onRenderTracked()注册一个调试钩子,当组件渲染过程中追踪到响应式依赖时调用。这个钩子仅在开发模式下可用,且在服务器端渲染期间不会被调用。

  • onRenderTriggered():注册一个调试钩子,当响应式依赖的变更触发了组件渲染时调用。这个钩子仅在开发模式下可用,且在服务器端渲染期间不会被调用。

  • onActivated():注册一个回调函数,若组件实例是 <KeepAlive> 缓存树的一部分,当组件被插入到 DOM 中时调用。这个钩子在服务器端渲染期间不会被调用。

  • onDeactivated():注册一个回调函数,若组件实例是 <KeepAlive> 缓存树的一部分,当组件从 DOM 中被移除时调用。这个钩子在服务器端渲染期间不会被调用。

  • onServerPrefetch():注册一个异步函数,在组件实例在服务器上被渲染之前调用。

源代码: 

<script>
  import Hello from './components/Hello.vue';
  import {onBeforeMount,onMounted,onBeforeUpdate,onUpdated} from 'vue';
  export default{
    data(){
      return{
        message:'hello word!'
      }
    },
    setup(){
      //生命周期钩子函数,函数中有一个参数和一个回调函数
      onBeforeMount(()=>{
        console.log('onBeforeMount')
      });
      onMounted(()=>{
        console.log('onMounted')
      });
      onBeforeUpdate(()=>{
        console.log('onBeforeUpdate')
      });
      onUpdated(()=>{
        console.log(' onUpdated')
      })
    }
  }

</script>

<template>
  
</template>

<style>

</style>

3、在setup中使用computed 

  • computed ():接受一个 getter 函数,返回一个只读的响应式 ref 对象。该 ref 通过 .value 暴露 getter 函数的返回值。它也可以接受一个带有 get 和 set 函数的对象来创建一个可写的 ref 对象。

源代码: 

<script>
  import Hello from './components/Hello.vue';
  import { ref,reactive, toRefs, watch, watchEffect, computed} from 'vue';//ref定义响应式变量,reactive 可以定义引用数据类型
  export default{
    data(){
      return{
        message:'hello word!'
      }
    },
    setup(){
      //msg逻辑代码
      const msg=ref('hello word!')
      const reverseMsg=computed(()=>{//返回一个带有value属性的对象
        return msg.value.split('').reverse().join('')
      })
      console.log(reverseMsg.value)
      return{
       msg,
       use
      }
    },
    //选项式API
    //  computed:{
    //   reverseMsg:function(){
    //     return this.message.split('').reverse().join('')
    //   }
    //  }
  }

</script>

<template>
  <h2>{{msg}}</h2>
</template>

<style>

</style>

4、在setup中使用props

  • setup 函数的第一个参数是组件的 props。和标准的组件一致,一个 setup 函数的 props 是响应式的,并且会在传入新的 props 时同步更新。

  • 如果你确实需要解构 props 对象,或者需要将某个 prop 传到一个外部函数中并保持响应性,那么你可以使用 toRefs()toRef() 这两个工具函数。

源代码: 

<!-- App.vue -->
<script>
  import Hello from './components/Hello.vue';
  export default{
    data() {
        return {
            message: "hello word!"
        };
    },
    components: { Hello }
}

</script>

<template>
  <Hello :message="message"></Hello>
</template>

<style>

</style>

<!-- Hello.vue -->
<script>
  export default{
    data(){
      return{
        counter:0
      }
    },
    props:{
      message:{
        type:String,
        default:'你好'
      }
    },
    setup(props){
      console.log(props.message)
    },
    // mounted(){
    //   console.log(this.message)
    // }
  }
</script>

<template>
  <h2>{{message}}</h2>
</template>

<style>

</style>

5、setup中的context参数 

  • 传入 setup 函数的第二个参数是一个 Setup 上下文对象。上下文对象暴露了其他一些在 setup 中可能会用到的值:
  • export default {
      setup(props, context) {
        // 透传 Attributes(非响应式的对象,等价于 $attrs)
        console.log(context.attrs)
    
        // 插槽(非响应式的对象,等价于 $slots)
        console.log(context.slots)
    
        // 触发事件(函数,等价于 $emit)
        console.log(context.emit)
    
        // 暴露公共属性(函数)
        console.log(context.expose)
      }
    }
  • attrsslots 都是有状态的对象,它们总是会随着组件自身的更新而更新。这意味着你应当避免解构它们,并始终通过 attrs.xslots.x 的形式使用其中的属性。此外还需注意,和 props 不同,attrsslots 的属性都不是响应式的。 

源代码: 

<!-- App.vue -->

<script>
  import Hello from './components/Hello.vue';
  export default{
    data() {
        return {
            message: "hello word!"
        };
    },
    methods:{
      injectContext(value){
        console.log(value)
      }
    },
    mounted(){
      console.log(this.$refs.content)
      this.$refs.content.sendeParent()
    },
    components: { Hello }
}

</script>

<template>
  <!-- <Hello id="content" @injectContext="injectContext"></Hello> -->
  <Hello id="content" ref="content" @injectContext="injectContext"></Hello>
  <Hello id="content"></Hello>
  <button @click="message='你好!'">更改</button>
</template>

<style>

</style>

<!-- Hello.vue -->
<script>
  import {onUpdated,toRefs,ref,h} from 'vue'
  export default{
    data(){
      return{
        counter:0
      }
    },
    props:{
      message:{
        type:String,
        default:'你好'
      }
    },
    setup(props,context){
      const counter=ref(20)
      function sendeParent(){
        context.emit('injectContext',counter)
      }
      console.log(context)
      context.expose({
        sendeParent,
        counter
      })
      return()=>h('div',counter.value)
      //props
      // console.log(props.message)
      // const {message}=toRefs(props)
      // console.log(message.value)
      // onUpdated(()=>{
      //   console.log(message.value)
      // })
    },
    // mounted(){
    //   console.log(this.message)
    // }
  }
</script>

<template>
  <h1>我是子组件内容</h1>
  <h2>{{message}}</h2>
  <button @click="sendeParent">发送数据</button>
</template>

<style>

</style>

6、setup中provide和inject 

  • provide():提供一个值,可以被后代组件注入。

  • function provide<T>(key: InjectionKey<T> | string, value: T): void
  • provide() 接受两个参数:第一个参数是要注入的 key,可以是一个字符串或者一个 symbol,第二个参数是要注入的值。

  • 当使用 TypeScript 时,key 可以是一个被类型断言为 InjectionKey 的 symbol。InjectionKey 是一个 Vue 提供的工具类型,继承自 Symbol,可以用来同步 provide()inject() 之间值的类型。

  • inject():注入一个由祖先组件或整个应用 (通过 app.provide()) 提供的值。

  • 第一个参数是注入的 key。Vue 会遍历父组件链,通过匹配 key 来确定所提供的值。如果父组件链上多个组件对同一个 key 提供了值,那么离得更近的组件将会“覆盖”链上更远的组件所提供的值。如果没有能通过 key 匹配到值,inject() 将返回 undefined,除非提供了一个默认值。

  • 第二个参数是可选的,即在没有匹配到 key 时使用的默认值。它也可以是一个工厂函数,用来返回某些创建起来比较复杂的值。如果默认值本身就是一个函数,那么你必须将 false 作为第三个参数传入,表明这个函数就是默认值,而不是一个工厂函数。

  • 与注册生命周期钩子的 API 类似,inject() 必须在组件的 setup() 阶段同步调用。

  • 当使用 TypeScript 时,key 可以是一个类型为 InjectionKey 的 symbol。InjectionKey 是一个 Vue 提供的工具类型,继承自 Symbol,可以用来同步 provide()inject() 之间值的类型。

源代码: 

<!-- App.vue -->
<script>
  import Hello from './components/Hello.vue';
  import {provide} from 'vue'
import { ref } from '@vue/reactivity';
  export default{
    data() {
        return {
            
        };
    },
    setup(){
      const name=ref('xueysr')
      provide('name',name)
      function changeName(){
        name.value='x-ysr'
      }
      return{
        changeName
      }
    },
    components: { Hello }
}

</script>

<template>
  <Hello></Hello>
  <button @click="changeName">改变name</button>
</template>

<style>

</style>

<!-- Hello.vue -->
<script>
  import {inject} from 'vue'
  export default{
    data(){
      return{
        counter:0
      }
    },
    setup(){
      const name=inject('name')
      return{
        name
      }
    }
  }
</script>

<template>
  <h1>我是hello组件</h1>
  <h2>{{name}}</h2>
</template>

<style>

</style>

部分内容转载自:组合式 API:setup() | Vue.js 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

X-ysr

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值