Skip to content
This repository was archived by the owner on Nov 13, 2023. It is now read-only.

Commit a4514e0

Browse files
committed
add keystroke event detection, thanks @micheleriva
1 parent 27a6a51 commit a4514e0

File tree

5 files changed

+630
-40
lines changed

5 files changed

+630
-40
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ var YourComponent = Vue.extend({
8989
|after|URL of after image|true|String|-|
9090
|afterLabel|When hovering over image what label should show up over after image|false|String|-|
9191
|offset|How far from the left the slider should be on load (between 0 and 1)|false|Number|0.5|
92+
|keyboardStep|How far the slider should be moved on arrow key press (between 0 and 1)|false|Number|0.2|
9293

9394
## Usage
9495

demo/Demo.vue

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<h2>Demo</h2>
44
<TwentyTwenty
55
offset="0.7"
6+
keyboardStep="0.1"
67
before="//placehold.it/600x200/E8117F/FFFFFF"
78
beforeLabel="before"
89
after="//placehold.it/600x200/CCCCCC/FFFFFF"

package.json

+31-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
"version": "0.8.1",
44
"main": "./dist/vue-twentytwenty.common.js",
55
"author": "Mark Hayes <[email protected]>",
6-
"license": "MIT",
6+
"contributors": [
7+
"Mattia Astorino (https://equinsuocha.io)",
8+
"Michele Riva (https://micheleriva.it)"
9+
],
10+
"license": "MIT",
711
"repository": {
812
"type": "git",
913
"url": "https://github.com/mhayes/vue-twentytwenty"
@@ -16,12 +20,36 @@
1620
],
1721
"devDependencies": {
1822
"@vue/cli-plugin-babel": "~4.3.0",
23+
"@vue/cli-plugin-eslint": "~4.3.0",
1924
"@vue/cli-service": "^4.3.1",
25+
"babel-eslint": "^10.1.0",
26+
"eslint": "^6.7.2",
27+
"eslint-plugin-vue": "^6.2.2",
2028
"vue": "^2.6.11",
2129
"vue-template-compiler": "^2.6.11"
2230
},
2331
"scripts": {
2432
"serve": "vue-cli-service serve demo/index.js",
25-
"build": "vue-cli-service build --target lib --name vue-twentytwenty ./src/index.js"
26-
}
33+
"build": "vue-cli-service build --target lib --name vue-twentytwenty ./src/index.js",
34+
"lint": "vue-cli-service lint"
35+
},
36+
"eslintConfig": {
37+
"root": true,
38+
"env": {
39+
"node": true
40+
},
41+
"extends": [
42+
"plugin:vue/essential",
43+
"eslint:recommended"
44+
],
45+
"parserOptions": {
46+
"parser": "babel-eslint"
47+
},
48+
"rules": {}
49+
},
50+
"browserslist": [
51+
"> 1%",
52+
"last 2 versions",
53+
"not dead"
54+
]
2755
}

src/TwentyTwenty.vue

+39-23
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,33 @@
33
v-bind:style="containerStyle"
44
v-on:touchstart="startSlide"
55
v-on:mousedown="startSlide">
6+
67
<img :src="after" alt="after"
78
v-on:mousedown.prevent
89
v-on:load="setDimensions" />
10+
911
<img :src="before" alt="before"
1012
v-on:mousedown.prevent
1113
v-bind:style="beforeImgStyle" />
14+
1215
<div class="twentytwenty-overlay"
1316
v-bind:style="overlayStyle">
1417
<div v-if="beforeLabel" class="twentytwenty-before-label">{{beforeLabel}}</div>
1518
<div v-if="afterLabel" class="twentytwenty-after-label">{{afterLabel}}</div>
1619
</div>
20+
1721
<div class="twentytwenty-handle"
18-
v-bind:style="handleStyle">
22+
v-bind:style="handleStyle"
23+
tabindex="0"
24+
v-on:keydown="handleArrowNavigation">
1925
<div class="twentytwenty-arrow-left"></div>
2026
<div class="twentytwenty-arrow-right"></div>
2127
</div>
2228
</div>
2329
</template>
2430

