vue3.x 组件数据传递 —— 父子传值 -- definePorps && defineEmits

以下示例:基于 Vue3 setup语法糖 

// 在vue2.x中,vue 单向传值,组件通过v-bind来绑定数据,接收参数的组件使用props来接收;

// 在vue3中,父组件通过v-bind来传值,子组件使用defineProps来接收 --(defineProps是全局编译器宏)—— 【因为script变为了setup函数,没有组件选项,使用defineProps来接收Props】

// defineProps 是一个方法,内部返回一个对象(所有挂载到该组件的props,不指定prop的属性值会放入attrs中)

// 父子传递数据规律:父组件动态绑定单向传值v-bind;绑定响应子组件的事件使用 @
// emit 绑定的事件名 规范示例:
// 父组件 @do-event="doEvent"
// 子组件 声明emit事件名 'do-event'

 


 

// 父子组件通信

// 方式一:props && emits

// 父组件 app.vue --基本字符类型直接传值,变量、复合类型使用v-bind绑定(缩写为“ :”符号)
// props 如果是多单词组成,kebab-case (短横线分隔命名) 命名;如:  <Demo :user-info="user.name"></Demo> 
<template>
  <div>
    <Demo :data="data" title="标题"></Demo> 
  </div>
</template>

<script setup lang="ts"> // setup语法糖
  
import Demo from './components/Demo.vue'; // setup语法糖效率提升之一:子组件只需要导入,无需声明 --即 components:['Demo'] 被省略
  
import { reactive } from 'vue';
const data = reactive<number[]>([1,2,3]);

</script>


// 子组件 demo.vue
<template>
  <div>
    <h2>{{title}}</h2>
    <h2>{{data}}</h2>
    <br/>
    <button @click="getProps">获取props</button>
  </div>
</template>

<script setup lang="ts">
 // 直接在template使用,将从父组件传入的值,通过string[]类型作为入参,传入defineProps中
 // defineProps(['title','data']); // 只读
  
  // 如果script 里的方法要拿到 props 的值
    let props = defineProps(['title','data'])
    const getProps = ()=>{
     console.log(props.title);
    }
</script>

点击 ‘获取porps’ 效果: 

 

 

 


 

进阶一:使用TS类型注解 
 
// 显性指定prop类型
// 使用TypeScript 类型注解

// app.vue
<template>
  <div>
    <Demo :data="data" title="标题" :person="person"></Demo>
  </div>
</template>

<script setup lang="ts">
import Demo from './components/Demo.vue'; 
import { reactive } from 'vue';
// import { Person } from './assets/type_interface/type_info'; // 减少Person代码的优化项
  
interface Person {
  name: string,
  age: number
}

const data = reactive<number[]>([1,2,3])
const person = reactive<Person>({name:'tom',age: 12});

</script>

// demo.vue

<script setup lang="ts">
interface Person { // 接口类型,接收父组件传入的person并指定接收的类型
  name: string,
  age: number
}
// 解析:接收具有类型断言的props,目的是保持严谨
  // defindProps返回对象,因此<>中 使用 {key: value}
  // title? -- 指可选的参数,该参数可以不接收
let props = defineProps<{title?: string, data: number[],person: Person}>();
const getProps = ()=>{
 console.log(props.title);
}
</script>
<template>
  <div>
    <h2>{{title}}</h2>
    <h2>{{data}}</h2>
    <h2>{{person.name}}--{{person.age}}</h2>
    <br/>
    <button @click="getProps">获取props</button>
  </div>
</template>


  /** person 是父组件传入的一个对象类型,这里使用interface接口定义的类型 -- 这里,可以发现父组件和子组件都有定义interface Person,所以我们就存在了优化点:减少重复代码。 -- 在app.vue中可以看到 // import { Person } from './assets/type_interface/type_info'; 
  type_info.ts 中
    interface Person {
      name: string,
      age: number
    }
  export type {Person}

-- 当然如果只是快速验证可行性,可以person:object 用法

-- 这里有扩展知识点:关于interface 和 type; -- 可自查
  */

 

进阶二:需要指定props的默认值 -- withDefaults 用法 
//  withDefaults API 可以让你在使用 TS 类型系统时,也可以指定 props 的默认值
//  参数1:props -- object类型 --通过defineProps传入props;
//  参数2:defaultValues --object类型

// app.vue
<template>
  <div>
    <Demo></Demo> // 这里未传值:
  </div>
</template>
<script setup lang="ts">
import Demo from './components/Demo.vue'; 
import { reactive } from 'vue';
interface Person {
  name: string,
  age: number
}

const data = reactive<number[]>([1,2,3])
const person = reactive<Person>({name:'tom',age: 10});
</script>


// demo.vue
<script setup lang="ts">
interface Person {
  name: string,
  age: number
}
let props = withDefaults(defineProps<{title?: string, data?: number[],person: Person}>(),{
  title:'demo标题', // 基本字符类型直接写默认值
  data:()=>[4,5,6], // 复合类型-数组 使用函数返回
  person:()=>{return {name:'xxx',age:12}} // 复合类型-对象 使用
})
const getProps = ()=>{
 console.log(props.title);
}
</script>
<template>
  <div>
    <h2>{{title}}</h2>
    <h2>{{data}}</h2>
    <h2>{{person.name}}--{{person.age}}</h2>
    <br/>
    <button @click="getProps">获取props</button>
  </div>
</template>

效果展示:— demo.vue 组件中的默认值 


// 子组件传值 -- 使用 defineEmits 方法 --【vue3.1.3版本前,这个API 是defineEmit,最新版为复数形式 -- 即结尾有s 】

// app.vue
<template>
  <div>
    <Demo @send-demo="getDemo"></Demo> // sendByDemo 为子组件声明的响应指令,getDemo为父组件接收数据的函数
  </div>
</template>
<script setup lang="ts">

import Demo from './components/Demo.vue'; 
import { reactive } from 'vue';
let getDemo = (list: number[])=>{ // 接收子组件的传参
  console.log(list);
}
</script>

// demo.vue
<script setup lang="ts">
import {reactive} from 'vue'
const list = reactive<number[]>([1,2,3,])
let emit = defineEmits(['send-demo']) // 获取emit定义的分发事件名称,使用kebab-case
const sendToApp = ()=>{ // 定义触发调用emit事件的方法
  emit('send-demo',list)
}
</script>
<template>
  <div>
    <button @click="sendToApp">发送值给父组件</button>// 触发sendToApp方法,从而调用emit
  </div>
</template>

 

 

 

 

 

 

posted @ 2022-05-18 16:45  抹茶奶盖xh  阅读(5479)  评论(0)    收藏  举报