探秘vue3的setup函数的两个参数!

关联精彩文章:# 改进tabs组件切换效果,丝滑的动画获得一致好评~

简介

随着vue3的不断演化,vue3的setup语法糖越来越被大家熟知,我们可以很容易的写出下面的代码。

js 复制代码
<template>
  <div>
    <p>{{ name }}</p>
  </div>
</template>

<script setup>
const props = defineProps(['name'])
</script>

但是,你还记得setup不使用语法糖的用法吗?还记得它的两个参数是什么吗?

js 复制代码
<template>
  <div>
    <p>{{ name }}</p>
    <button @click="handleClick">点击我</button>
    <slot></slot>
  </div>
</template>

<script>
export default {
  props: {
    name: {
      type: String,
      required: true
    }
  },
  setup(props, context) {
    const handleClick = () => {
      context.emit('change', props.name);
    }

    return {
      brand: props.brand,
      handleClick
    }
  }
}
</script>

上面的示例中,我们定义了一个名为nameprop,并在setup函数中通过context.emit触发了一个自定义事件change

如果你已经对上面非语法糖的写法陌生了,没关系,快跟我一些复习,探秘下原生的setup语法吧!

setup函数

在Vue 3中,setup是一个组合式API(Composition API)中的核心函数,用于定义组件的逻辑。setup函数在组件实例创建之前被调用,接收两个参数:propscontext。这两个参数为我们提供了访问组件属性和上下文的能力。

setup包含两个参数,一个为props、一个为context (均为形参)

diff 复制代码
-   props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性。
-   context:上下文对象
js 复制代码
<script>
export default {
    name:'Child',
    setup(props,context){

    }
}
</script>

props

props是一个对象,包含了父组件传递给当前组件的所有属性。在setup函数内部,props是响应式的,意味着当父组件的属性发生变化时,setup函数中的props也会自动更新。

props的含义和基本用法和vue2是一致的。

vue2中的props

APP.vue(父组件)

js 复制代码
<template>
	<div class="app">
		<h3>我是App组件</h3>
		<Child :name ="提姆" age="9"></Child>
	</div>
</template>
<script>
	import Child from './components/Child.vue'//静态引入
	export default {
		name:'App',
		components:{Child},  //组件写法不变
	}
</script>

Child.vue(子组件)

js 复制代码
<template>
    <div class="child">
        子组件
        <span>{{ name }}</span>
        <span>{{ age }}</span>
    </div>
</template>

<script>
    export default {
        name:'Child',
        // props:["name","age"],    //组件的props参数同vue2
        setup(props,context){
           console.log(props)
           console.log(context)
        // console.log(context.attrs)
        }
    }
</script>

如上图,如果props不声明接收(被注释),则setup的第一个参数为空,但context内可以找到相关值。

声明props后,即去掉注释后,

context详解

context是一个对象,包含以下三个属性:attrsslotsemit

attrs

attrs是一个对象,包含了父组件传递但未被声明为props的特性。它类似于this.$attrs,可以用来接收未声明的属性。

js 复制代码
setup(props, context) {
  console.log(context.attrs); // 输出未声明为 props 的所有属性
}

vue2中的attrs

js 复制代码
export default {
  //props:['msg','school'],
  mounted() {
    console.log(this)
  }
}

我们可以发现,vc实例上没有 msg 和 school 这两个属性了。

但是,打开 a t t r s ,我们会惊奇的发现,即使子组件没有声明接受,父组件传递的参数也会被 attrs,我们会惊奇的发现,即使子组件没有声明接受,父组件传递的参数也会被 attrs,我们会惊奇的发现,即使子组件没有声明接受,父组件传递的参数也会被attrs所捕获

这也意味着即使我们不声明参数的接收,也可以直接在子组件中使用 { {$attrs.msg } }的方式使用参数。

综上,我们可以知道:子组件声明接收的参数,会直接挂载在vc实例上;而子组件未声明接收参数,会储存在 $attrs 中。

slots

slots是一个对象,包含了传递给组件的插槽内容。可以用来访问和渲染插槽内容。

js 复制代码
setup(props, context) {
  console.log(context.slots); // 输出所有插槽内容
}

vue2中的slots

打印子组件的实例对象vc

js 复制代码
<template>
  <div>
    我是Demo组件
  </div>
</template>
export default {
  mounted() {
    console.log(this)
  }
}

可以发现,子组件的实例对象vc上的$slots属性为空

如果我们在demo标签之间写一点东西

js 复制代码
<template>
  <div>
    <h1>我是Vue2写的效果<h1>
    <Demo>
       <span>你好啊<span1>
    </Demo>
  </div>
</template>

这时,我们打印一下子组件的实例对象v会惊喜的发现,$slots上存放了我们传入的虚拟节点(Vnode)

这个时候,如果我们在子组件中定义了插槽,这些虚拟节点就会渲染在插槽出现的位置

js 复制代码
<template>
  <div>
    我是Demo组件
    <slot></slot>
  </div>
</template>
export default {
  mounted() {
    console.log(this)
  }
}

当然,即使不定义插槽,标签之间的虚拟节点也都会存放在$slots属性上。

emit

emit是一个函数,用于触发自定义事件。它类似于this.$emit,可以用来在组件内部触发事件。

javascript 复制代码
setup(props, context) {
  const handleClick = () => {
    context.emit('customEvent', '华为');
  }
  return { handleClick };
}

总结

Vue 3中的setup函数是组合式API的核心,用于定义组件逻辑。它接收propscontext两个参数,提供访问组件属性和上下文的能力。props是响应式的,包含父组件传递的属性。context包含attrsslotsemit,分别用于接收未声明的属性、访问插槽内容和触发自定义事件。相比Vue 2的选项式API,Vue 3的组合式API提供了更灵活和模块化的代码组织方式,使组件逻辑更清晰、更易于维护。

相关推荐
万少4 小时前
用腻了 WorkBuddy 的默认界面?这个开源小工具给它换上了毛玻璃
前端·javascript·后端
海上彼尚8 小时前
Nodejs也能写Agent - 16.LangGraph篇 - 条件分支与循环
前端·后端·langchain·node.js
To_OC8 小时前
从 “卡死半天” 到 “打字机效果”:大模型流式输出前端实现全记录
前端·javascript·llm
SoaringHeart9 小时前
Flutter最佳实践:键盘辅助视图输入框天添加图片附件
前端·flutter
kyriewen9 小时前
我看完这篇安全论文——AI推荐的npm包,92%是编出来的
前端·javascript·ai编程
小心我捶你啊11 小时前
数据采集和Web解锁不是一回事,从用途到规则区分
前端·爬虫·网络协议
hunterandroid11 小时前
[鸿蒙从零到一] ArkUI 基础组件实战:Text、Image、Button 与 TextInput
前端
fsssb11 小时前
Chromium 源码学习笔记(五):一次点击,在进入 JS 之前先经历了什么?
前端
hunterandroid11 小时前
WorkManager 可靠性实战:唯一任务、重试与幂等设计
android·前端