admin管理员组文章数量:1357696
Maybe its not related to svelte, but if do some DOM changes after input is focused, for example
<input onfocus={() => toggleVisibiltyOfOtherElement = true } onblur={() => console.log("blur")} />
(toggleVisibiltyOfOtherElement
triggers dom changes)
then blur is also triggered. Which doesn't make any sense, since visually the input is still focused. This makes it impossible to show another element only when input is focused, because showing that element unfocuses the input
Any way to fix this?
app.svelte
<script>
import Component from "./Component.svelte"
let s = $state("");
let sFiler = $state();
let showBox = $state(false);
</script>
<input bind:this={sFilter} type="text" bind:value={s} placeholder="search..."
onfocus={() => showBox = true }
onblur={() => showBox = false }
/>
<Component bind:visible={showBox}>
box content
</Component>
component.svelte
<script>
import { clickoutside } from "./onclickoutside.svelte";
let { visible = $bindable(), children } = $props()
</script>
{#if visible}
<div use:clickoutside onclickoutside={() => visible = false}>
{@render children()}
</div>
{/if}
<style>
div{
position: fixed;
background: pink;
left: 0;
top: 40px;
width: 500px;
height: 200px;
}
</style>
onclickoutside.svelte.js
export const clickoutside = (node, ignore) => {
function listener(event) {
const target = event.target;
if (!event.target || (ignore && target.closest(ignore))) {
return;
}
if (node && !node.contains(target) && !event.defaultPrevented) {
node.dispatchEvent(new CustomEvent("clickoutside", { detail: { target } }))
}
}
document.addEventListener("click", listener, true)
return {
destroy() {
document.removeEventListener("click", listener, true)
}
}
}
Maybe its not related to svelte, but if do some DOM changes after input is focused, for example
<input onfocus={() => toggleVisibiltyOfOtherElement = true } onblur={() => console.log("blur")} />
(toggleVisibiltyOfOtherElement
triggers dom changes)
then blur is also triggered. Which doesn't make any sense, since visually the input is still focused. This makes it impossible to show another element only when input is focused, because showing that element unfocuses the input
Any way to fix this?
app.svelte
<script>
import Component from "./Component.svelte"
let s = $state("");
let sFiler = $state();
let showBox = $state(false);
</script>
<input bind:this={sFilter} type="text" bind:value={s} placeholder="search..."
onfocus={() => showBox = true }
onblur={() => showBox = false }
/>
<Component bind:visible={showBox}>
box content
</Component>
component.svelte
<script>
import { clickoutside } from "./onclickoutside.svelte";
let { visible = $bindable(), children } = $props()
</script>
{#if visible}
<div use:clickoutside onclickoutside={() => visible = false}>
{@render children()}
</div>
{/if}
<style>
div{
position: fixed;
background: pink;
left: 0;
top: 40px;
width: 500px;
height: 200px;
}
</style>
onclickoutside.svelte.js
export const clickoutside = (node, ignore) => {
function listener(event) {
const target = event.target;
if (!event.target || (ignore && target.closest(ignore))) {
return;
}
if (node && !node.contains(target) && !event.defaultPrevented) {
node.dispatchEvent(new CustomEvent("clickoutside", { detail: { target } }))
}
}
document.addEventListener("click", listener, true)
return {
destroy() {
document.removeEventListener("click", listener, true)
}
}
}
Share
Improve this question
edited Mar 28 at 17:18
Alex
asked Mar 28 at 15:42
AlexAlex
66.1k185 gold badges459 silver badges651 bronze badges
1
- Please provide a complete, minimal reproduction. – brunnerh Commented Mar 28 at 16:42
2 Answers
Reset to default 1blur
is not triggered.
The logic works as expected if focus is moved via tab, but if you click on the input, focus triggers on mouse-down, and a click is emitted on mouse-up which immediately causes the click outside logic to set the flag back to false.
You could for example add special handling for the input or move the boundary for click-outside higher up in the tree so it considers both the input and the content to show to be inside.
Now with the code you can see that the problem is what Brunnerh gives in his answer, the mouseup
after focus
triggers the clickoutside
custom event and hides the box. The easiest solution is to simply use onclick
instead of onfocus
:
<script>
import Component from "./Component.svelte"
let s = $state("");
let sFiler = $state();
let showBox = $state(false);
</script>
<input bind:this={sFilter} type="text" bind:value={s} placeholder="search..."
onclick={() => showBox = true }
onblur={() => showBox = false }
/>
<Component bind:visible={showBox}>
box content
</Component>
Keep in mind that if a user for some reason presses the mouse inside the input, then drags out of it and then releases the mouse, the click action is never triggered and the box won't show up. That's a very unexpected behavior but you can get around it by doing the following:
//App.svelte
<script>
import Component from "./Component.svelte"
let s = $state("");
let sFiler = $state();
let showBox = $state(false);
let inputMouseDown = $state(false)
function revealBox() {
if (!inputMouseDown) return
showBox = true
inputMouseDown = false;
}
</script>
<input bind:this={sFilter} type="text" bind:value={s} placeholder="search..."
onmousedown={() => inputMouseDown = true}
ontouchstart={() => inputMouseDown = true}
onblur={() => showBox = false }
/>
<svelte:window onmouseup={revealBox} ontouchend={revealBox}/>
<Component bind:visible={showBox} {inputMouseDown}>
box content
</Component>
//Component.svelte
<script>
import { clickoutside } from "./onclickoutside.svelte";
let { visible = $bindable(), inputMouseDown, children } = $props()
function hideBox() {
if (inputMousedown) return
visible = false
}
</script>
{#if visible}
<div use:clickoutside onclickoutside={hideBox}>
{@render children()}
</div>
{/if}
<style>
div{
position: fixed;
background: pink;
left: 0;
top: 40px;
width: 500px;
height: 200px;
}
</style>
Also added touch support. Here's a working REPL.
本文标签: javascriptSvelte input blur triggered when element is focusedStack Overflow
版权声明:本文标题:javascript - Svelte input blur triggered when element is focused - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744027724a2578342.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论