vue3 自定义指令 数据更新两次但是 指令只更新一次

vue3 自定义指令 数据更新两次但是 指令只更新一次
代码里面 写了两个延时指令 理论上 页面显示的是第二个延时指令里面的数据
下面代码 只要有网复制到html文件就可以运行
求哪位帮我看下

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title></title>
</head>

<body>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script src="https://unpkg.com/dayjs@1.8.21/dayjs.min.js"></script>
    <div id="app">
        <div v-demo>{{ times }}</div>
    </div>

    <script>
        const {
            createApp,
            ref
        } = Vue

        const app = createApp({
            setup() {
                const times = ref('')
                setTimeout(() => {
                    times.value = '2023-08-18 13:26:02'
                }, 1000)
                setTimeout(() => {
                    times.value = '2023-08-10 13:26:02'
                }, 5000)
                return {
                    times


                }
            }
        })
        app.directive('demo', (el, binding, ) => {
                console.log('==========el.textContent', el.textContent);
                if (!el.textContent) return
                el.textContent = dayjs(el.textContent).format('YYYY-MM-DD')
            }
            //  {
            //     updated: (el, binding, vnode, prevVnode) => {
            //         console.log('==========el.textContent', el.textContent);
            //         if (!el.textContent) return
            //         el.textContent = dayjs(el.textContent).format('YYYY-MM-DD')
            //             // el.textContent = dayjs(el.textContent).format('YYYY-MM-DD HH:mm:ss')
            //     }
            // }

        )
        app.mount('#app')
    </script>
</body>

</html>


binding里面包含有新的要绑定的值,el里面包含的是旧值

img

binding里面才是新的时间

img


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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title></title>
</head>

<body>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script src="https://unpkg.com/dayjs@1.8.21/dayjs.min.js"></script>
    <div id="app">
        <div>{{ formattedDate }}</div>
    </div>

    <script>
        const { createApp, ref, computed } = Vue

        const app = createApp({
            setup() {
                const times = ref('')
                setTimeout(() => {
                    times.value = '2023-08-18 13:26:02'
                }, 1000)
                setTimeout(() => {
                    times.value = '2023-08-10 13:26:02'
                }, 5000)

                const formattedDate = computed(() => {
                    return dayjs(times.value).format('YYYY-MM-DD')
                })

                return {
                    formattedDate
                }
            }
        })

        app.mount('#app')
    </script>
</body>

</html>


引用chatgpt内容作答:
你的代码基本上是正确的,但是有一点小问题。你的自定义指令 v-demo 在 setup 函数中被调用了两次,但是只有在第一次调用时你设置了 times.value 的值。这就导致了指令只更新一次,因为在第二次调用时,times.value 的值没有改变。

解决方法是在每次指令调用时都更新 times.value 的值,这样指令就会每次都正确地显示新的日期。在你的例子中,可以在两个 setTimeout 回调函数中都更新 times.value。

以下是修复后的代码:

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title></title>
</head>

<body>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script src="https://unpkg.com/dayjs@1.8.21/dayjs.min.js"></script>
    <div id="app">
        <div v-demo>{{ times }}</div>
    </div>

    <script>
        const { createApp, ref } = Vue;

        const app = createApp({
            setup() {
                const times = ref('');
                setTimeout(() => {
                    times.value = '2023-08-18 13:26:02';
                }, 1000);
                setTimeout(() => {
                    times.value = '2023-08-10 13:26:02';
                }, 5000);
                return {
                    times
                };
            }
        });

        app.directive('demo', (el, binding) => {
            if (!el.textContent) return;
            el.textContent = dayjs(el.textContent).format('YYYY-MM-DD');
        });

        app.mount('#app');
    </script>
</body>

</html>

