Vue3 父子组件

9 篇文章 0 订阅

组件传值

在子组件中通过props声明需要传参参数
父组件传值
通过 :参数进行传参

子组件调用父组件方法

子组件通过$emit(parentFunction,param…) 触发父组件事件
parentFunction 父组件方法名,父组件通过@parentFunction来声明该事件
param 可以给父组件事件传参

父组件调用子组件方法

如果需要让父组件调用子组件方法
需要在父组件中暴露子组件给模版
在子组件中暴露其方法给模版
需要使用setup,其在vue官方文档中解释为(顶级绑定暴露给模板)

完整示例

子组件 MaskModal.vue

<template>
    <div class="mask" v-show="showModal">
        <div class="real_mask"></div>
        <div class="m_container">
            <div class="title">
                <span class="t_t">{{title}}</span>
                # 这个通过$emit调用父组件的取消方法并传参
                <span class="t_i" @click="$emit('cancel','已经取消了')"><b>x</b></span>
            </div>
            <div class="body">
                <slot name="body">333</slot>
            </div>
            <div class="footer">
                  # 这个通过$emit调用父组件的提交方法
                <div class="yes" @click="$emit('submit')">{{okTest?okTest:'同意'}}</div>
                  # 这个通过$emit调用父组件的取消方法
                <div class="no" @click="$emit('cancel')">{{noTest?noTest:'不同意'}}</div>
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        name: "MaskModal",
        # 声明子组件需要的参数
        props: {
            showModal: Boolean,
            okTest: String,
            noTest: String,
        },
        setup: () => {
            # 这里是为了让父组件能够调用子组件的方法
            const childMethod = () => {
                alert("成功调用子组件方法");
            }
            # 将子组件的方法通过setup暴露给顶级模版
            return {
                childMethod
            }
        },
        data: () => {
            return {
                title: '协议声明',
            }
        },
    }
</script>

# 样式 不解释
<style scoped lang="scss">
    @import "src/assets/sass/mixin.scss";
    @import "src/assets/sass/main.scss";

    .mask {
        @include create_mask();
        z-index: 777;

        .real_mask {
            @include create_mask();
            background-color: #333;
            opacity: .5;
        }

        .m_container {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 800px;
            min-height: auto;
            background-color: white;

            .body {
                width: 100%;
                min-height: 100px;
            }

            .title {
                width: 100%;
                height: 70px;
                background-color: #f5f5f5;
                text-align: center;
                line-height: 70px;
                color: #424242;
                font-size: 18px;
                font-weight: 400;

                .t_t {
                    float: left;
                    margin-left: 20px;
                }

                .t_i {
                    display: block;
                    position: relative;
                    float: right;
                    top: 22px;
                    height: 25px;
                    font-size: 25px;
                    width: 25px;
                    color: black;
                    border-radius: 25px;
                    margin-right: 20px;
                    line-height: 25px;

                    &:hover {
                        background-color: red;
                        color: white;
                    }
                }
            }

            .footer {
                width: 100%;
                height: 81px;
                background-color: #f5f5f5;
                display: flex;
                justify-content: center;
                align-items: center;

                .yes {
                    width: 160px;
                    height: 40px;
                    background-color: #ff6700;
                    text-align: center;
                    line-height: 40px;
                    color: white;
                }

                .no {
                    width: 160px;
                    height: 40px;
                    margin-left: 20px;
                    background-color: #b0b0b0;
                    line-height: 40px;
                    text-align: center;
                    color: white;

                    &:hover {
                        background-color: grey;
                    }
                }

            }
        }
    }
</style>

父组件 HomePage.vue

<template>
    <common-header></common-header>
    <product-menu></product-menu>
    <product-show title="手机"></product-show>
    <product-show title="平板"></product-show>
    <router-view></router-view>
    
    # show-modal="showModal" ok-test="ok" no-test="no" 给子组件传值
    # @cancel="cancel" @submit="submit" 父组件事件 分别对应 $emit('cancel') $emit('submit')
    # ref="child" 可以让我们直接访问底层 DOM 元素的情况 对应 const child
    <mask-modal :show-modal="showModal" ok-test="ok" no-test="no" ref="child" @submit="handleClick" @cancel="cancel">
        <template v-slot:body>
            支付成功
        </template>
    </mask-modal>
</template>

<script>
    import CommonHeader from "../components/CommonHeader";
    import ProductMenu from "../components/ProductMenu";
    import ProductShow from "../components/ProductShow";
    import MaskModal from "../components/MaskModal";
    import {ref} from 'vue'

    export default {
        setup: () => {
            # child 变量名 需要同 组件上的ref 名称相同
            const child = ref()
            const handleClick = () => {
                // 调用子组件的方法
                # 需要子组件通过setup 暴露 childMethod 方法
                child.value.childMethod()
            }

           
            # 原理 就是 通过ref 能直接访问 子组件dom
            # 子组件暴露的方法 能从dom中直接调用
            # 暴露子组件和 handleClick 方法
            return {
                child,
                handleClick
            }
        },
        name: "HomePage",
        data: () => {
            return {
                showModal: true,
            }
        },
        components: {CommonHeader, ProductMenu, ProductShow, MaskModal},
        methods: {
            cancel(message) {
                console.log(message);
                this.showModal = false;
            },
        },
        mounted() {

        }
    }
</script>

<style lang="scss" scoped>
</style>

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值