#vue.js #vuejs3
#vue.js #vuejs3
Вопрос:
Цель
Я хочу отфильтровать источник данных, используемый в цикле for, на основе ввода строки поиска.
Пример
У меня есть источник данных [{ title: «Title1» }, { title: «Title2» }]. Я ввожу «Title1» в свою строку поиска. Я только хочу, чтобы отфильтрованный источник данных for-цикла отображал объект с «Title1».
Проблема
Метод searchInputChange(…), похоже, работает, и источник данных this.filteredPosts, похоже, изменяется правильно. Однако источник данных, похоже, не обновляется в шаблоне HTML. Он всегда содержит оба объекта.
Home.vue
<template>
<Searchfield @searchInputChange="searchInputChange" />
<div v-for="post in filteredPosts" :key="post.id">
{{ post.title }}
</div>
</template>
<script>
import { ref } from 'vue'
import Searchfield from '../components/Searchfield.vue'
export default {
name: 'Home',
components: { Searchfield },
setup() {
let filteredPosts = ref([])
let allPosts = [
{
"id": 1,
"title": "Title1",
},
{
"id": 2,
"title": "Title2",
}
]
filteredPosts.value = [...allPosts]
return { allPosts, filteredPosts }
},
methods: {
searchInputChange(value) {
const filterPosts = this.allPosts.filter(post => post.title.toLowerCase().includes(value.toLowerCase()));
this.filteredPosts.value = [...filterPosts]
}
}
}
</script>
Searchfield.vue
<template>
<input type="text" @change="searchInputChange" placeholder="Search...">
</template>
<script>
export default {
name: 'Searchfield',
setup(props, context) {
const searchInputChange = (event) => {
context.emit('searchInputChange', event.target.value)
}
return { searchInputChange }
}
}
</script>
Спасибо!
Ответ №1:
При использовании ref внутри setup
вам нужно изменить его значение (или прочитать значение) с помощью value
свойства, чтобы все присвоения (внутри setup
) filteredPosts
должны выглядеть следующим образом filteredPosts.value = ....
За пределами setup
(скажем, в methods
), filteredPosts
это обычное реактивное свойство реактивного объекта (экземпляра компонента) и .value
не требуется (и его использование является ошибкой)
Все это довольно запутанно и является одной из причин, по которой не рекомендуется смешивать Composition API и Options API — просто используйте один или другой.
В вашем случае filteredPosts
это может быть просто computed
, без необходимости переназначать его вручную каждый раз при изменении входных данных…
const app = Vue.createApp({
setup(){
const searchTerm = Vue.ref('')
let allPosts = [
{
"id": 1,
"title": "Title1",
},
{
"id": 2,
"title": "Title2",
}
]
const filteredPosts = Vue.computed(() => allPosts.filter(post => post.title.toLowerCase().includes(searchTerm.value.toLowerCase())) )
return {
searchTerm,
filteredPosts
}
},
})
app.component('Searchfield', {
props: ['modelValue'],
emits: ['update:modelValue'],
setup(props, { emit }) {
const model = Vue.computed({
get: () => props.modelValue,
set: (newValue) => emit('update:modelValue', newValue)
})
return { model }
},
template: `<input type="text" v-model="model" placeholder="Search...">`
})
app.mount('#app')
<script src="https://unpkg.com/vue@3.2.23/dist/vue.global.js"></script>
<div id='app'>
<searchfield v-model="searchTerm"></searchfield>
<div v-for="post in filteredPosts" :key="post.id">
{{ post.title }}
</div>
</div>
Комментарии:
1. Это работает! Отличный пример. Спасибо.