admin管理员组

文章数量:1335623

I have a search ponent in Vue.js. When you type into the text input, a list of search results is fetched from the server, then displayed in a list beneath the search field. When you click one of the results, the submit event fires.

However, now I tried adding a blur event to the text input, which should hide the list of results when the user clicks away from the input. This works fine, except for one crucial situation - clicking on a result no longer fires the submit event.

I understand why this is - the blur event apparently fires before the click event, and hides the results list before the click can be registered on one of the results. My question is, how do I get around this? I need the results list to close when clicking outside the text input, but I obviously also need the submit method to function.

Here is the ponent in full:

<template>
    <div class="search basic-search">
        <input type="text" v-model="search_string" v-on:keyup="search" v-on:focus="activate" v-on:blur="inactivate" class="form-control search" placeholder="Search stocks" />
        <div :class="['search-results', active === true ? 'active' : '']">
            <div class="search-result" v-for="result in search_results" v-on:click="submit(result.id)">
                {{ result.name }} ({{ result.ticker }})
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        data: function() {
            return {
                search_string : '',
                search_results : [],
                active : false
            };
        },

        methods : {
            search : function() {
                const axios_data = {
                    _token  : $('meta[name="csrf-token"]').attr('content'),
                    str : this.search_string
                };

                axios.post('/stock-search', axios_data).then(response => {

                    if(response.data.success){
                        this.search_results = response.data.stocks;
                        this.active = true;
                    }

                });
            },

            activate : function() {
                if(this.search_string !== '')
                    this.active = true;
            },

            inactivate : function() {
                this.active = false;
            },

            submit : function(stock_id) {
                document.location = "/graphs/" + stock_id;
            }
        }
    }
</script>

I have a search ponent in Vue.js. When you type into the text input, a list of search results is fetched from the server, then displayed in a list beneath the search field. When you click one of the results, the submit event fires.

However, now I tried adding a blur event to the text input, which should hide the list of results when the user clicks away from the input. This works fine, except for one crucial situation - clicking on a result no longer fires the submit event.

I understand why this is - the blur event apparently fires before the click event, and hides the results list before the click can be registered on one of the results. My question is, how do I get around this? I need the results list to close when clicking outside the text input, but I obviously also need the submit method to function.

Here is the ponent in full:

<template>
    <div class="search basic-search">
        <input type="text" v-model="search_string" v-on:keyup="search" v-on:focus="activate" v-on:blur="inactivate" class="form-control search" placeholder="Search stocks" />
        <div :class="['search-results', active === true ? 'active' : '']">
            <div class="search-result" v-for="result in search_results" v-on:click="submit(result.id)">
                {{ result.name }} ({{ result.ticker }})
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        data: function() {
            return {
                search_string : '',
                search_results : [],
                active : false
            };
        },

        methods : {
            search : function() {
                const axios_data = {
                    _token  : $('meta[name="csrf-token"]').attr('content'),
                    str : this.search_string
                };

                axios.post('/stock-search', axios_data).then(response => {

                    if(response.data.success){
                        this.search_results = response.data.stocks;
                        this.active = true;
                    }

                });
            },

            activate : function() {
                if(this.search_string !== '')
                    this.active = true;
            },

            inactivate : function() {
                this.active = false;
            },

            submit : function(stock_id) {
                document.location = "/graphs/" + stock_id;
            }
        }
    }
</script>
Share Improve this question asked Apr 10, 2020 at 9:29 sveti petarsveti petar 3,79714 gold badges77 silver badges158 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 6

You could delay the hiding of the box until click fires

inactivate : function() {
   setTimeout( () => this.active = false, 100)
},

You may also try to use mousedown instead of click

<div class="search-result" v-for="result in search_results" v-on:mousedown="submit(result.id)">

I don't know if the order of the events is determined, but mousedown should be triggered before blur.

I had the same problem but instead of click I was doing they "enter". So the solution for Vue is:

@keydown.enter="selectPreselectedOption"

Which triggers before the blur on my input (which also triggers on enter, but keyup)

I was able to solve this issue by adding v-on:mousedown.prevent like this

<div :class="['search-results', active === true ? 'active' : '']">
    <div 
        class="search-result" 
        v-for="result in search_results" 
        v-on:click="submit(result.id)"
        v-on:mousedown.prevent
    >
        {{ result.name }} ({{ result.ticker }})
    </div>
</div>

This prevents the click from propagating up to the parent with v-on:blur. With this solution you'd still need call inactivate manually in function submit.

本文标签: javascriptBlur event cancels click event in Vue componentStack Overflow