想实现一个弹窗组件

<scale-dialog></scale-dialog>

要实现打开和关闭弹窗功能,很自然地想到给弹窗加一个属性,通过父组件给子组件传值来控制是否显示弹窗:

<scale-dialog :show="show"></scale-dialog>

但是这种形式只能在父组件关闭弹窗,而弹窗组件本身肯定也要有一个关闭按钮,弹窗自己关闭自己的话这种方式就不太合适了。
最后参考element ui,使用v-model实现。
在vue2版本中,v-model本质上是父组件绑定value属性(v-bind:value)并监听input事件,子组件触发input事件从而反向更改value值的语法糖,所以本人理所当然地如下实现弹窗组件:

<template>
    <div class="scale-dialog" :class="{sdShow: visiable, sdHide: !visiable}">
        <div class="scale-dialog-inner">
            <div class="scale-dialog-content" :style="{width, height}">
                <div class="sd-header">
                    <div class="sd-title">
                        <slot name="title">对话框</slot>
                    </div>
                    <div class="sd-close" @click="visiable = false"></div>
                </div>
                <div class="sd-body">
                    <slot name="body"></slot>
                </div>
                <div class="sd-footer">
                    <slot name="footer"></slot>
                </div>
            </div>
        </div>
        <div class="scale-dialog-modal"></div>
    </div>
</template>

<script setup>
    import { defineProps, computed } from 'vue'
    // 监听input事件
    const emit = defineEmits(['input'])
    const props = defineProps({
        value: {
            type: Boolean,
            default: false,
            required: true
        },
        width: {
            type: String,
            default: '144rem'
        },
        height: {
            type: String,
            default: 'auto'
        }
    })
    // 通过visiable变量控制是否显示弹窗
    const visiable = computed({
        get() {
            return props.value
        },
        set( newVal ) {
        	// 触发input事件,更改父组件的value值
            emit('input', newVal)
        }
    })
</script>

然后啪啪打脸,实际上点击弹窗没有任何效果。
这是因为vue3中更改了v-model的实现原理,把v-bind:value改成了v-bind:modelValue,监听的事件也从input改成了update:modelValue,所以应该改成如下方式实现:

<template>
    <div class="scale-dialog" :class="{sdShow: visiable, sdHide: !visiable}">
        <div class="scale-dialog-inner">
            <div class="scale-dialog-content" :style="{width, height}">
                <div class="sd-header">
                    <div class="sd-title">
                        <slot name="title">对话框</slot>
                    </div>
                    <div class="sd-close" @click="visiable = false"></div>
                </div>
                <div class="sd-body">
                    <slot name="body"></slot>
                </div>
                <div class="sd-footer">
                    <slot name="footer"></slot>
                </div>
            </div>
        </div>
        <div class="scale-dialog-modal"></div>
    </div>
</template>

<script setup>
    import { ref, defineProps, computed } from 'vue'

    const emit = defineEmits(['update:modelValue'])

    const props = defineProps({
        modelValue: {
            type: Boolean,
            default: false,
            required: true
        },
        width: {
            type: String,
            default: '144rem'
        },
        height: {
            type: String,
            default: 'auto'
        }
    })

    const visiable = computed({
        get() {
            return props.modelValue
        },
        set( newVal ) {
            emit('update:modelValue', newVal)
        }
    })

</script>

出现这个问题实际上还是vue3文档没有掌握好,还需继续努力。

Logo

前往低代码交流专区

更多推荐