Vue3学习之路(三)

771 阅读3分钟

父子组件之间的通讯

父传子 defineProps

父组件传值给子组件主要是由父组件为子组件通过v-bind绑定数值,而后传给子组件;子组件则通过 defineProps 接收使用。

<template>
  <p>这是父组件</p>
  <!-- 子组件 -->
  <ChildrenCom :name="name" :setCount="setCount"/>
  <el-button @click="setCount">父组件传递过来的方法</el-button>
</template>

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

const name = ref('父传子state')
</script>
<template>
  <p>这是子组件</p>
  <span>传递过来的值{{ name }} </span>
</template>

<script>
import { ref } from 'vue'

/**
 * 子组件获取参数方式
 * 1、defineProps(['count']);
 * 2、defineProps({count:number);
 * 3、defineProps({count:{type:number,default:0}});
 */

const props = defineProps({
  name: String,
  setCount: Function,
});
console.log(props.name)
</script>

父组件传递子组件方法还是state基本一样

子传父

1、defineProps方式

比较贴合React

<script setup>
import ChildrenCom from '@/components/DemoCon.vue';
import { ref } from 'vue';

const count = ref();

const transmitFather = params => {
  count.value = params;
};
</script>

<template>
  父组件
  <p>这是子组件传递过来的值:{{ count }}</p>
  <!-- 子组件 -->
  <ChildrenCom :transmitFather="transmitFather" />
</template>

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

const count = ref('子组件传递的值');
const props = defineProps(['transmitFather']);

const transmit = () => {
  props.transmitFather(count.value);
};
</script>

<template>
  <p>这是子组件</p>
  <el-button @click="transmit">子传父方法</el-button>
</template>

2、defineEmits方式

子组件传值给父组件主要是子组件通过defineEmits注册一个自定义事件,而后触发emit去调用该自定义事件,并传递参数给父组件。

在父组件中调用子组件时,通过v-on绑定一个函数,通过该函数获取传过来的值。

<script setup>
import ChildrenCom from '@/components/DemoCon.vue';
import { ref } from 'vue';

const count = ref();
const transmitFather = params => {
  count.value = params;
};
</script>

<template>
  父组件
  <p>这是子组件传递过来的值:{{ count }}</p>
  <!-- 子组件 -->
  <ChildrenCom @transmit-father="transmitFather" />
</template>
<template>
  <p>这是子组件</p>
  <el-button @click="transmit">子传父方法</el-button>
</template>

<script setup>
import { ref, defineEmits } from 'vue';

const count = ref('子组件传递的值');
const emit = defineEmits(['transmit-father']);

const transmit = () => {
  emit('transmit-father', count.value);
};
</script>

父组件调用子组件 defineExpose

默认情况下在 <script setup>语法糖下组件内部的属性和方法是不开放给父组件访问的,可以通过 defineExpose编译指定哪些属性和方法允许访问,父组件中使用ref.value调用子组件暴露的属性或方法。

在组件挂在完璧之后调用 也就是 onMethods 生命周期

<template>
    <div>我是父组件</div>
    <el-button @click="getSonMethod">获取子组件的方法</el-button>
    <ChildrenCom ref="sonMethodsRef"/>
</template>

<script setup>
import { ChildrenCom } from './ChildrenCom';
import { ref } from "vue";

const sonMethodsRef = ref()

const getSonMethod = () => {
  sonMethodsRef.value.toFatherMethod()
  console.log(sonMethodsRef.value.toFatherValue)
}
</script>
<template>
    <div>我是子组件</div>
</template>

<script setup>
import { defineExpose } from "vue";

const toFatherMethod = () => { 
    console.log("我是要暴露给父组件的方法") 
}
// 暴露给父组件的值 
const toFatherValue = ref<string>("我是要暴露给父组件的值")

// 暴露方法和属性给父组件 
defineExpose({toFatherMethod, toFatherValue})
</script>

在子组件中定义属性toFatherValue和方法toFatherMethod,而后通过defineExpose暴露出来。
父组件调用时,为子组件绑定一个ref,并定义一个ref变量sonMethodRef,通过调用sonMethodRef,来获取子组件暴露出来的属性和方法。

多层级嵌套传递 provide 和 inject

嵌套层级关系 : Father => SecondChild 组件传递参数,并在SecondChild组件里可以进行修改father组件

Father > FirstChild > SecondChild

<template>
  <p>你好,这是最上层组件</p>
  <FirstChild />
</template>

<script setup>
import { provide, ref } from 'vue';
import FirstChild from './FirstChild.vue';

const state = ref(0);

const setState = e => {
  console.log(e);
  state.value++;
};

provide('father-data', { state, name: 'Tom' });
provide('father-fun', setState);
</script>
<template>
  <SecondChild />
</template>

<script setup>
import SecondChild from '../components/SecondChild.vue';
</script>
<template>
  父组件传过来的值:{{ state }}--{{name}}
  <el-button @click="setState('ccc')">切换父组件的值</el-button>
</template>

<script setup>
import { inject } from 'vue';

const {state,name} = inject('father-data');
const setState = inject('father-fun');
</script>

父子组件双向绑定

<template>
  <el-button @click="dialog2Visible = true">组件内需要状态, 有自定义关闭按钮</el-button>
  <dialog-2 v-if="dialog2Visible" v-model="dialog2Visible" v-model:countAdd="count"></dialog-2>
</template>

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

const count = ref(100);
const dialog2Visible = ref(false);
</script>

// Dialog2 组件
<template>
  <el-dialog
    :model-value="modelValue"
    title="Tips"
    width="500"
    @close="hide"
  >
    <span>组件内部使用visible数据源 {{countAdd}}</span>
    <el-button @click="changeVmodal">Cancel</el-button>
    <div @click="$emit('update:modelValue', '喷射河马')">{{modelValue}}</div>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="hide">Cancel</el-button>
        <el-button type="primary" @click="hide">Confirm</el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script setup>
import {ref} from 'vue'
const props = defineProps({
  modelValue: Boolean, // 接收父组件使用 v-model 传进来的值,必须用 modelValue 这个名字来接收
  countAdd:Number
});
const count = ref(0)
const emit = defineEmits([
    'update:modelValue', // 必须用 update:modelValue 这个名字来通知父组件修改值
    'update:countAdd'
]);
const changeVmodal =()=>{
  emit('update:countAdd', count.value++ )
}
function hide() {emit('update:modelValue', false)}
</script>

更加丰富的传参