如何在vue中实现自更新排序
how to achieve a selfupdating sort in vue
我有一个 vuex-store game
,其中包含一个数组 players
。
每个 player
都有一个 id
、name
和一个 score
。
我现在有一个组件 scoreboard
,它应该按分数列出所有玩家。
为了对玩家进行排序,我在我的组件中添加了一个计算 属性。
当我现在在应用程序中的某处更新玩家分数时,我计算的 属性 不会被触发。我知道它没有被触发,因为数组本身没有改变。我需要调用 push/pop/shift/anything 来改变数组。
解决这个问题的常用方法是什么?当我更新它的一些属性时,我是否也应该改变数组?由于呈现 player.points
的组件已经成功更新,这看起来很脏。
有没有办法将更多 listeners 添加到计算的 属性?
我的组件:
<template>
<div class="scoreboard">
<strong>Scoreboard</strong>
<div class="scores">
<score-board-entry v-for="player in sortedPlayers" :key="player.id" :player="player"></score-board-entry>
</div>
</div>
</template>
<script>
import _ from 'lodash'
import ScoreBoardEntry from './ScoreBoardEntry.vue'
export default {
props: ['players'],
data () {
return { }
},
components: { ScoreBoardEntry },
computed: {
sortedPlayers () {
return _.sortBy(this.players, 'score')
}
}
}
</script>
<style scoped>
</style>
我的店铺:
const initialState: state = {
id: '',
players: []
}
const game = {
namespaced: true,
state: initialState,
mutations: {
addPoints (state: state, payload: addPointsPayload) {
const player = state.players.find((p) => p.id === payload.id)
player.points = player.points + payload.points
}
...
如果不了解您如何使用记分板组件,很难说出为什么它没有更新。
无论如何,如果您要删除 scoreBoard 组件中的 属性 球员,并使用带有 mapState 或 mapGetters 的 Vuex 状态球员,它会在您更改球员数据时立即自动更新您的棋盘。
我在创建下面的演示过程中发现的另一点是您按分数排序,但我认为它应该是分数。因为您的状态中没有得分 属性 或得分计算不在您的代码段中。
请查看下面的演示或此 fiddle。
而且我认为您的 loadash 排序没问题。我刚刚把结果倒过来,把最高分放在第一位。
在您的 addPoints
突变方法中,我更改为 shorthand +=
因为我认为这样更容易阅读 - 您的版本在这里也可以。
mapState 或 mapMutations 演示中的注释代码与映射器的作用相同,保留在那里以了解映射器在做什么。
const initialState = {
id: '',
players: [{
id: 0,
name: 'first',
points: 20
}, {
id: 1,
name: 'second',
points: 10
}, {
id: 2,
name: 'third player',
points: 35
}]
};
const game = {
namespaced: true,
state: initialState,
mutations: {
addPoints(state, payload) {
const player = state.players.find((p) => p.id === parseInt(payload.id));
//console.log('addpoints', payload, player);
player.points += payload.points;
}
}
};
const ScoreBoardEntry = {
props: ['player'],
template: `
<div>
Name: {{player.name}}<br/>
Score: {{player.points}}
<pre>Debug:
{{player}}
</pre>
</div>
`
};
const scoreBoard = {
//props: ['players'],
template: `
<div class="scoreboard">
<strong>Scoreboard</strong>
<div class="scores">
<score-board-entry v-for="player in sortedPlayers" :key="player.id" :player="player"></score-board-entry>
</div>
</div>
`,
data() {
return {}
},
components: {
ScoreBoardEntry
},
computed: {
...Vuex.mapState({
players: (state) => state.game.players // info: mapping more complicated here because of module --> with-out module we could just use ...mapState(['players]);
}),
/*players() { // same as mapState
console.log(this.$store.state.game.players);
return this.$store.state.game.players;
},*/
sortedPlayers() {
return _.sortBy(this.players, 'points').reverse(); //'score')
}
}
};
Vue.use(Vuex);
const store = new Vuex.Store({
modules: {
game
}
});
new Vue({
el: '#app',
store,
data() {
return {
testData: {
id: 2,
points: 10
}
};
},
components: {
scoreBoard
},
methods: {
/*addPoints(payload) {
this.$store.commit('game/addPoints', payload);
}*/
...Vuex.mapMutations({
addPoints: 'game/addPoints'
})
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/2.3.1/vuex.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.js"></script>
<div id="app">
user id: <input v-model="testData.id">
points: <input v-model="testData.points" type="number">
<button @click="addPoints(testData)">
Add points
</button>
<score-board></score-board>
</div>
我有一个 vuex-store game
,其中包含一个数组 players
。
每个 player
都有一个 id
、name
和一个 score
。
我现在有一个组件 scoreboard
,它应该按分数列出所有玩家。
为了对玩家进行排序,我在我的组件中添加了一个计算 属性。
当我现在在应用程序中的某处更新玩家分数时,我计算的 属性 不会被触发。我知道它没有被触发,因为数组本身没有改变。我需要调用 push/pop/shift/anything 来改变数组。
解决这个问题的常用方法是什么?当我更新它的一些属性时,我是否也应该改变数组?由于呈现 player.points
的组件已经成功更新,这看起来很脏。
有没有办法将更多 listeners 添加到计算的 属性?
我的组件:
<template>
<div class="scoreboard">
<strong>Scoreboard</strong>
<div class="scores">
<score-board-entry v-for="player in sortedPlayers" :key="player.id" :player="player"></score-board-entry>
</div>
</div>
</template>
<script>
import _ from 'lodash'
import ScoreBoardEntry from './ScoreBoardEntry.vue'
export default {
props: ['players'],
data () {
return { }
},
components: { ScoreBoardEntry },
computed: {
sortedPlayers () {
return _.sortBy(this.players, 'score')
}
}
}
</script>
<style scoped>
</style>
我的店铺:
const initialState: state = {
id: '',
players: []
}
const game = {
namespaced: true,
state: initialState,
mutations: {
addPoints (state: state, payload: addPointsPayload) {
const player = state.players.find((p) => p.id === payload.id)
player.points = player.points + payload.points
}
...
如果不了解您如何使用记分板组件,很难说出为什么它没有更新。
无论如何,如果您要删除 scoreBoard 组件中的 属性 球员,并使用带有 mapState 或 mapGetters 的 Vuex 状态球员,它会在您更改球员数据时立即自动更新您的棋盘。
我在创建下面的演示过程中发现的另一点是您按分数排序,但我认为它应该是分数。因为您的状态中没有得分 属性 或得分计算不在您的代码段中。
请查看下面的演示或此 fiddle。
而且我认为您的 loadash 排序没问题。我刚刚把结果倒过来,把最高分放在第一位。
在您的 addPoints
突变方法中,我更改为 shorthand +=
因为我认为这样更容易阅读 - 您的版本在这里也可以。
mapState 或 mapMutations 演示中的注释代码与映射器的作用相同,保留在那里以了解映射器在做什么。
const initialState = {
id: '',
players: [{
id: 0,
name: 'first',
points: 20
}, {
id: 1,
name: 'second',
points: 10
}, {
id: 2,
name: 'third player',
points: 35
}]
};
const game = {
namespaced: true,
state: initialState,
mutations: {
addPoints(state, payload) {
const player = state.players.find((p) => p.id === parseInt(payload.id));
//console.log('addpoints', payload, player);
player.points += payload.points;
}
}
};
const ScoreBoardEntry = {
props: ['player'],
template: `
<div>
Name: {{player.name}}<br/>
Score: {{player.points}}
<pre>Debug:
{{player}}
</pre>
</div>
`
};
const scoreBoard = {
//props: ['players'],
template: `
<div class="scoreboard">
<strong>Scoreboard</strong>
<div class="scores">
<score-board-entry v-for="player in sortedPlayers" :key="player.id" :player="player"></score-board-entry>
</div>
</div>
`,
data() {
return {}
},
components: {
ScoreBoardEntry
},
computed: {
...Vuex.mapState({
players: (state) => state.game.players // info: mapping more complicated here because of module --> with-out module we could just use ...mapState(['players]);
}),
/*players() { // same as mapState
console.log(this.$store.state.game.players);
return this.$store.state.game.players;
},*/
sortedPlayers() {
return _.sortBy(this.players, 'points').reverse(); //'score')
}
}
};
Vue.use(Vuex);
const store = new Vuex.Store({
modules: {
game
}
});
new Vue({
el: '#app',
store,
data() {
return {
testData: {
id: 2,
points: 10
}
};
},
components: {
scoreBoard
},
methods: {
/*addPoints(payload) {
this.$store.commit('game/addPoints', payload);
}*/
...Vuex.mapMutations({
addPoints: 'game/addPoints'
})
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/2.3.1/vuex.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.js"></script>
<div id="app">
user id: <input v-model="testData.id">
points: <input v-model="testData.points" type="number">
<button @click="addPoints(testData)">
Add points
</button>
<score-board></score-board>
</div>