Vue component to bind event-handlers or classes to window/document/body

Pseudo Window

Declaratively interface window/document/body in your Vue template.

Insert pseudo-window anywhere in your template:

<pseudo-window @resize.passive="handleResize" />

? Install

npm i vue-pseudo-window

?‍♂️ Why?

  • Cleaner code No longer pollute your component with .addEventListener() & .removeEventListener()
  • ♻️ Template API Use Vue's @event syntax to bind listeners to the window as like you would to any other element
  • ? Robust Supports all event modifiers capture, passive, and once. SSR friendly.
  • ? Tiny 819 B Gzipped!

Before

<template>
  ...
</template>

<script>
export default {

	// Your component would be polluted with event binding logic
	mounted() {
		window.addEventListener('resize', this.handleResize, { passive: true })
	},

	beforeDestroy() {
		window.removeEventListener('resize', this.handleResize)
	},

	methods: {
		handleResize() {
			...
		}
	}
}
</script>

After

<template>
	<div>
		...

		<!-- Insert pseudo-window anywhere in your template -->
		<pseudo-window @resize.passive="handleResize" />
	</div>
</template>

<script>
export default {

	// Much cleaner!
	methods: {
		handleResize() {
			...
		}
	}
}
</script>

?‍? Demos

Adding listeners to window

<template>
	<div>
		<div>
			Window width: {{ winWidth }}
		</div>

		<pseudo-window
			<!-- Handle window resize with "passive" option -->
			@resize.passive="onResize"
		/>
	</div>
</template>

<script>
import PseudoWindow from 'vue-pseudo-window';

export default {
	components: {
		PseudoWindow
	},
	
	data() {
		return {
			winWidth: 0
		}
	},

	methods: {
		onResize() {
			this.winWidth = window.innerWidth;
		}
	}
}
</script>

Adding class & listeners to document <html>

<template>
	<div>
		<pseudo-window
			document

			<!-- Add a class to <html> -->
			:class="$style.lockScroll"

			<!-- Handle document click -->
			@click="onClick"
		/>
	</div>
</template>

<script>
import PseudoWindow from 'vue-pseudo-window';

export default {
	components: {
		PseudoWindow
	},

	methods: {
		onClick() {
			console.log('Document click!')
		}
	}
}
</script>

<style module>
.lockScroll {
	overflow: hidden;
}
</style>

Adding class & listeners to body <body>

<template>
	<div>
		<pseudo-window
			body

			<!-- Add a class to <body> -->
			:class="$style.lockScroll"

			<!-- Handle body click -->
			@click="onClick"
		/>
	</div>
</template>

<script>
import PseudoWindow from 'vue-pseudo-window';

export default {
	components: {
		PseudoWindow
	},

	methods: {
		onClick() {
			console.log('Body click!')
		}
	}
}
</script>

<style module>
.lockScroll {
	overflow: hidden;
}
</style>

Only want one root element?

PseudoWindow is a functional component that returns exactly what's passed into it. By using it as the root component, its contents will pass-through.

<template>
	<pseudo-window
		@blur="pause"
		@focus="resume"
	>
		<video>
			<source
				src="/media/examples/flower.webm"
				type="video/webm"
			>
		</video>
	</div>
</template>

<script>
import PseudoWindow from 'vue-pseudo-window';

export default {
	components: {
		PseudoWindow
	},

	methods: {
		resume() {
			this.$el.play()
		},
		pause() {
			this.$el.pause()
		}
	}
}
</script>

GitHub