我有一个搜索字段,我想根据它过滤用户。
我向用户显示是否没有过滤器,或者如果您搜索任何内容,则显示filteredUsers
。
问题在于,如果您在搜索栏中进行搜索,然后我尝试编辑一个字段(内联编辑),则会users
被更新,而filteredUsers
不会被更新。
我还有其他过滤器和操作,这就是为什么我只发布了那部分代码。我必须同时使用它们,因为在其他情况下,我需要用户。
在vue.js
中如何工作?
//in componnet
computed: {
...mapGetters([
'users',
'filteredUsers'
]),
getFilteredUsers () {
return this.filteredUsers || this.users
}
}
// in mutation
UPDATE_CONSUMER (state, { user, index }) {
// here users is updated, but filteredUsers in not
state.users.splice(index, 1, user)
},
<tr v-for="user, index in getFilteredUsers">
// getters.js file
export default {
users: state => {
return state.users
},
filteredUsers: state => {
return state.filteredUsers
}
}
// mutations.js
SEARCH_USERS (state) {
const searchTextTrimmed = state.searchText.trimStart()
const users = [
...state.users.filter(user => {
return user.name.toLowerCase().startsWith(searchTextTrimmed.toLowerCase())
})
]
if (searchTextTrimmed) {
state.filteredUser = users
} else {
state.users = users
state.filteredUser = null
}
}
答案 0 :(得分:1)
理想情况下,state
中不会同时包含两个数组。相反,您只有users
和searchText
。然后,您将在filteredUsers
和getters
派生的users
中有searchText
。
在下面的示例中,我尝试保留问题中的UPDATE_CONSUMER
突变。我从那里推断,假设您要在编辑用户对象时创建它们的副本,而不是变异原始对象。如果可以更改原始对象,因为这两个对象在两个列表之间共享,那么整个问题将变得毫无意义。
const store = new Vuex.Store({
state: {
searchText: '',
users: [
{name: 'Black', fruit: 'Apple'},
{name: 'Blue', fruit: 'Pear'},
{name: 'Brown', fruit: 'Banana'}
]
},
mutations: {
UPDATE_CONSUMER (state, { user, index }) {
state.users.splice(index, 1, user)
},
UPDATE_SEARCH_TEXT (state, searchText) {
state.searchText = searchText
}
},
getters: {
filteredUsers (state) {
const searchText = state.searchText.trimStart().toLowerCase()
const users = state.users
if (!searchText) {
return users
}
return users.filter(user => user.name.toLowerCase().startsWith(searchText))
}
}
})
new Vue({
el: '#app',
store,
computed: {
...Vuex.mapState(['users']),
...Vuex.mapGetters(['filteredUsers']),
searchText: {
get () {
return this.$store.state.searchText
},
set (searchText) {
this.$store.commit('UPDATE_SEARCH_TEXT', searchText)
}
}
},
methods: {
onInputFruit (user, fruit) {
const newUser = {...user, fruit}
const index = this.users.indexOf(user)
this.$store.commit('UPDATE_CONSUMER', {user: newUser, index})
}
}
})
#app > * {
margin: 0 0 10px;
}
table {
border-collapse: collapse;
}
td, th {
background: #eee;
border: 1px solid #777;
padding: 5px;
}
<script src="https://unpkg.com/vue@2.6.10/dist/vue.js"></script>
<script src="https://unpkg.com/vuex@3.1.1/dist/vuex.js"></script>
<div id="app">
<input v-model="searchText">
<table>
<tr><th>Name</th><th>Fruit</th><tr>
<tr v-for="user in filteredUsers" :key="user.name">
<td>{{ user.name }}</td>
<td>
<input :value="user.fruit" @input="onInputFruit(user, $event.target.value)">
</td>
</tr>
</table>
<p>{{ filteredUsers }}</p>
<p>{{ users }}</p>
</div>
其他一些注意事项:
users
的使用方法,而是使用了mapState
。如果您希望通过mapGetters
进行所有操作,则可以将其恢复原样。getFilteredUsers
。而是让filteredUsers
始终返回符合搜索条件的当前用户列表。我提供了一种优化措施,如果没有searchText
,它会尽早返回,但是如果没有它,它仍然可以工作。const users = [...state.users.filter
。无需使用[...]
在此处创建新数组,因为filter
仍将返回新数组。searchText
和过滤保留在存储中,但是感觉有点像应该由组件状态来处理。在不了解您的应用程序的情况下很难说,但是搜索框可能只存在于UI的一小部分,并且不一定需要通过商店与其他应用程序共享。我实现此方法的一个潜在问题是,随着用户键入数据会立即更新。在我的示例中,这不是问题,但是如果根据正在编辑的字段过滤列表,则可能导致该行在用户键入时突然消失。避免该问题的一种方法是在更新数据之前等待场模糊,例如使用change
事件而不是input
事件。可以使用其他变通办法,具体取决于预期的行为。