UNPKG

vuex-viewport

Version:

Vuex extension that allows making window size as computed property.

352 lines (274 loc) 7.93 kB
# vuex-viewport [![npm](https://img.shields.io/npm/v/vuex-viewport)](https://www.npmjs.com/package/vuex-viewport) [![GitHub license](https://img.shields.io/github/license/ony3000/vuex-viewport)](https://github.com/ony3000/vuex-viewport/blob/master/LICENSE) [![package hits](https://data.jsdelivr.com/v1/package/npm/vuex-viewport/badge?style=rounded)](https://www.jsdelivr.com/package/npm/vuex-viewport)<br> Vuex extension that allows making window size as computed property. **NOTE:** If you use Vue 3, Vuex 4 and TypeScript, see [the section below](#typescript-support). ## Requirement * Vuex 2.3.0+ (up to 4.x) ## Installation ### CDN ```html <script src="https://cdn.jsdelivr.net/npm/vuex-viewport@1.2.1/dist/vuex-viewport.js"></script> ``` ### NPM ```sh npm install vuex-viewport ``` ### Yarn ```sh yarn add vuex-viewport ``` ## Usage ### Outline 1. Add a module and plugin to your store. 2. Use computed property where necessary. ### with CDN See example code [here](./demo.html). ```html <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](https://codesandbox.io/s/use-case-es2015-module-import-5tfck) or another example code [using with Nuxt.js](https://codesandbox.io/s/use-case-using-with-nuxtjs-dcubc). ```javascript // 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'); ``` ```vue // 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](https://lodash.com/docs/4.17#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](https://lodash.com/docs/4.17#debounce)) breakpoints | Object | {<br>&nbsp;&nbsp;tablet:&nbsp;768,<br>&nbsp;&nbsp;desktop:&nbsp;992<br>} | 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 1. Add a declaration file in your project directory. ```typescript // 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>; } } ``` 2. Create a store instance. ```typescript // store.ts import { createStore } from 'vuex'; import { storeModule, createPlugin } from 'vuex-viewport'; export const store = createStore({ modules: { viewport: storeModule, }, plugins: [ createPlugin(), ], }); ``` 3. Install the store instance. ```typescript // 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'); ``` 4. Use store states and getters in Vue component. ```vue // 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. 1. No declaration file is required. 2. The process of creating and installing a store is the same as the above example. 3. Use store states and getters in Vue component. ```vue // 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 1. No declaration file is required. 2. Create a store instance. ```typescript // 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); } ``` 3. Install the store instance. ```typescript // 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'); ``` 4. Use store states and getters in Vue component. ```vue // 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> ```