vue3组件实现v-model双向绑定
实现一个基本的双向绑定
比如我们要实现一个search-input组件,在父组件中是这要调用的:
<template>
<div class="search-input-wrapper">
<search-input v-model="query"></search-input>
</div>
</template>
<script type="text/ecmascript-6">
import SearchInput from '@/components/search/search-input'
import { ref, watch } from 'vue'
export default {
name: 'search',
components: {
SearchInput
},
setup() {
const query = ref('')
// 用于检测双向绑定是否成功
watch(query, (val) => {
console.log(val)
})
return {
query
}
}
}
</script>
在search-input组件内部,则应按照以下规范:
<template>
<div class="search-input">
<input type="text"
class="input-inner"
v-model="query"
>
</div>
</template>
<script type="text/ecmascript-6">
export default {
name: 'search-input',
props: {
// 此组件也用v-model双向绑定的固定写法
modelValue: String
},
data() {
return {
query: this.modelValue
}
},
watch: {
// 此组件也用v-model双向绑定的固定写法
query(newQuery) {
this.$emit('update:modelValue', newQuery.trim())
}
}
}
</script>
在组件内部,v-model不能直接绑定props的值,子组件不能修改父组件传过来的值,只能修改自己组件data中的值,然后再watch,之后向父元素派发事件。
添加input节流等优化
直接上修改后的代码
<template>
<div class="search-input">
<i class="icon-search"></i>
<input type="text"
class="input-inner"
v-model="query"
>
<i class="icon-dismiss"
v-show="query"
@click="clear"
alt="清空input中的内容"
></i>
</div>
</template>
<script type="text/ecmascript-6">
import { debounce } from 'throttle-debounce'
export default {
name: 'search-input',
props: {
// 此组件也用v-model双向绑定的固定写法
modelValue: String
},
data() {
return {
query: this.modelValue
}
},
created() {
// 在watch中,无法执行debounce,所以在created中使用this.$watch来监听
// debounce(每隔多少毫秒, 执行的回调)
// 使用debounce之后,只是派发最后一次输入的值 进行节流
this.$watch('query', debounce(300, (newQuery) => {
this.$emit('update:modelValue', newQuery.trim())
}))
// 当是通过父组件修改值的时候,去修改本组件的query值
// 所以需要观测外部modelValue值的变化,当外部值变化时候更新query
this.$watch('modelValue', (newVal) => {
this.query = newVal
})
},
methods: {
clear() {
this.query = ''
}
}
}
</script>
主要修改的地方有两点:
1、使用throttle-debounce插件,为input输入增加节流功能,只保留最后一次的输入结果。
https://www.npmjs.com/package/throttle-debounce
https://github.com/niksy/throttle-debounce#readme
介绍:https://www.jianshu.com/p/a1a9003153b0
2、修改了原来的watch,在created()中使用this.$watch,并在回调函数中使用debounce函数
3、增加watch-modelValue的值,这样,当值在父组件中被修改的时候,可以监听,并且修改子组件中的query值。
至此,才算真正实现了双向绑定
如果要在父元素中修改search-input的query值:
<search-input v-model="query"></search-input>
const query = ref('')
query.value = 'xxxx'
return {
query
}