关联精彩文章:# 改进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>
上面的示例中,我们定义了一个名为name
的prop
,并在setup
函数中通过context.emit
触发了一个自定义事件change
。
如果你已经对上面非语法糖的写法陌生了,没关系,快跟我一些复习,探秘下原生的setup语法吧!
setup函数
在Vue 3中,setup
是一个组合式API(Composition API)中的核心函数,用于定义组件的逻辑。setup
函数在组件实例创建之前被调用,接收两个参数:props
和context
。这两个参数为我们提供了访问组件属性和上下文的能力。
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
是一个对象,包含以下三个属性:attrs
、slots
和 emit
。
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 这两个属性了。
但是,打开 <math xmlns="http://www.w3.org/1998/Math/MathML"> a t t r s ,我们会惊奇的发现,即使子组件没有声明接受,父组件传递的参数也会被 attrs,我们会惊奇的发现,即使子组件没有声明接受,父组件传递的参数也会被 </math>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的核心,用于定义组件逻辑。它接收props
和context
两个参数,提供访问组件属性和上下文的能力。props
是响应式的,包含父组件传递的属性。context
包含attrs
、slots
和emit
,分别用于接收未声明的属性、访问插槽内容和触发自定义事件。相比Vue 2的选项式API,Vue 3的组合式API提供了更灵活和模块化的代码组织方式,使组件逻辑更清晰、更易于维护。