Vue.js
Vuex
Sök…
Introduktion
Vuex är ett tillståndshanteringsmönster + bibliotek för Vue.js-applikationer. Det fungerar som en centraliserad butik för alla komponenter i en applikation, med regler som säkerställer att staten endast kan muteras på ett förutsägbart sätt. Den integreras också med Vues officiella förlängning av dev-verktyg för att tillhandahålla avancerade funktioner såsom nollkonfigurering av tidfärdsfelsökning och status / export / import av stillbild.
Vad är Vuex?
Vuex är ett officiellt plugin för Vue.js som erbjuder en centraliserad datastore för användning i din applikation. Det påverkas starkt av Flux-applikationsarkitekturen, som har ett riktningslöst dataflöde som leder till enklare applikationsdesign och resonemang.
Inom en Vuex-applikation har datastore alla delade applikationstillstånd . Detta tillstånd förändras av mutationer som utförs som svar på en åtgärd som åberopar en mutationshändelse via avsändaren .
Ett exempel på dataflödet i en Vuex-applikation visas i diagrammet nedan. Diagram som används under MIT- licensen, ursprungligen från den officiella Vuex GitHub-repo .
Enskilda Vue.js-applikationskomponenter kan få åtkomst till butikobjektet för att hämta data via getters , som är rena funktioner som returnerar en skrivskyddad kopia av önskad data.
Komponenter kan ha handlingar som är funktioner som utför ändringar i komponentens egna kopia av data och sedan använda avsändaren för att skicka en mutationshändelse. Denna händelse hanteras sedan av datalagret som uppdaterar tillståndet vid behov.
Ändringar återspeglas sedan automatiskt i hela applikationen eftersom alla komponenter är reaktivt bundna till butiken via deras getters.
Ett exempel som illustrerar användningen av vuex i ett Vue-projekt.
const state = {
lastClickTime: null
}
const mutations = {
updateLastClickTime: (state, payload) => {
state.lastClickTime = payload
}
}
const getters = {
getLastClickTime: state => {
return new Date(state.lastClickTime)
}
}
const actions = {
syncUpdateTime: ({ commit }, payload) => {
commit("updateLastClickTime", payload)
},
asyncUpdateTime: ({ commit }, payload) => {
setTimeout(() => {
commit("updateLastClickTime", payload)
}, Math.random() * 5000)
}
}
const store = new Vuex.Store({
state,
getters,
mutations,
actions
})
const { mapActions, mapGetters } = Vuex;
// Vue
const vm = new Vue({
el: '#container',
store,
computed: {
...mapGetters([
'getLastClickTime'
])
},
methods: {
...mapActions([
'syncUpdateTime',
'asyncUpdateTime'
]),
updateTimeSyncTest () {
this.syncUpdateTime(Date.now())
},
updateTimeAsyncTest () {
this.asyncUpdateTime(Date.now())
}
}
})
Och HTML-mallen för samma:
<div id="container">
<p>{{ getLastClickTime || "No time selected yet" }}</p>
<button @click="updateTimeSyncTest">Sync Action test</button>
<button @click="updateTimeAsyncTest">Async Action test</button>
</div>
Här innehåller staten lastClickTime- egenskapen initialiserad som null. Denna inställning av standardvärden är viktig för att hålla egenskaperna reaktiva . Egenskaper som inte nämns i staten kommer att finnas tillgängliga men ändringarna som gjorts därefter skulle inte vara tillgängliga genom att använda getters.
Den getter som används, ger en beräknad egenskap som kommer att uppdateras varje gång en mutation uppdaterar värdet på den statliga egenskapen.
Endast mutationer får ändra tillståndet och dess egenskaper, det sagt, det gör det bara synkront .
En åtgärd kan användas i fallet med asynkrona uppdateringar, där API-samtalet (här hånat av den slumpmässigt tidsinställda setTimeout) kan göras i åtgärden, och efter att ha fått svaret kan en mutation åta sig att göra ändringen till staten .
Varför använda Vuex?
När man bygger stora applikationer som SPA: er, som vanligtvis består av många återanvändbara komponenter, kan de snabbt bli svåra att bygga och underhålla. Delning av data och tillstånd mellan dessa komponenter kan också snabbt bryta ner och bli svårt att felsöka och underhålla.
Genom att använda en centraliserad applikationsdatalager kan hela applikationstillståndet representeras på ett ställe vilket gör applikationen mer organiserad. Genom att använda ett enkelriktat dataflöde, mutationer och genom att utvidga komponentdata åtkomst till endast de data som krävs blir det mycket enklare att resonera om komponentrollen och hur den ska påverka applikationstillståndet.
VueJS-komponenter är separata enheter och de kan inte enkelt dela data mellan varandra. För att dela data utan vuex måste vi emit
händelse med data och sedan lyssna och fånga händelsen med on
.
komponent 1
this.$emit('eventWithDataObject', dataObject)
komponent 2
this.$on('eventWithDataObject', function (dataObject) {
console.log(dataObject)
})
Med vuex installerat kan vi helt enkelt komma åt dess data från valfri komponent utan att behöva lyssna på händelser.
this.$store.state.myData
Vi kan också ändra data synkront med mutatorer , använda asynkrona åtgärder och få data med getterfunktioner .
Getterfunktioner kan fungera som globala beräknade funktioner. Vi kan komma åt dem från komponenter:
this.$store.getters.myGetter
Åtgärder är globala metoder. Vi kan skicka dem från komponenter:
this.$store.dispatch('myAction', myDataObject)
Och mutationer är det enda sättet att ändra data i vuex. Vi kan göra ändringar:
this.$store.commit('myMutation', myDataObject)
Vuex-kod skulle se ut så här
state: {
myData: {
key: 'val'
}
},
getters: {
myGetter: state => {
return state.myData.key.length
}
},
actions: {
myAction ({ commit }, myDataObject) {
setTimeout(() => {
commit('myMutation', myDataObject)
}, 2000)
}
},
mutations: {
myMutation (state, myDataObject) {
state.myData = myDataObject
}
}
Hur installerar jag Vuex?
För det mesta kommer du att använda Vuex i större komponentbaserade applikationer där du troligtvis använder en modulbuntare som Webpack eller Browserify tillsammans med Vueify om du använder enstaka filer.
I detta fall är det enklaste sättet att få Vuex från NPM. Kör kommandot nedan för att installera Vuex och spara det i dina applikationsberoenden.
npm install --save vuex
Se till att du laddar länk Vuex med din Vue-inställning genom att placera följande rad efter ditt require('vue')
.
Vue.use(require('vuex'))
Vuex är också tillgängligt på CDN; du kan ta tag i den senaste versionen från cdnjs här .
Auto avvisbara aviseringar
Det här exemplet registrerar en vuexmodul dynamiskt för att lagra anpassade aviseringar som automatiskt kan tas bort
notifications.js
lösa vuex-lagring och definiera vissa konstanter
//Vuex store previously configured on other side
import _store from 'path/to/store';
//Notification default duration in milliseconds
const defaultDuration = 8000;
//Valid mutation names
const NOTIFICATION_ADDED = 'NOTIFICATION_ADDED';
const NOTIFICATION_DISMISSED = 'NOTIFICATION_DISMISSED';
ställa in vårt modul initialtillstånd
const state = {
Notifications: []
}
ställa in våra modulgetters
const getters = {
//All notifications, we are returning only the raw notification objects
Notifications: state => state.Notifications.map(n => n.Raw)
}
ställa in våra modulåtgärder
const actions = {
//On actions we receive a context object which exposes the
//same set of methods/properties on the store instance
//{commit} is a shorthand for context.commit, this is an
//ES2015 feature called argument destructuring
Add({ commit }, notification) {
//Get notification duration or use default duration
let duration = notification.duration || defaultDuration
//Create a timeout to dismiss notification
var timeOut = setTimeout(function () {
//On timeout mutate state to dismiss notification
commit(NOTIFICATION_DISMISSED, notification);
}, duration);
//Mutate state to add new notification, we create a new object
//for save original raw notification object and timeout reference
commit(NOTIFICATION_ADDED, {
Raw: notification,
TimeOut: timeOut
})
},
//Here we are using context object directly
Dismiss(context, notification) {
//Just pass payload
context.commit(NOTIFICATION_DISMISSED, notification);
}
}
ställa in våra modulmutationer
const mutations = {
//On mutations we receive current state and a payload
[NOTIFICATION_ADDED](state, notification) {
state.Notifications.push(notification);
},
//remember, current state and payload
[NOTIFICATION_DISMISSED](state, rawNotification) {
var i = state.Notifications.map(n => n.Raw).indexOf(rawNotification);
if (i == -1) {
return;
}
clearTimeout(state.Notifications[i].TimeOut);
state.Notifications.splice(i, 1);
}
}
Registrera vår modul med definierat tillstånd, bokstäver, åtgärder och mutation
_store.registerModule('notifications', {
state,
getters,
actions,
mutations
});
Användande
componentA.vue
Denna komponent visar alla aviseringar som bootstraps varningar i övre högra hörnet av skärmen, gör det också möjligt att manuellt avvisa varje avisering.
<template>
<transition-group name="notification-list" tag="div" class="top-right">
<div v-for="alert in alerts" v-bind:key="alert" class="notification alert alert-dismissible" v-bind:class="'alert-'+alert.type">
<button v-on:click="dismiss(alert)" type="button" class="close" aria-label="Close"><span aria-hidden="true">×</span></button>
<div>
<div>
<strong>{{alert.title}}</strong>
</div>
<div>
{{alert.text}}
</div>
</div>
</div>
</transition-group>
</template>
<script>
export default {
name: 'arc-notifications',
computed: {
alerts() {
//Get all notifications from store
return this.$store.getters.Notifications;
}
},
methods: {
//Manually dismiss a notification
dismiss(alert) {
this.$store.dispatch('Dismiss', alert);
}
}
}
</script>
<style lang="scss" scoped>
$margin: 15px;
.top-right {
top: $margin;
right: $margin;
left: auto;
width: 300px;
//height: 600px;
position: absolute;
opacity: 0.95;
z-index: 100;
display: flex;
flex-wrap: wrap;
//background-color: red;
}
.notification {
transition: all 0.8s;
display: flex;
width: 100%;
position: relative;
margin-bottom: 10px;
.close {
position: absolute;
right: 10px;
top: 5px;
}
> div {
position: relative;
display: inline;
}
}
.notification:last-child {
margin-bottom: 0;
}
.notification-list-enter,
.notification-list-leave-active {
opacity: 0;
transform: translateX(-90px);
}
.notification-list-leave-active {
position: absolute;
}
</style>
Utdrag för att lägga till meddelande i någon annan komponent
//payload could be anything, this example content matches with componentA.vue
this.$store.dispatch('Add', {
title = 'Hello',
text = 'World',
type = 'info',
duration = 15000
});