这样你的自定义指令就会在每次数据更新时都正确地格式化日期,并且你会看到两个不同的日期按预期显示在页面上。

 app.directive('demo', {
    mounted(el, binding) {
      const times = binding.value;
      if (!times) return;
      el.textContent = dayjs(times).format('YYYY-MM-DD');
    },
    updated(el, binding) {
      const times = binding.value;
      if (!times) return;
      el.textContent = dayjs(times).format('YYYY-MM-DD');
    }
  });

试试这个

Day.js 引入问题:你使用dayjs来格式化日期,但是脚本的顶部只引入了dayjs.min.js,并且没有引入dayjs的Vue插件。这可能导致dayjs在自定义指令中无法正常工作


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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title></title>
</head>

<body>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script src="https://unpkg.com/dayjs@1.8.21/dayjs.min.js"></script>
    <div id="app">
        <div v-demo>{{ times }}</div>
    </div>

    <script>
        const {
            createApp,
            ref
        } = Vue

        const app = createApp({
            setup() {
                const times = ref('')
                setTimeout(() => {
                    times.value = '2023-08-18 13:26:02'
                }, 1000)
                setTimeout(() => {
                    times.value = '2023-08-10 13:26:02'
                }, 5000)
                return {
                    times
                }
            }
        })

        app.directive('demo', {
            mounted: (el, binding) => {
                if (!el.textContent) return
                el.textContent = dayjs(el.textContent).format('YYYY-MM-DD')
            },
            updated: (el, binding) => {
                if (!el.textContent) return
                el.textContent = dayjs(el.textContent).format('YYYY-MM-DD')
            }
        })

        app.mount('#app')
    </script>
</body>

</html>


【以下回答由 GPT 生成】

这个问题是因为在Vue3中,自定义指令的更新时机和渲染周期有关,而延时指令的数据更新发生在下一个渲染周期而不是即时更新。因此,你可以使用Vue3的watchEffect函数来监听times的变化,并在变化时更新指令。以下是修改后的代码示例:

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title></title>
</head>

<body>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script src="https://unpkg.com/dayjs@1.8.21/dayjs.min.js"></script>
    <div id="app">
        <div v-demo>{{ times }}</div>
    </div>

    <script>
        const { createApp, ref, watchEffect } = Vue

        const app = createApp({
            setup() {
                const times = ref('')
                setTimeout(() => {
                    times.value = '2023-08-18 13:26:02'
                }, 1000)
                setTimeout(() => {
                    times.value = '2023-08-10 13:26:02'
                }, 5000)

                watchEffect(() => {
                    const el = document.querySelector('[v-demo]')
                    if (el) {
                        el.innerText = times.value
                    }
                })

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

</html>

这样,通过使用watchEffect函数,当times的值发生变化时,可以即时更新指令所在的元素的内容。运行修改后的代码,指令将在times值发生变化时更新。



【相关推荐】



如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title></title>
</head>

<body>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script src="https://unpkg.com/dayjs@1.8.21/dayjs.min.js"></script>
    <div id="app">
        <div v-demo>{{ times }}</div>
    </div>

    <script>
        const {
            createApp,
            ref
        } = Vue

        const app = createApp({
            setup() {
                const times = ref('')
                setTimeout(() => {
                    times.value = '2023-08-18 13:26:02'
                }, 1000)
                setTimeout(() => {
                    times.value = '2023-08-10 13:26:02'
                }, 5000)
                return {
                    times
                }
            }
        })
        app.directive('demo', {
            // 使用updated钩子函数来更新指令
            updated(el, binding) {
                console.log('==========el.textContent', el.textContent);
                if (!el.textContent) return
                el.textContent = dayjs(el.textContent).format('YYYY-MM-DD')
            }
        })
        app.mount('#app')
    </script>
</body>

</html>



Vue的数据频繁变化时但只会更新一次得原因

如果每次修改都触发视图更新,会导致多次重复和不必要的渲染操作。例如一个组件使用了两个data的属性,更新两个属性如果触发两次渲染的话,会影响性能。

原因:Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。