Vue 3:如何在 Typed.js 短语完成时使用 Watch/WatchEffect 触发消息?

Vue 3: How to use Watch/WatchEffect to trigger message when a Typed.js phrase completes?

我有一些 Vue 2 代码正在尝试升级到 Vue 3,但我在使用 Typed.js 库的实例时遇到了很多麻烦。这是我在 Vue 2 中的一个最小工作示例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>CDN with Vue 2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">

        <h1>Here's the typed phrase:</h1>
        <h2 id="typing"></h2>
        <div v-if="showMessage">
            And now the typing is complete and this message appears!
        </div>
    </div>


    <script src="https://cdnjs.cloudflare.com/ajax/libs/typed.js/2.0.0/typed.min.js"></script>
    <script>
        var app = new Vue({
            el: '#app',
            data() {
                return {
                    typed: "",
                    showMessage: false,
                };
            },
            mounted() {
                this.initTyped();
            },
            methods: {
                initTyped() {
                    this.typed = new Typed("#typing", {
                        strings: ["Hi, I'm Bill. <br/> I'm a developer."],
                        loop: false,
                        showCursor: false,
                        typeSpeed: 35,
                    });
                }
            },
            watch: {
                "typed.typingComplete": function () {
                    if (this.typed.typingComplete) {
                        this.showMessage = true;
                    }
                },
            },
        })
    </script>
</body>
</html>

以上代码应该可以正常工作,只需将其粘贴到文件中并查看即可。它应该会输入一个句子,输入完成后,会出现一条消息。

我是 Vue 3 的新手,所以对于以下可能出现的所有错误深表歉意,但这是我想要开始工作的要点:

<html>

<head>
    <meta charset="UTF-8">
    <title>CDN with Vue 2</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>

<body>
    <div id="app">
        <h1>Here's the typed phrase:</h1>
        <h2 id="typing"></h2>
        <div v-if="showMessage">
            And now the typing is complete and this message appears!
        </div>
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/typed.js/2.0.0/typed.min.js"></script>

    <script>
        const { ref, createApp, onMounted, watchEffect } = Vue
        createApp({
            setup() {

                let showMessage = ref(false)

                const initTyped = () => {
                    const typed = new Typed("#typing", {
                        strings: ["Hi, I'm Bill. <br/> I'm a developer."],
                        loop: false,
                        showCursor: false,
                        typeSpeed: 35,
                    });
                }

                onMounted(() => {
                    initTyped()
                })

                watchEffect(() => {
                    if (typed.typingComplete) {
                        showMessage = true;
                    }
                });

                return {
                    showMessage
                }
            }
        }).mount('#app')
    </script>
</body>
</html>

我不知道我是否应该使用 Watch/WatchEffect,我猜我声明和更新 showMessage 变量全错了,我不知道如何设置 typed 变量,所以它对 watchEffect 可用,而且我通常不知道我在用组合 API!

做什么

同样在你推荐vue-typed-js之前,这个库似乎还不兼容Vue 3;但无论如何我都没有在 Vue 2 中使用它。

感谢任何帮助,Vue 3 中的一些代码会很棒!

等效的 Vue 3 代码为:

  1. typed 声明为 ref

  2. initTyped() 中,将 typed 的值设置为新的 Typed 实例(通过其 .value 属性)。

  3. 在watcher中,设置showMessage的值 至 true(通过其 .value 属性)。

1️⃣
let typed = ref()

const initTyped = () => {
    2️⃣
    typed.value = new Typed("#typing", {⋯});
}


onMounted(() => {
    initTyped()
})

watchEffect(() => {
    if (typed.typingComplete) {
        3️⃣
        showMessage.value = true;
    }
});

<html>

<head>
    <meta charset="UTF-8">
    <title>CDN with Vue 2</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>

<body>
    <div id="app">
        <h1>Here's the typed phrase:</h1>
        <h2 id="typing"></h2>
        <div v-if="showMessage">
            And now the typing is complete and this message appears!
        </div>
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/typed.js/2.0.0/typed.min.js"></script>

    <script>
        const { ref, createApp, onMounted, watchEffect } = Vue
        createApp({
            setup() {

                let showMessage = ref(false)
                let typed = ref()
                
                const initTyped = () => {
                    typed.value = new Typed("#typing", {
                        strings: ["Hi, I'm Bill. <br/> I'm a developer."],
                        loop: false,
                        showCursor: false,
                        typeSpeed: 35,
                        onComplete: () => showMessage.value = true
                    });
                }

                onMounted(() => {
                    initTyped()
                })

                watchEffect(() => {
                    if (typed.typingComplete) {
                        showMessage.value = true
                    }
                })
                
                return {
                    showMessage
                }
            }
        }).mount('#app')
    </script>
</body>
</html>

但您不需要存储对 Typed 实例的引用。 Typed 选项包括一个 onComplete callback 属性 可以代替观察者使用,因此您的代码可以简化为:

const initTyped = () => {
    new Typed("#typing", {
        ⋮
        onComplete: () => showMessage.value = true, 
    });
}

onMounted(() => {
    initTyped()
})

<html>

<head>
    <meta charset="UTF-8">
    <title>CDN with Vue 2</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>

<body>
    <div id="app">
        <h1>Here's the typed phrase:</h1>
        <h2 id="typing"></h2>
        <div v-if="showMessage">
            And now the typing is complete and this message appears!
        </div>
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/typed.js/2.0.0/typed.min.js"></script>

    <script>
        const { ref, createApp, onMounted } = Vue
        createApp({
            setup() {

                let showMessage = ref(false)

                const initTyped = () => {
                    new Typed("#typing", {
                        strings: ["Hi, I'm Bill. <br/> I'm a developer."],
                        loop: false,
                        showCursor: false,
                        typeSpeed: 35,
                        onComplete: () => showMessage.value = true
                    });
                }

                onMounted(() => {
                    initTyped()
                })

                return {
                    showMessage
                }
            }
        }).mount('#app')
    </script>
</body>
</html>