一、简述

setup语法<script setup> 的组件是默认私有的:一个父组件无法访问到一个使用了 <script setup> 的子组件中的任何东西,除非子组件在其中通过 defineExpose 宏显式暴露。

当父组件通过模板引用获取到了该组件的实例时,得到的实例类型为 { a: number, b: number } (ref 都会自动解包,和一般的实例一样)

二、父组件调用子组件方法/变量

1.子组件[defineExpose]

<template>
	<div>子组件</div>
</template>
 
<script setup>
// 第1步:定义子组件的方法
const getUserName = (userId) => {
	console.log(userId)
}
// 第1步:定义子组件的变量
const userVO = ref()
// 第2步:暴露方法
defineExpose({
	getUserName,
    userVO
})
</script>

2.父组件

<template>
    <!--第2步 在引用子组件时,定义ref引用-->
	<child ref="childRef" />
</template>
<script setup>
import Child from './components/child.vue'
// 第1步 定义子组件引用变量
const childRef = ref(null)
// 第3步 调用子组件方法/变量
const getChildMethodOrValue = () => {
	// 调用子组件的方法或者变量,通过value
	childRef.value.getUserName(8);
    // 这里子组件userVO会自动拆包,不用使用userVO.value
    console.log('调用子组件的变量',childRef.value.userVO)
}
</script>

三、子组件调用父组件方法/变量

1.方法调用

1.1.父组件

<template>
    // 第2步:定义子组件引用父组件方法名
	<child @getUserName="handle"/>
</template>
 
<script setup>
	import Child from './components/child.vue';
    // 第1步:定义父组件需要被调用的方法
	const handle = (userId) => {
		console.log('子组件调用了父组件的方法',userId)
	}
</script>

 1.2.子组件[defineEmits]

<template>
	<view>子组件</view>
	<button @click="handleBtn">调用父组件的方法</button>
</template>
 
<script setup>
    //第1步:定义子组件调用父组件方法的引用
	const emit = defineEmits(['getUserName'])
	const handleBtn= () => {
        // 第2步:通过方法引用调用父组件方法
		emit('getUserName',12)
	}
</script>

 2.参数传递

2.1.单向传递[defineProps]

所有的 props 都遵循着单向绑定原则,props 因父组件的更新而变化,自然地将新的状态向下流往子组件,而不会逆向传递。这避免了子组件意外修改父组件的状态的情况,不然应用的数据流将很容易变得混乱而难以理解。

另外,每次父组件更新后,所有的子组件中的 props 都会被更新到最新值,这意味着你不应该在子组件中去更改一个 prop。

prop 被用于传入初始值;而子组件想在之后将其作为一个局部数据属性。在这种情况下,最好是新定义一个局部数据属性,从 props 上获取初始值即可:

const props = defineProps(['initialCounter'])

// 计数器只是将 props.initialCounter 作为初始值
// 像下面这样做就使 prop 和后续更新无关了
const counter = ref(props.initialCounter)
 2.1.1.父组件
<template>
    <!--第2步:将需要传递的参数绑定到子组件-->
	<child :userVO='userVO'/>
</template>
 
<script setup>
	import Child from './components/child.vue';
    // 第1步:定义需要传递到子组件的参数
	const userVO = ref({
        id: 18,
        name:'mark'
    })
</script>
  2.1.2.子组件
<template>
	<view>子组件</view>
    <!--第2步:使用父组件传递的数据-->
    <span>{{caseVO.name}}</span>
</template>
 
<script setup>
    //第1步:定义需要接收父组件传递的数据
	const props = defineProps({
        caseVO:{
            type:Object,
            default:null
        }
    })
    //第2步:使用父组件传递的数据
	console.log('可以直接使用父组件传递的数据',props.caseVO.name)
</script>

2.1.双向绑定[defineModel、defineProps+defineEmits]

2.1.1 defineModel(vue3.4+)

defineModel 是一个便利宏。编译器将其展开为以下内容:

  • 一个名为 modelValue 的 prop,本地 ref 的值与其同步;
  • 一个名为 update:modelValue 的事件,当本地 ref 的值发生变更时触发。
 2.1.1.1 父组件
<template>
    <!--第2步:将需要传递的参数绑定到子组件-->
	<child v-model:userVO='userVO'/>
</template>
 
<script setup>
	import Child from './components/child.vue';
    // 第1步:定义需要传递到子组件的参数
	const userVO = ref({
        id: 18,
        name:'mark'
    })
</script>
 2.1.1.2 子组件 
<template>
	<view>子组件</view>
    <!--第2步:使用父组件传递的数据-->
    <input v-model='caseVO.name'></input>
</template>
 
<script setup>
    //第1步:定义需要接收父组件传递的数据
	const caseVO= defineModel('caseVO')
</script>
2.1.2 defineProps+defineEmits(vue3.4-)
 2.1.2.1 父组件 
<template>
    <!--第2步:将需要传递的参数绑定到子组件-->
	<child v-model:userVO='userVO'/>
</template>
 
<script setup>
	import Child from './components/child.vue';
    // 第1步:定义需要传递到子组件的参数
	const userVO = ref({
        id: 18,
        name:'mark'
    })
</script>
 2.1.2.2 子组件 
<template>
	<view>子组件</view>
    <!--第3步:使用父组件传递的数据-->
    <input v-model='caseVO.name' @input="updateFatherValue"></input>
</template>
 
<script setup>
    //第1步:定义需要接收父组件传递的数据
	const props = defineProps({
      caseVO: {
        type: Object
      }
    })
    //第2步:定义需要更新父组件传递的数据
    const emits = defineEmits(['update:caseVO'])
    const caseVO = ref(props.caseVO)
    //第4步:手动更新父组件对应的参数值
    const updateFatherValue = () =>{
        emits('update:caseVO',caseVO.value)
    }
</script>

 

GitHub 加速计划 / vu / vue
99
16
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:9 个月前 )
9e887079 [skip ci] 7 个月前
73486cb5 * chore: fix link broken Signed-off-by: snoppy <michaleli@foxmail.com> * Update packages/template-compiler/README.md [skip ci] --------- Signed-off-by: snoppy <michaleli@foxmail.com> Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 11 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