Home / Frontend Codes and Demos / CSS Code Demos / Vue Touch HammerJs Example and Demo
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

Vue Touch HammerJs Example and Demo

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

Demo Download

Author Lisi
Hits
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[index]}"> 				{{ 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; }   /* layout */ 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[this.animals.indexOf(this.selected)]; 			} 			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

Vue Touch HammerJs Example and Demo preview

About CV

I'm frontend developer

Check Also

Naturalized Checkbox Toggle Switches

This demo is a response to a post by Marcus Connor addressing confusion with checkbox …