# 如何实现一个高亮关键字的搜索框

正常思路是通过正则匹配改变关键字为标签,这里涉及到了防抖、正则和中文输入法的问题。

# 防抖

防抖是避免在同一时间执行多次相同函数。(在一段时间内多次执行了同一函数,以最后一次请求的参数执行function)

function debounce(func, wait = 300) {
    var timeout;
    return function () {
        let context = this;
        let args = arguments;
        if(timeout) clearTimeout(timeout)
        timeout = setTimeout(function() {
            func.apply(context, args);
        }, wait);
    }
}

# 中文输入法

<input @input="input" type="text"/>

以上是一个input根据修改执行搜索的正常写法。但是这样写有个问题,输入中文期间也会去执行input,输入中文会建立一个虚拟文本,最好是等用户确认之后再执行input

# 引入3个方法

  • compositionStart: 用户切换中文输入法打拼音时会触发
  • compositionUpdate: 输入拼音字母会触发
  • compositionEnd: 最后将输入好的中文填入input中时触发

这3个方法是针对中文输入的,修改上面的页面内容

<input @compositionstart="compositionstart" @compositionend="compositionend" @input="input"/>

需要设置一个 bool 判断是不是正在输入值,避免输中文的时候也会调用 input

export default {
    data() {
        return {
            list: [],
            keyword: '',
            isZh: false
        }
    },
    methods: {
        input(){
            // input执行顺序不可控 setTimeout改变队列顺序
            setTimeout(() => {
                if(this.isZh) return;
                console.log('input');
            }, 0)
        },

        compositionend() {
            this.isZh = false;
            console.log('compositionend');
        },
        compositionstart() {
            this.isZh = true;
            console.log('compositionstart');
        }
    }
}

# 正则

通过正则修改返回的内容把关键字替换成标签返回。

export default {
    data() {
        return {
            list: [],
            keyword: '',
            isZh: false
        }
    },
    methods: {
        input: debounce(function(){
            if(this.isZh) return;
                this.axios.get('/api').then(res => { // 模拟接口
                    this.list = res.data;
                })
            console.log('input');
        }, 300),

        compositionend() {
            this.isZh = false;
            console.log('compositionend');
        },
        compositionstart() {
            this.isZh = true;
            console.log('compositionstart');
        }
    },
    computed: {
        convertList() { // 返回转换后的数组
            let {keyword} = this;
            let reg = new RegExp(`${keyword}`);
            return this.list.map(item => {
                return item.replace(reg, `<b style="color: green;">${keyword}</b>`);
            })
        }
    }
}
<div>
    <input type="text" @compositionend="compositionend" @compositionstart="compositionstart" @onpaste="onpaste" @input="input" v-model="keyword">
    <div v-for="item in convertList" v-html="item" :key="item"></div>
    </div>