首页 > 其他分享 >16-setup()与组合式API-computed-watch

16-setup()与组合式API-computed-watch

时间:2024-07-20 15:53:56浏览次数:17  
标签:count const computed 16 setup value props ref

16-setup()与组合式API-computed-watch

一、setup()

1、基本使用:

setup() 钩子是在组件中使用组合式 API 的入口,通常只在以下情况下使用:

  1. 需要在非单文件组件中使用组合式 API 时。

  2. 需要在基于选项式 API 的组件中集成基于组合式 API 的代码时。

<script>
import { ref } from 'vue'

export default {
  setup() {
    const count = ref(0)

    // 返回值会暴露给模板和其他的选项式 API 钩子
    return {
      count
    }
  },

  mounted() {
    console.log(this.count) // 0
  }
}
</script>

<template>
  <button @click="count++">{{ count }}</button>
</template>

在模板中访问从 setup 返回的 ref 时,它会自动浅层解包,因此你无须再在模板中为它写 .value。当通过 this 访问时也会同样如此解包。(ref返回的是一个包装对象,但在其他模板中访问setup返回的值时直接访问对象就是具体的值【也就是自动解包】)

setup() 自身并不含对组件实例的访问权,即在 setup() 中访问 this 会是 undefined。你可以在选项式 API 中访问组合式 API 暴露的值,但反过来则不行。(在setup内部不可以使用this,当你像访问ref或其他响应值需要具体属性名字+.value访问)

2、访问 Props

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

export default {
  props: {
    title: String
  },
  setup(props) {
    console.log(props.title)
  }
}

请注意如果你解构了 props 对象,解构出的变量将会丢失响应性。因此我们推荐通过 props.xxx 的形式来使用其中的 props。

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

import { toRefs, toRef } from 'vue'

export default {
  setup(props) {
    // 将 `props` 转为一个其中全是 ref 的对象,然后解构
    const { title } = toRefs(props)
    // `title` 是一个追踪着 `props.title` 的 ref
    console.log(title.value)

    // 或者,将 `props` 的单个属性转为一个 ref
    const title = toRef(props, 'title')
  }
}
3、Setup 上下文

传入 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)
  }
}

该上下文对象是非响应式的,可以安全地解构:

export default {
  setup(props, { attrs, slots, emit, expose }) {
    ...
  }
}
4、暴露公共属性

expose 函数用于显式地限制该组件暴露出的属性,当父组件通过模板引用(ref)访问该组件的实例时,将仅能访问 expose 函数暴露出的内容:

export default {
  setup(props, { expose }) {
    // 让组件实例处于 “关闭状态”
    // 即不向父组件暴露任何东西
    expose()

    const publicCount = ref(0)
    const privateCount = ref(0)
    // 有选择地暴露局部状态
    expose({ count: publicCount })
  }
}

下面我们来解释一些如何配合ref模板引用来使用

<!-- 子组件代码 -->
<template>
  <button @click="increment">Increment</button>
</template>

<script>
import { ref } from 'vue';

export default {
  setup(_, { expose }) {
    const count = ref(0);

    const increment = () => {
      count.value++;
    };

    expose({
      count,
      increment
    });

    return {
      increment
    };
  }
};
</script>

<!-- 父组件代码 -->
<template>
  <ChildComponent ref="childComp" />
  <button @click="incrementChildCount">Increment Child Count from Parent</button>
  <p>Child Count from Parent: {{ childComp?.count }}</p>
</template>

<script>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  setup() {
    // 定义对象接受子组件expose对象
    const childComp = ref(null);
	
     //父组件使用子组件的暴露的方法重新定义新函数
    const incrementChildCount = () => {
      if (childComp.value) {
        childComp.value.increment();
      }
    };

    return {
      childComp,
      incrementChildCount
    };
  }
};
</script>

上述值得我们注意的就是子组件ref值,父组件setup定义接受子组件expose对象的对象名,setup返回ref值要一致,也就是上述代码的这三个部分

1、<ChildComponent ref="childComp" />
<script>
2、const childComp = ref(null);
return {
3、   childComp,
      incrementChildCount
    };
</script>
5、与渲染函数一起使用

setup 也可以返回一个渲染函数,此时在渲染函数中可以直接使用在同一作用域下声明的响应式状态:

import { h, ref } from 'vue'

export default {
  setup() {
    const count = ref(0)
    return () => h('div', count.value)
  }
}

返回一个渲染函数将会阻止我们返回其他东西。对于组件内部来说,这样没有问题,但如果我们想通过模板引用将这个组件的方法暴露给父组件,那就有问题了

我们可以通过调用 expose() 解决这个问题:

import { h, ref } from 'vue'

export default {
  setup(props, { expose }) {
    const count = ref(0)
    const increment = () => ++count.value

    expose({
      increment
    })

    return () => h('div', count.value)
  }
}

这样既可以使用h渲染函数,也能将想暴露给父组件的属性可以正常返回

二、computed

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

1、创建一个只读的计算属性 ref:
const count = ref(1)
const plusOne = computed(() => count.value + 1)

console.log(plusOne.value) // 2

plusOne.value++ // 错误
2、创建一个可写的计算属性 ref:
const count = ref(1)
const plusOne = computed({
  get: () => count.value + 1,
  set: (val) => {
    count.value = val - 1
  }
})

plusOne.value = 1
console.log(count.value) // 0

三、watch

侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。

watch() 默认是懒侦听的,即仅在侦听源发生变化时才执行回调函数。

第一个参数是侦听器的。这个来源可以是以下几种:

  • 一个函数,返回一个值
  • 一个 ref
  • 一个响应式对象
  • …或是由以上类型的值组成的数组

