当NewValue是相同的字符串时,如何解雇观察者?

发布于 2025-02-04 08:39:22 字数 1283 浏览 4 评论 0 原文

I'm inserting base64 images into an editor by assigning their base64 string to reactive object state.image and pointing a watcher at it.问题是,当我想两次插入相同的图像时,观察者不会发射。

Watcher

const renderImage = (editor) => {
    const unwatch = watch(() => state.image, () => {
        console.log('watcher fires!')
        editor.chain().focus().setImage({ src: state.image }).run()
        unwatch()
        state.image = null
    })
}

您可以看到我试图用 untatch()杀死观察者,并另外set set state.image = null ,但加载相同的图像时仍不会发射。

@click 事件在此元素中触发:

<button  @click="$refs.image.click(); renderImage(editor)"></button>

<input type="file" ref="image" style="display: none" @change="getImageUrl">

图像的 dataUrl 均在 getimageurl 中创建:

const getImageUrl = (event) => {
    const files = event.target.files;
    if (!files.length)
        return;
    const reader = new FileReader();
    reader.onload = (event) => {
        state.image = event.target.result;
    };
    reader.readAsDataURL(files[0]);
}

这两个元素似乎都可以根据需要工作。

我该如何使观察者开火?

I'm inserting base64 images into an editor by assigning their base64 string to reactive object state.image and pointing a watcher at it. Problem is that when I want to insert the same image twice, the watcher doesn't fire.

watcher:

const renderImage = (editor) => {
    const unwatch = watch(() => state.image, () => {
        console.log('watcher fires!')
        editor.chain().focus().setImage({ src: state.image }).run()
        unwatch()
        state.image = null
    })
}

As you can see I'm trying to kill the watcher with unwatch() and in addition set state.image = null but it still doesn't fire when the same image is loaded.

The @click event is triggered in this element:

<button  @click="$refs.image.click(); renderImage(editor)"></button>

<input type="file" ref="image" style="display: none" @change="getImageUrl">

and the dataUrl of the image is created in getImageUrl:

const getImageUrl = (event) => {
    const files = event.target.files;
    if (!files.length)
        return;
    const reader = new FileReader();
    reader.onload = (event) => {
        state.image = event.target.result;
    };
    reader.readAsDataURL(files[0]);
}

Both elements seem to work as desired.

How do I make the watcher fire?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

惟欲睡 2025-02-11 08:39:22

这个问题假设观看回调不是发射的,但是在这种情况下,实际上是&lt; input&gt; 没有发射事件。

&lt; input&gt; 仅触发更改/输入事件的值实际上更改。选择同一文件时,该值没有更改,因此没有更改 -event发生 getimageurl()处理程序,该处理程序将触发观察文件加载时。

要解决问题,请重置&lt; input&gt; 的值,在复制所选文件的路径之后:

⋮
const image = ref() // template ref on input

const getImageUrl = (event) => {
    const files = event.target.files;
    if (!files.length)
        return;

    const fileToRead = files[0]; // 1️⃣ copy input's value
    image.value.value = null;    // 2️⃣ and reset the input
  
    const reader = new FileReader();
    reader.onload = (event) => {
        state.image = event.target.result;
    };
    reader.readAsDataURL(fileToRead);
}

demo 1

次要重构

renderimage()实际上只是在使用观看基本上创建一个 fileReader 's load 事件的异步回调。似乎可以通过将图像渲染代码直接移动到 load -event处理程序中来简化这可以简化这一点:

const getImageUrl = (event) => {
const files = event.target.files;
if (!files.length)
return;

const fileToRead = files[0];
image.value.value = null;

const reader = new FileReader();
reader.onload = (event) => {
//

The question assumes the watch callback isn't firing, but in this case, it's actually the <input> that isn't firing its event.

The <input> only fires the change/input event when its value actually changes. When selecting the same file, the value hasn't changed, and thus no change-event occurs to call the getImageUrl() handler, which would've triggered the watch when the file gets loaded.

To resolve the issue, reset the <input>'s value after copying the selected file's path:

⋮
const image = ref() // template ref on input

const getImageUrl = (event) => {
    const files = event.target.files;
    if (!files.length)
        return;

    const fileToRead = files[0]; // 1️⃣ copy input's value
    image.value.value = null;    // 2️⃣ and reset the input
  
    const reader = new FileReader();
    reader.onload = (event) => {
        state.image = event.target.result;
    };
    reader.readAsDataURL(fileToRead);
}

demo 1

Minor refactoring

renderImage() is actually just using watch to essentially create an async callback for FileReader's load event. It seems this could be simplified by moving the image rendering code into that load-event handler directly:

const getImageUrl = (event) => {
    const files = event.target.files;
    if (!files.length)
        return;

    const fileToRead = files[0];
    image.value.value = null;

    const reader = new FileReader();
    reader.onload = (event) => {
        // ???? render image
        editor.chain().focus().setImage({ src: event.target.result }).run();
    };
    reader.onerror = reject;
    reader.readAsDataURL(fileToRead);
}

Then you could remove renderImage():

<!-- <button @click="$refs.image.click(); renderImage(editor)"></button> --> <!-- no longer needed -->

<button @click="$refs.image.click()"></button>

...and also state.image:

const state = reactive({
  // image: '' // no longer needed
})

demo 2

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文