CSS

Vue Touch HammerJs Example and Demo

W
W3Tweaks Team
Frontend Tutorials
Oct 10, 2018 2 min read
Vue Touch HammerJs Example and Demo
Vue Touch HammerJs Example and Demo are developed using CSS, HTML and HammerJs.

Vue Touch HammerJs Example and Demo are developed using CSS, HTML and HammerJs.

Demo Download

Author Lisi

Created AUGUST 10, 2018

License Open

Compatible browsers Chrome, Firefox, Safari

HTML Snippet

`<main class="" id="app" v-pan="onPan"> 	<div class="emoji" ref="emoji">{{ selectedContent }}</div> 	<section class="slider"> 		<ul class="slider__list" ref="list"> 			<li v-for="(animal, index) in animals" :key="animal" 					class="slider__item"  					v-tap="(e) => onTap(e, animal)" 					:style="{backgroundColor: colors}"> 				{{ animal }} 			</li> 		</ul> 	</section> </main>`

SCSS Code

`.slider { 	width: 100%; 	height: 120px; 	overflow: visible;   position: relative;   white-space: nowrap;  	&__list { 		display: flex; 		width: 100%; 		height: 100%; 		 		font-size: 2rem; 		backface-visibility: hidden; 		transform: translateX(calc(var(--x, 0) * 1%)); 	} 	 	&__item { 		position: relative; 		flex: 0 0 140px; 		 		display: flex; 		justify-content: center; 		align-items: center; 		height: 100%; 		margin-right: 12px; 		padding: 6px; 		box-sizing: border-box; 		 		border-radius: 8px; 		text-align: center;   	transition: opacity 0.15s ease; 		color: #fff;  		&:focus { 			opacity: 0.8; 		} 	} }  .emoji  { 	padding: 40px; 	font-size: 6rem; 	min-height: 6rem; 	backface-visibility: hidden; }    html { 	height: 100%; 	display: flex; 	background: #155e63; }  body {	 	position: relative;  	width: 100%; 	height: 100%; 	max-width:  360px; 	max-height: 640px; 	margin: auto;  	background: #efefef; 	font-family:'Do Hyeon', sans-serif; 	font-size: 16px; }  #app { 	height: 100%; 	width: 100%; 	display: flex; 	flex-direction: column; 	justify-content: center; 	align-items: center; 	padding: 20px; 	box-sizing: border-box; 	 	overflow: hidden; }`

JavaScript Snippet

`Vue.directive("pan", { 	bind: function(el, binding) { 		if (typeof binding.value === "function") { 			const mc = new Hammer(el); 			mc.get("pan").set({ direction: Hammer.DIRECTION_ALL }); 			mc.on("pan", binding.value); 		} 	} });  Vue.directive("tap", { 	bind: function(el, binding) { 		if (typeof binding.value === "function") { 			const mc = new Hammer(el); 			mc.on("tap", binding.value); 		} 	} });  const app = new Vue({ 	el: "#app", 	data: { 		animals: [ 			"cat", 			"dog", 			"panda", 			"lion", 			"frog", 			"bear", 			"mouse", 			"tiger", 			"monkey" 		], 		emojis: ["ðߐ±", "ðߐ¶", "ðߐ¼", "ð�¦", "🐸", "🐻", "🐹", "🐯", "🐵"], 		colors: [ 			"#F7CC45", 			"#AC6909", 			"#272625", 			"#FFAD01", 			"#81DC58", 			"#C68E71", 			"#F2B2BD", 			"#FFCB00", 			"#BE9763" 		], 		currentOffset: 0, 		selected: "cat" 	}, 	computed: { 		overflowRatio() { 			return this.$refs.list.scrollWidth / this.$refs.list.offsetWidth; 		}, 		itemWidth() { 			return this.$refs.list.scrollWidth / this.animals.length; 		}, 		selectedContent() { 			if (this.selected) { 				return this.emojis; 			} 			return ""; 		}, 		count() { 			return this.animals.length 		} 	}, 	watch: { 		selected(newValue) { 			TweenMax.fromTo( 				this.$refs.emoji, 				0.6, 				{ scale: 0 }, 				{ scale: 1, ease: Elastic.easeOut.config(1, 0.8) } 			); 		} 	}, 	methods: { 		onPan(e) { 			const dragOffset = 100 / this.itemWidth * e.deltaX / this.count * this.overflowRatio;  			const transform = this.currentOffset + dragOffset;  			this.$refs.list.style.setProperty("--x", transform);  			if (e.isFinal) { 				this.currentOffset = transform; 				const maxScroll = 100 - this.overflowRatio * 100; 				let finalOffset = this.currentOffset;  				// scrolled to last item 				if (this.currentOffset <= maxScroll) { 					finalOffset = maxScroll; 				} else if (this.currentOffset >= 0) { 					// scroll to first item 					finalOffset = 0; 				} else { 					// animate to next item according to pan direction 					const index = this.currentOffset / this.overflowRatio / 100 * this.count; 					const nextIndex = e.deltaX <= 0 ? Math.floor(index) : Math.ceil(index); 					finalOffset = 100 * this.overflowRatio / this.count * nextIndex; 				}  				// bounce back animation 				TweenMax.fromTo( 					this.$refs.list, 					0.4, 					{ '--x': this.currentOffset }, 					{ 						'--x': finalOffset, 						ease: Elastic.easeOut.config(1, 0.8), 						onComplete: () => { 							this.currentOffset = finalOffset; 						} 					} 				); 			} 		}, 		onTap(e, value) { 			if (value) { 				TweenMax.to(e.target, 0.12, { scale: 1.1, yoyo: true, repeat: 1, ease: Sine.easeOut}) 				this.selected = value; 			} 		} 	} });`

Preview