实现效果
接下来, 我们会围绕组件的几个点展开讨论:
如何让父组件v-model起效 搜索框自动锁定焦点 监听键盘按下触发搜索 组件按字搜索且搜索结果高亮条件
技术点讲解:
1.由于父级监听输入框的值,所以当组件输入值变化的时候,需要把值广播给父级.
// search-components / html
input(
v-model="text"
)
// watch
/**
* 检测传入的文本
* @param {String} newValue 新值
*/
text (newValue) {
if (!this.searchOnEnter) {
this.$refs.input.blur()
// 监听键盘按下触发搜索
this.$emit('onSearch', newValue)
}
// 如何让父组件v-model起效
this.$emit('input', newValue)
}
搜索框自动锁定焦点实现思路有3种方式, 新页面通过mounted触发focus() / 通过$refs.input.focus()触发 / 通过自定义指令 v-focus触发 . 我们重点将用指令怎么实现. 首先在plugins写一个指令函数,其次在组件里面加上v-focus
// plugins/directive.js
/**
* 设置将元素获得焦点
*/
vue.directive('focus', function (el, {value}) {
if(value) {
el.focus()
}
})
-
搜索行为按字触发//使用的时候,监听input值,有变动触发延时一秒的请求 toSearch () { // 如果搜索框内有值 if (this.xxx) { setTimeout(() => { // 一秒内只执行一次 if (this.lastDelay - event.timeStamp === 0) { // TODO } }, 1000) } else { // 移除输入框和搜索列表的内容 this.removeInputValue() } }, -
搜索结果高亮条件实现的思路是前端拿到搜索结果后,遍历结果,找到关键词然后加上样式,最后用v-html渲染.
// let state.clientItem 用户搜索内容
if (state.clientItem) {
// 去除头尾空格
let inputItem = state.clientItem.trim()
.split(' ')
.filter(item => {
return item
})
.join('|')
let clientReg = new RegExp(inputItem, 'g')
let currentList = []
state.clientList.forEach(element => {
let unifiedCustName = element.unifiedCustName.replace(clientReg, function ($) {
return `<span style='color : #FA6F5B'>${$}</span>`
})}
}
全部代码
组件
<template lang="pug">
div._search(
:class="isShowCancel ? '_search-shadow' : ''"
)
div._search-input
i.iconfont.icon-search
input(
ref="input"
type="text"
placeholder="搜索"
v-model="text"
@focus="$emit('focus')"
@keyup.enter="$emit('onSearch', $event)"
@keydown="$emit('keydown')"
@blur="$emit('blur')"
)
i.iconfont.icon-close(
v-show="text"
@click="onClear"
)
span(v-show="isShowCancel" @click="searchCancel") 取消
</template>
<script>
export default {
name: 'SearchComponents',
props: {
// 查询默认值
placeholder: {
type: String,
default: '搜索'
},
// 是否显示取消
isShowCancel: {
type: Boolean,
default: false
},
// 自动锁定焦点
autoFocus: {
type: Boolean,
default: false
},
// 获取焦点
focus: {
type: Function,
default: () => {}
},
// 手指抬起
keyup: {
type: Function,
default: () => {}
},
// 手指按下
keydown: {
type: Function,
default: () => {}
},
// 失去焦点
blur: {
type: Function,
default: () => {}
},
// 关闭事件
onCancel: {
type: Function,
default: () => {}
},
// 查询事件
onSearch: {
type: Function,
default: () => {}
},
// enter 输入事件
searchOnEnter: {
type: Boolean,
default: true
}
},
data () {
return {
text: this.value
}
},
mounted () {
if (this.autoFocus) this.$refs.input.focus()
},
methods: {
searchCancel () {
this.$emit('input', '')
this.$emit('onCancel')
},
onClear () {
this.text = ''
}
},
watch: {
text (newValue) {
if (!this.searchOnEnter) {
this.$refs.input.blur()
this.$emit('onSearch', newValue)
}
this.$emit('input', newValue)
},
value (newValue) {
this.text = newValue
}
}
}
</script>
<style lang="stylus" scoped>
._search
position relative
height 5rem
flex-shrink 0
display flex
align-items center
justify-content space-between
padding 1rem 1.5rem
box-sizing border-box
._search-shadow
box-shadow 0 .2rem 1rem 0 rgba(0, 0, 0, .05)
span
font-size 1.5rem
color #333333
margin-left 1.5rem
._search-input
height 100%
width 100%
background-color #fafafa
border-radius 5rem
display flex
flex 1
align-items center
i
font-size 1.3rem
color #333333
margin-left .5rem
margin-right .6rem
.icon-close
font-size 1.8rem
color #dddddd
input
outline none
border none
background-color transparent
font-size 1.4rem
width 100%
height 100%
input::-webkit-input-placeholder
color #cccccc
</style>
使用组件
<template lang="pug">
//- 分页在mutation,页数1清空,其他就push.
.use-search
common-search(
v-model="searchStr"
:is-show-cancel="showMode"
@focus="toSearch"
@onCancel="showMode=false"
@onSearch="onSearch"
)
//- 内容
.content
span(v-html="item.materName)
</template>
<script>
import CommonSearch from '~/components/SearchComponents'
export default {
components: {
CommonSearch
},
data () {
return {
// 搜索内容
searchStr: '',
// search_switch
showMode: true
}
},
methods: {
// search_点击input框触发
toSearch () {
// 如果搜索框内有值
if (this.xxx) {
setTimeout(() => {
// 一秒内只执行一次
if (this.lastDelay - event.timeStamp === 0) {
// TODO
}
}, 1000)
} else {
// 移除输入框和搜索列表的内容
this.removeInputValue()
}
},
// search_键盘enter时候触发
onSearch () {
},
// 取消搜索
onCancel () {
}
}
}
</script>