이 할일 목록을 Svelte의 즉시 검색과 결합하는 방법은 무엇입니까?

Nov 26 2020

tldr 버전에 대한 편집은 아래 코드에서 내가 매우 가깝다고 말하는 곳으로 스크롤 하십시오.

문제

완료되면 다음과 같은 특성이있는 기본 할 일 목록이 있습니다.

  1. 페이지가로드되면 양식 필드에 초점이 맞춰져야합니다.
  2. 사용자가 위 / 아래 화살표를 클릭하면 CSS 배경색 변경을 통해 목록의 항목을 선택해야합니다.
  3. 사용자가 양식에 새 항목을 입력하면 목록에 표시되어야합니다.
  4. 사용자가 양식 필드에 입력하면 "즉시 검색"이 목록에 적용되고 검색과 일치하는 항목 만 나타납니다. 다른 모든 기능은 계속 작동합니다. 사용자가 위 / 아래 화살표를 사용하여 스크롤하면 페이지에 표시되는 항목 수에 관계없이 계속 작동합니다. 두 개의 항목 만 표시되는 경우 사용자는 위 아래 화살표를 사용하여 두 항목을 선택하고 양식 필드 초점을 맞출 수 있어야합니다.

4 번을 제외한 모든 항목이 제대로 작동하는 것 같습니다. 다음 코드는 항목 1-3을 보여줍니다.

https://svelte.dev/repl/214b9c033d1c489e991484d387c267c2?version=3.30.0

<script>
    import { onMount } from 'svelte';
    let clients = ["a Little piggy","b little piggy","c little piggy"]; 
    let indexVal = -1;
    let downArrowPress = 40;
    let upArrowPress = 38;
    let clientInputTextField = "";
    let clientVal = "";
    onMount(function() {
        clientInputTextField.focus();
    });


    function handleKeydown(event) {
        if(event.keyCode === upArrowPress) {
            indexVal-=1;    
            indexVal = indexVal < 0 ?  clients.length : indexVal
            console.log(indexVal);
        }

        if(event.keyCode === downArrowPress) {
            indexVal+=1;
            indexVal = indexVal > clients.length ?  0 : indexVal
            console.log(indexVal);
        }

        if(indexVal > clients.length -1 || indexVal < 0){
            clientInputTextField.focus(); 
        } else {
            clientInputTextField.blur()
        }   
    }
    
    function handleSubmit(e) {
        const value = e.target.input.value;
        console.log(value);
        clients = [...clients, value];
        clientVal = "";
    }
</script>



<svelte:window on:keydown={handleKeydown}/>

<form on:submit|preventDefault={handleSubmit}>
    <input type="text" name="input" bind:this={clientInputTextField}  bind:value={clientVal} autocomplete="off">
    <input type="submit" name="">
</form>