第二个参数是在发生变化时要调用的回调函数。这个回调函数接受三个参数:新值、旧值,以及一个用于注册副作用清理的回调函数。该回调函数会在副作用下一次重新执行前调用,可以用来清除无效的副作用,例如等待中的异步请求。

  • immediate:在侦听器创建时立即触发回调。第一次调用时旧值是 undefined
  • deep:如果源是对象,强制深度遍历,以便在深层级变更时触发回调。参考深层侦听器
  • flush:调整回调函数的刷新时机。参考回调的刷新时机watchEffect()
  • onTrack / onTrigger:调试侦听器的依赖。参考调试侦听器
  • once:回调函数只会运行一次。侦听器将在回调函数首次运行后自动停止。

示例:

1、侦听一个 getter 函数:
const state = reactive({ count: 0 })
watch(
  () => state.count,
  (count, prevCount) => {
    /* ... */
  }
)
2、侦听一个 ref:
const count = ref(0)
watch(count, (count, prevCount) => {
  /* ... */
})
// 上述第一个参数一定不要是count.value 参数是count监听的是一个响应式对象,参数是count.value监听的是一个静态对象,也就是侦听器不回触发
3、当侦听多个来源时,回调函数接受两个数组,分别对应来源数组中的新值和旧值:
watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
  /* ... */
})
4、当使用 getter 函数作为源时,进行深层监听(即监听复杂数据类型)
const state = reactive({ count: 0 })
watch(
  () => state,
  (newValue, oldValue) => {
    // newValue === oldValue
  },
  { deep: true }
)

标签:count,const,computed,16,setup,value,props,ref
From: https://blog.csdn.net/2301_79349971/article/details/140572672

相关文章

  • MSCD260-16-ASEMI工业电源MSCD260-16
    编辑:llMSCD260-16-ASEMI工业电源MSCD260-16型号:MSCD260-16品牌:ASEMI封装:MSCD批号:2024+类型:整流模块电流:260A电压:1600V安装方式:直插式封装特性:大功率、整流模块产品引线数量:4产品内部芯片个数:6产品内部芯片尺寸:MIL工作结温:-40℃~150℃功率:50W包装方式:500/盒:3000/箱......
  • ViT(论文解读):An Image is worth 16*16 words
    研究问题虽然transformer已经成为NLP领域的标准(BERT、GPT3、T5),但是在CV领域很有限。在CV中,自注意力要么和CNN一起用,要么替换CNN中某个组件后保持整体结构不变。本文证明了对CNN的这种依赖并不必要,在图像分类中,纯VisionTransformer直接作用于一系列图像块也可以取得不错的成果......
  • [rCore学习笔记 016]实现应用程序
    写在前面本随笔是非常菜的菜鸡写的。如有问题请及时提出。可以联系:[email protected]:https://github.com/WindDevil(目前啥也没有设计方法了解了特权级机制,实际上如果要设计一个应用程序就需要保证它符合U模式的要求,不要去访问S模式下的功能,那么其实现要点是:应......
  • CF1698 F
    CF1698F不错的题目。考虑必要条件,也就是不变量,发现操作不改变相邻二元组集合,且不能改变\(a_1,a_n\)。那么必要条件就是\(a,b\)相邻二元组集合相等和\(a_1=b_1,a_n=b_n\)。通过构造证明充分性。对于此类从\(a\)操作到\(b\)的问题,且操作可逆,不妨考虑中间状态\(c\),考虑......
  • MDS130-16-ASEMI整流模块MDS130-16
    编辑:llMDS130-16-ASEMI整流模块MDS130-16型号:MDS130-16品牌:ASEMI封装:MDS批号:2024+分类:整流模块特性:整流模块、整流桥平均正向整流电流(Id):130A最大反向击穿电压(VRM):1600V恢复时间:>2000ns结温:-40℃~150℃正向峰值电压:1.05V~1.25V引脚数量:5芯片个数:6芯片尺寸:MILMDS130-1......
  • LeetCode题练习与总结:比较版本号--165
    一、题目描述给你两个 版本号字符串 version1 和 version2 ,请你比较它们。版本号由被点 '.' 分开的修订号组成。修订号的值 是它 转换为整数 并忽略前导零。比较版本号时,请按 从左到右的顺序 依次比较它们的修订号。如果其中一个版本字符串的修订号较少,则将缺失......
  • SQL Prompt安装不上(报错:1603)
     一开始一直跟踪服务看到是RedGateClient运行不起来(报错信息代码是这个1603),后面查询到官网:https://productsupport.red-gate.com/hc/en-us/articles/360015772598-Redgate-Client-Service-fails-to-start使用管理员运行CMD执行:netshhttpaddiplisten127.0.0.1 之后再......
  • 【Software Defined Radio 】Zynq Ultrascale+ RFSoC --> 16 时分多路传输:正交频分多
    OFDM通过将宽带频率选择信道划分为几个并行子信道来解决这个问题。渠道。这些子通道中的每一个都足够窄,以确保它们单独体验“平坦”衰落“,这意味着子通道上的响应是恒定增益,或简单的线性响应。作为一个因此,可以使用非常简单的补偿响应来单独均衡子通道。使用分信道显著......
  • verilog实现ram16*8 (vivado)
    moduleram_16x2(inputclk,//时钟信号inputwe,//写使能inputen,//使能信号input[3:0]addr,//地址线input[1:0]datain,//输入数据线outputreg[1:0]dataout//输出数据线);//定义存储器数组......
  • 在 Ubantu上安装 FreePBX 16&Asterisk20
    在Ubantu上安装FreePBX16&Asterisk20注:必须以Root用户身份安装更新系统apt-getupdate&&apt-getupgrade-y安装SURY存储库签名密钥echo"debhttps://packages.sury.org/php/$(lsb_release-sc)main"|sudotee/etc/apt/sources.list.d/php7.x.listap......