vuex-viewport
Vuex extension that allows making window size as computed property.
NOTE: If you use Vue 3, Vuex 4 and TypeScript, see the section below.
Requirement
- Vuex 2.3.0+ (up to 4.x)
Installation
CDN
<script src="https://cdn.jsdelivr.net/npm/vuex-viewport@1.2.1/dist/vuex-viewport.js"></script>
NPM
npm install vuex-viewport
Yarn
yarn add vuex-viewport
Usage
Outline
- Add a module and plugin to your store.
- Use computed property where necessary.
with CDN
See example code here.
<script>
var store = new Vuex.Store({
modules: {
viewport: vuexViewport.storeModule
},
plugins: [
vuexViewport.createPlugin()
]
});
new Vue({
el: '#app',
store: store,
computed: {
windowWidth: function () {
return this.$store.state.viewport.width;
},
windowHeight: function () {
return this.$store.state.viewport.height;
},
layoutType: function () {
// NOTE: This getter is supported in 1.1.0+
return this.$store.getters['viewport/mediaName'];
}
}
});
</script>
without CDN
See example code here or another example code using with Nuxt.js.
// main.js
import Vue from 'vue';
import Vuex from 'vuex';
import { storeModule, createPlugin } from 'vuex-viewport';
import App from './App.vue';
Vue.use(Vuex);
const store = new Vuex.Store({
modules: {
viewport: storeModule
},
plugins: [
createPlugin()
]
});
new Vue({
store,
render: (h) => h(App)
}).$mount('#app');
// App.vue
<template>
<div id="app">
<p>Layout type: {{ layoutType }}</p>
<p>Window size: {{ windowWidth }} x {{ windowHeight }}</p>
</div>
</template>
<script>
export default {
name: 'App',
computed: {
windowWidth: function () {
return this.$store.state.viewport.width;
},
windowHeight: function () {
return this.$store.state.viewport.height;
},
layoutType: function () {
// NOTE: This getter is supported in 1.1.0+
return this.$store.getters['viewport/mediaName'];
}
}
};
</script>
Configuration
The createPlugin
has some options (supported in 1.1.0+):
Name | Type | Default | Description |
---|---|---|---|
delay | Number | 200 | The number of milliseconds to delay to measure the window size. (see debounce) |
maxDelay | Number | 1000 | The maximum number of milliseconds to wait without measuring the size of the window if a series of resizing events does not end. (see debounce) |
breakpoints | Object | { tablet: 768, desktop: 992 } |
A set of key-value pairs whose key is the mediaName and whose value is the minimum width of the window. |
TypeScript Support
You'll probably use one of these three examples.
Using neither Class-style Component nor Composition API
- Add a declaration file in your project directory.
// vuex.d.ts
import { ComponentCustomProperties } from 'vue';
import { Store } from 'vuex';
import { ModuleState } from 'vuex-viewport';
declare module '@vue/runtime-core' {
// declare your own store states
interface State {
viewport: ModuleState;
}
// provide typings for `this.$store`
interface ComponentCustomProperties {
$store: Store<State>;
}
}
- Create a store instance.
// store.ts
import { createStore } from 'vuex';
import { storeModule, createPlugin } from 'vuex-viewport';
export const store = createStore({
modules: {
viewport: storeModule,
},
plugins: [
createPlugin(),
],
});
- Install the store instance.
// main.ts
import { createApp } from 'vue';
import { store } from 'PATH_OF_YOUR_store.ts';
import App from 'PATH_OF_YOUR_App.vue';
const app = createApp(App);
app.use(store);
app.mount('#app');
- Use store states and getters in Vue component.
// App.vue
<template>
<div>
<p>Layout type: {{ layoutType }}</p>
<p>Window size: {{ windowWidth }} x {{ windowHeight }}</p>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'App',
computed: {
windowWidth(): number {
return this.$store.state.viewport.width;
},
windowHeight(): number {
return this.$store.state.viewport.height;
},
layoutType(): string {
return this.$store.getters['viewport/mediaName'];
},
},
});
</script>
Using with Class-style Component
NOTE: This example is using Vue Class Component 8, which is still in beta as of July 2021.
-
No declaration file is required.
-
The process of creating and installing a store is the same as the above example.
-
Use store states and getters in Vue component.
// App.vue
<template>
<div>
<p>Layout type: {{ layoutType }}</p>
<p>Window size: {{ windowWidth }} x {{ windowHeight }}</p>
</div>
</template>
<script lang="ts">
import { Options, Vue } from 'vue-class-component';
@Options({
computed: {
windowWidth() {
return this.$store.state.viewport.width;
},
windowHeight() {
return this.$store.state.viewport.height;
},
layoutType() {
return this.$store.getters['viewport/mediaName'];
},
},
})
export default class App extends Vue {}
</script>
Using with Composition API
-
No declaration file is required.
-
Create a store instance.
// store.ts
import { InjectionKey } from 'vue';
import { createStore, useStore as baseUseStore, Store } from 'vuex';
import { storeModule, createPlugin, ModuleState } from 'vuex-viewport';
export interface State {
viewport: ModuleState;
}
export const key: InjectionKey<Store<State>> = Symbol();
export const store = createStore({
modules: {
viewport: storeModule,
},
plugins: [
createPlugin(),
],
});
export function useStore() {
return baseUseStore(key);
}
- Install the store instance.
// main.ts
import { createApp } from 'vue';
import { store, key } from 'PATH_OF_YOUR_store.ts';
import App from 'PATH_OF_YOUR_App.vue';
const app = createApp(App);
app.use(store, key);
app.mount('#app');
- Use store states and getters in Vue component.
// App.vue
<template>
<div>
<p>Layout type: {{ layoutType }}</p>
<p>Window size: {{ windowWidth }} x {{ windowHeight }}</p>
</div>
</template>
<script lang="ts">
import { defineComponent, computed } from 'vue';
import { useStore } from 'PATH_OF_YOUR_store.ts';
export default defineComponent({
name: 'App',
setup() {
const store = useStore();
const windowWidth = computed(() => store.state.viewport.width);
const windowHeight = computed(() => store.state.viewport.height);
const layoutType = computed(() => store.getters['viewport/mediaName']);
return {
windowWidth,
windowHeight,
layoutType,
};
},
});
</script>