<ul>
    {#each clients as client, i}
        {#if i === indexVal}
            <li style="background-color:orange">{client}</li>
            {:else}
            <li style="">{client}</li>
        {/if}
    {/each}
</ul>




<!-- 

function search(e){
    console.log(e.target.value)
    const searchString = e.target.value.toLowerCase();
    const filteredCharacters = clients.filter((character) => {
        return (
            character.toLowerCase().includes(searchString) ||
            character.toLowerCase().includes(searchString)
        );
    });
    
     console.log(filteredCharacters)
}
 -->

위의 코드를 즉시 검색 기능과 결합하고 싶습니다.

function search(e){
    console.log(e.target.value)
    const searchString = e.target.value.toLowerCase();
    const filteredCharacters = clients.filter((character) => {
        return (
            character.toLowerCase().includes(searchString) ||
            character.toLowerCase().includes(searchString)
        );
    });
    
     console.log(filteredCharacters)
}

지금까지 시도한 모든 것은 엉망이되고 목록을 반환하지 않고 입력 필드의 초점을 (onBlur) 해제합니다.

console.log 아래 코드는 사용자가 검색 할 때 원하는 것을 제공하는 배열입니다. 다음 단계는 DOM에 적용하는 것입니다. 지금까지 시도한 모든 것이 작동하지 않았습니다.

https://svelte.dev/repl/ceca685a3a4c49b4b5ccd780a101fc63?version=3.30.0

<script>
    import { onMount } from 'svelte';
    let clients = ["a Little piggy","b little piggy","c little piggy"]; 
    let indexVal = -1;
    let downArrowPress = 40;
    let upArrowPress = 38;
    let clientInputTextField = "";
    let clientVal = "";
    onMount(function() {
        clientInputTextField.focus();
    });


    function search(e){
    console.log(e.target.value)
    const searchString = e.target.value.toLowerCase();
    const filteredCharacters = clients.filter((character) => {
        return (
            character.toLowerCase().includes(searchString) ||
            character.toLowerCase().includes(searchString)
        );
    });
    
     console.log(filteredCharacters)
    
    }


    function handleKeydown(event) {
        if(event.keyCode === upArrowPress) {
            indexVal-=1;    
            indexVal = indexVal < 0 ?  clients.length : indexVal
            console.log(indexVal);
        }

        if(event.keyCode === downArrowPress) {
            indexVal+=1;
            indexVal = indexVal > clients.length ?  0 : indexVal
            console.log(indexVal);
        }

        if(indexVal > clients.length -1 || indexVal < 0){
            clientInputTextField.focus(); 
        } else {
            clientInputTextField.blur()
        }   
    }
    
    function handleSubmit(e) {
        const value = e.target.input.value;
        console.log(value);
        clients = [...clients, value];
        clientVal = "";
    }
</script>



<svelte:window on:keydown={handleKeydown}/>

<form on:submit|preventDefault={handleSubmit}>
    <input type="text" name="input" bind:this={clientInputTextField}  bind:value={clientVal} on:input={search} autocomplete="off">
    <input type="submit" name="">
</form>

<ul>
    {#each clients as client, i}
        {#if i === indexVal}
            <li style="background-color:orange">{client}</li>
            {:else}
            <li style="">{client}</li>
        {/if}
    {/each}
</ul>




<!-- 


 -->

편집하다

나는 아래 코드에서 매우 가깝습니다.

이 버전에서 유일한 문제는 사용자가 새 할 일을 제출할 때 목록이 DOM에 나타나지 않는다는 것입니다. 다른 모든 것이 작동합니다. 내가 의미하는 바를 보려면 입력 필드에 항목을 추가하고 제출 한 다음 양식 필드에 문자 a를 입력 한 다음 백 스페이스 버튼을 누르십시오. 목록이 다시 나타납니다.

https://svelte.dev/repl/f8fb733401eb4e27b9b8e54c688d355a?version=3.30.0

<script>
    import { onMount } from 'svelte';
    let clients = ["a Little piggy","b little piggy","c little piggy"]; 
    let clientsCopy = [...clients];
    let indexVal = -1;
    let downArrowPress = 40;
    let upArrowPress = 38;
    let clientInputTextField = "";
    let clientVal = "";
    onMount(function() {
        clientInputTextField.focus();
    });


    function search(e){
    console.log(e.target.value)
    const searchString = e.target.value.toLowerCase();
    const filteredCharacters = clients.filter((character) => {
        return (
            character.toLowerCase().includes(searchString) ||
            character.toLowerCase().includes(searchString)
        );
    });
    
     clientsCopy = [...filteredCharacters]
    
    }


    function handleKeydown(event) {
        if(event.keyCode === upArrowPress) {
            indexVal-=1;    
            indexVal = indexVal < 0 ?  clientsCopy.length : indexVal
            console.log(indexVal);
        }

        if(event.keyCode === downArrowPress) {
            indexVal+=1;
            indexVal = indexVal > clientsCopy.length ?  0 : indexVal
            console.log(indexVal);
        }

        if(indexVal > clientsCopy.length -1 || indexVal < 0){
            clientInputTextField.focus(); 
        } else {
            clientInputTextField.blur()
        }   
    }
    
    function handleSubmit(e) {
        const value = e.target.input.value;
        console.log(value);
        clients = [...clients, value];
        clientVal = "";
    }
</script>



<svelte:window on:keydown={handleKeydown}/>

<form on:submit|preventDefault={handleSubmit}>
    <input type="text" name="input" bind:this={clientInputTextField}  bind:value={clientVal} on:input={search} autocomplete="off">
    <input type="submit" name="">
</form>

<ul>
    {#each clientsCopy as client, i}
        {#if i === indexVal}
            <li style="background-color:orange">{client}</li>
            {:else}
            <li style="">{client}</li>
        {/if}
    {/each}
</ul>




<!-- 


 -->

답변

William Nov 26 2020 at 22:53

알았어. 클라이언트 배열의 복사본을 반응 배열로 설정했습니다. 바라건대 이것은 누군가를 도울 것입니다.

https://svelte.dev/repl/ad1c185bf97a47b98506c3603f510de6?version=3.30.0

<script>
    import { onMount } from 'svelte';
    let clients = ["a Little piggy","b little piggy","c little piggy"]; 
    $: clientsCopy = clients ;
    let indexVal = -1;
    let downArrowPress = 40;
    let upArrowPress = 38;
    let clientInputTextField = "";
    let clientVal = "";
    onMount(function() {
        clientInputTextField.focus();
    });


    function search(e){
    console.log(e.target.value)
    const searchString = e.target.value.toLowerCase();
    const filteredCharacters = clients.filter((character) => {
        return (
            character.toLowerCase().includes(searchString) ||
            character.toLowerCase().includes(searchString)
        );
    });
    
     clientsCopy = [...filteredCharacters]
    
    }


    function handleKeydown(event) {
        if(event.keyCode === upArrowPress) {
            indexVal-=1;    
            indexVal = indexVal < 0 ?  clientsCopy.length : indexVal
            console.log(indexVal);
        }

        if(event.keyCode === downArrowPress) {
            indexVal+=1;
            indexVal = indexVal > clientsCopy.length ?  0 : indexVal
            console.log(indexVal);
        }

        if(indexVal > clientsCopy.length -1 || indexVal < 0){
            clientInputTextField.focus(); 
        } else {
            clientInputTextField.blur()
        }   
    }
    
    function handleSubmit(e) {
        const value = e.target.input.value;
        console.log(value);
        clients = [...clients, value];
        clientVal = "";
    }
</script>



<svelte:window on:keydown={handleKeydown}/>

<form on:submit|preventDefault={handleSubmit}>
    <input type="text" name="input" bind:this={clientInputTextField}  bind:value={clientVal} on:input={search} autocomplete="off">
    <input type="submit" name="">
</form>

<ul>
    {#each clientsCopy as client, i}
        {#if i === indexVal}
            <li style="background-color:orange">{client}</li>
            {:else}
            <li style="">{client}</li>
        {/if}
    {/each}
</ul>




<!-- 


 -->
SamGomena Nov 27 2020 at 03:14

이것은 여기 의 요점 에서 찾은 코드를 기반으로 한 것보다 조금 더 간결한 버전입니다 . 그래도 솔루션과 실질적으로 동일합니다 (예 : 별도의 "필터링 된"목록을 만들고 표시)!

<script>
    import { onMount } from 'svelte';
    let clients = ["a Little piggy","b little piggy","c little piggy"]; 
    let indexVal = -1;
    let downArrowPress = 40;
    let upArrowPress = 38;
    let clientInputTextField = "";
    let clientVal = "";
    
        const startsWith = (item, query) => item.toLowerCase().indexOf(query.toLowerCase()) != -1;
        $: filteredClients = clientVal && clientVal.length ? clients.filter(item => startsWith(item, clientVal)) : clients;
    
        onMount(function() {
            clientInputTextField.focus();
        });


    function handleKeydown(event) {
    if(event.keyCode === upArrowPress) {
            indexVal-=1;    
            indexVal = indexVal < 0 ?  clients.length : indexVal
            console.log(indexVal);
    }

    if(event.keyCode === downArrowPress) {
            indexVal+=1;
            indexVal = indexVal > clients.length ?  0 : indexVal
            console.log(indexVal);
    }

    if(indexVal > clients.length -1 || indexVal < 0){
            clientInputTextField.focus(); 
    } else {
        clientInputTextField.blur()
    }   
  }
    
    function onChange(e) {
        console.log("what")
        const searchTerm = e.target.value.toLowerCase();
        console.log(searchTerm)
        clients = clients.filter(client => client.toLowerCase().includes(searchTerm))
    }
    
    function handleSubmit(e) {
        const value = e.target.input.value;
        console.log(value);
        clients = [...clients, value];
        clientVal = "";
    }
</script>



<svelte:window on:keydown={handleKeydown}/>

<form on:submit|preventDefault={handleSubmit}>
<!--     <input type="text" name="input" on:change={onChange} bind:this={clientInputTextField}  bind:value={clientVal} autocomplete="off"> -->
    <input type="text" name="input" bind:this={clientInputTextField}  bind:value={clientVal} autocomplete="off">
    <input type="submit" name="">
</form>

<ul>
    {#each filteredClients as client, i}
        {#if i === indexVal}
            <li style="background-color:orange">{client}</li>
            {:else}
            <li style="">{client}</li>
        {/if}
    {/each}
</ul>