使用reactive无法在更新后获取到vm中的bottomOffset,但是shallowReactive可以

来源:10-8 createMessage 编码第六部分

78264609

2024-11-08

老师,我这里使用了reactive在第一时间获取不到vm.exposed.bottomOffset中的属性,但是后面Message组件挂载完成后,也没有重新去执行getLastMessageBottomOffset函数去获取最新的vm中的数据,但是使用shallowReactive就可以,这不应该啊

//method.ts
import { render, h, nextTick, shallowReactive, reactive } from 'vue'
import type { MessageCreatorProps, MessageContext } from './types'
import Message from './Message.vue'

let lastMessageId = 1
const DkMessageContext:MessageContext[] = reactive([])

export const DkMessage = (props: MessageCreatorProps) => {
    const id = `dk_message_${lastMessageId++}`
    const container = document.createElement('div')
    const _props = {
        ...props,
        id,
        onDestory: () => {
            const index = DkMessageContext.findIndex((msg) => msg.id === id)
            if (index === -1) return
            DkMessageContext.splice(index, 1)
            render(null, container)
        },
    }
    const vnode = h(Message, _props)

    render(vnode, container)

    const message = {
        id,
        vnode: vnode,
        vm: vnode.component!,
        props: _props,
    }

    DkMessageContext.push(message)

    nextTick(() => {
        document.body.appendChild(container.firstElementChild!)
    })

    return DkMessageContext
}

export const getLastMessage = () => {
    return DkMessageContext.at(-1)
}

export const getLastMessageBottomOffset = (id: number | string) => {
    const index = DkMessageContext.findIndex((msg) => msg.id === id)
    if (index > 0) {
        console.log(
            id,
            '-find_index:',
            index,
            '-find_prev.vm:',
            typeof DkMessageContext[index - 1].vm,
            '-find_prev.vm-->bottomOffset',
            DkMessageContext[index - 1].vm.exposed!.bottomOffset.value
        )
    }
    if (index <= 0) {
        return 0
    } else {
        const prev: MessageContext = DkMessageContext[index - 1]
        return prev.vm.exposed!.bottomOffset.value
    }
}

<!-- Message.vue -->
<template>
    <div ref="messageRef" class="dk-message" :class="{
        [`dk-message-${type}`]: type,
        'is-close': showClose
    }" :style="messageStyle" role="alert" v-if="messageShow">
        <div class="dk-message__content">
            <slot>
                {{ lastMessageBottomOffset + ' ' + offset + ' ' + currentMessageTopOffset + ' ' + +messageHeight + ' ' +
                    currentMessageBottomOffset }}
                <Render :vnode="message" />
            </slot>
        </div>
        <span class="dk-message__close" v-if="message" @click="$event => messageShow = false">
            <Icon icon="xmark"></Icon>
        </span>
    </div>
</template>
<script setup lang="ts">
    import { computed, nextTick, onMounted, ref, watch } from 'vue';
    import Render from '../common/Render';
    import Icon from '../Icon/Icon.vue';
    import type { MessageProps } from './types';
    import { getLastMessageBottomOffset } from './method';

    const props = withDefaults(defineProps<MessageProps>(), {
        type: 'info',
        duration: 3000,
        offset: 20
    })

    const messageRef = ref<HTMLElement>()

    const messageShow = ref(false)

    const messageHeight = ref(0)

    const lastMessageBottomOffset = computed(() => {
        console.log(props.id, '-get_lastMessageBottomOffset--',getLastMessageBottomOffset(props.id))
        return getLastMessageBottomOffset(props.id)
    })

    const currentMessageTopOffset = computed(() => props.offset + lastMessageBottomOffset.value)

    const currentMessageBottomOffset = computed(() => currentMessageTopOffset.value + messageHeight.value)

    const messageStyle = computed(() => ({
        top: currentMessageTopOffset.value + 'px'
    }))

    const showing = () => {
        if (props.duration <= 0) return
        setTimeout(() => {
            messageShow.value = false
        }, props.duration)
    }

    watch(messageShow, (cur) => {
        if (!cur) {
            props.onDestory()
        }
    })

    defineExpose({
        bottomOffset: currentMessageBottomOffset
    })

    onMounted(async () => {
        messageShow.value = true
        showing()

        await nextTick()
        messageHeight.value = messageRef.value!.getBoundingClientRect().height
    })
</script>

<style scoped>
    .dk-message {
        position: fixed;
        top: 10%;
        left: 50%;
        padding: 4px 8px;
        border: 2px solid black;
        background: springgreen;
        transform: translateX(-50%);
    }

</style>

下面是我的项目地址
仓库地址

写回答

1回答

张轩

2024-11-09

同学你好 

你说的vm.exposed.bottomOffset 这个直接是是 undefined 的对吗?我还没运行代码,先问一下

0
1
78264609
对,在使用reactive的时候有这种情况
2024-11-09
共1条回复

进阶必学,打造媲美ElementPlus的组件库

Vue3.3 + TS4 ,自主打造媲美 ElementPlus 的组件库

481 学习 · 219 问题

查看课程