2531
<script>
32+
2633
export default {
2734
data () {
2835
return {
@@ -33,7 +40,6 @@ export default {
3340
overlayStyle: {}
3441
}
3542
},
36-
3743
props: {
3844
before: {
3945
type: String,
@@ -52,50 +58,57 @@ export default {
5258
offset: {
5359
type: [String, Number],
5460
default: 0.5,
55-
validator: (value) => {
56-
return (value > 0 && value <= 1)
57-
}
61+
validator: (value) => (value > 0 && value <= 1)
62+
},
63+
keyboardStep: {
64+
type: [String, Number],
65+
default: 0.2,
66+
validator: (value) => (value > 0 && value <= 1)
5867
}
5968
},
60-
6169
methods: {
6270
setDimensions () {
6371
const img = this.$el.querySelector("img")
6472
this.imgOffset = img.getBoundingClientRect()
6573
this.containerStyle = { width: `${this.w}px`, height: `${this.h}px` };
6674
},
67-
6875
startSlide (event) {
6976
this.sliding = true
7077
this.moveSlide(event)
7178
this.overlayStyle = { opacity: 0 }
7279
},
73-
80+
handleArrowNavigation(event) {
81+
return this.moveSlide(event)
82+
},
7483
moveSlide (event) {
7584
if (this.sliding) {
7685
var x = (event.touches ? event.touches[0].pageX : event.pageX) - this.imgOffset.left
7786
x = (x < 0) ? 0 : ((x > this.w) ? this.w : x)
78-
79-
this.slideOffset = (x / this.w)
87+
return this.slideOffset = (x / this.w)
88+
}
89+
if (event.key) {
90+
switch(event.key) {
91+
case "Left": // IE/Edge key
92+
case "ArrowLeft": this.slideOffset = ((this.floatOffset - this.floatKeyboardStep) >= 0) ? this.floatOffset - this.floatKeyboardStep : 0 ; break;
93+
case "Right": // IE/Edge key
94+
case "ArrowRight": this.slideOffset = ((this.floatOffset + this.floatKeyboardStep) <= 1) ? this.floatOffset + this.floatKeyboardStep : 1 ; break;
95+
default: return;
96+
}
8097
}
8198
},
82-
8399
endSlide () {
84100
this.sliding = false
85101
this.overlayStyle = {}
86102
},
87-
88103
resize () {
89104
this.containerStyle = {};
90105
this.$nextTick(() => this.setDimensions());
91106
}
92107
},
93-
94108
computed: {
95109
beforeImgStyle () {
96110
return { clip: `rect(0, ${this.x}px, ${this.h}px, 0)` }
97111
},
98-
99112
handleStyle () {
100113
const size = 40;
101114
return {
@@ -105,30 +118,29 @@ export default {
105118
left: `calc(${this.slideOffset*100}% - ${size/2}px)`
106119
}
107120
},
108-
109121
x () {
110122
return this.w * this.slideOffset
111123
},
112-
113124
w () {
114-
if (this.imgOffset)
115-
return this.imgOffset.width
125+
return this.imgOffset ? this.imgOffset.width : null
116126
},
117-
118127
h () {
119-
if (this.imgOffset)
120-
return this.imgOffset.height
128+
return this.imgOffset ? this.imgOffset.height : null
129+
},
130+
floatOffset () {
131+
return parseFloat(this.slideOffset)
132+
},
133+
floatKeyboardStep () {
134+
return parseFloat(this.keyboardStep)
121135
}
122136
},
123-
124137
mounted () {
125138
document.addEventListener("touchmove", this.moveSlide)
126139
document.addEventListener("touchend", this.endSlide)
127140
document.addEventListener("mousemove", this.moveSlide)
128141
document.addEventListener("mouseup", this.endSlide)
129142
window.addEventListener("resize", this.resize)
130143
},
131-
132144
beforeDestroy () {
133145
document.removeEventListener("touchmove", this.moveSlide)
134146
document.removeEventListener("touchend", this.endSlide)
@@ -195,6 +207,10 @@ export default {
195207
margin-top: -4px;
196208
user-select: none;
197209
}
210+
.twentytwenty-container .twentytwenty-handle:active,
211+
.twentytwenty-container .twentytwenty-handle:focus {
212+
outline: 0;
213+
}
198214
.twentytwenty-container .twentytwenty-handle:before, .twentytwenty-container .twentytwenty-handle:after {
199215
content: "";
200216
border: 2px solid white;

0 commit comments

Comments
 (0)