2
0
mirror of https://github.com/tenrok/vue-context.git synced 2026-06-24 09:30:33 +03:00

Close on click (#9)

This commit is contained in:
Randall Wilk
2018-09-12 12:41:31 -05:00
committed by GitHub
parent 179adf2d6e
commit 0e23700464
7 changed files with 186 additions and 156 deletions
+5
View File
@@ -1,5 +1,10 @@
# Changelog # Changelog
# 3.2.0 (Sep 12, 2018)
### Added
- Prop to tell context menu not to close automatically on click ([issue #8](https://github.com/rawilk/vue-context/issues/8))
## 3.1.1 (June 23, 2018) ## 3.1.1 (June 23, 2018)
### Updated ### Updated
+1
View File
@@ -148,6 +148,7 @@ new Vue({
| Property | Type | Default | Description | Property | Type | Default | Description
| -------- | ---- | ------- | ----------- | -------- | ---- | ------- | -----------
| `closeOnClick` | Boolean | `true` | If set to false, context menu will not automatically close when clicked on.
| `closeOnScroll` | Boolean | `true` | If set to true, context menu will automatically close on window scroll. | `closeOnScroll` | Boolean | `true` | If set to true, context menu will automatically close on window scroll.
## Credits ## Credits
+1 -1
View File
File diff suppressed because one or more lines are too long
+176 -152
View File
@@ -1,179 +1,203 @@
<template> <template>
<div class="v-context" <div class="v-context"
v-show="show" v-show="show"
:style="style" :style="style"
tabindex="-1" tabindex="-1"
@blur="close" @blur="close"
@click="close" @click="onClick"
@contextmenu.capture.prevent @contextmenu.capture.prevent
> >
<slot :data="data"></slot> <slot :data="data"></slot>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
props: { props: {
closeOnScroll: { /**
type: Boolean, * Close the menu on click.
default: true *
} * @type {boolean}
}, */
closeOnClick: {
type: Boolean,
default: true
},
computed: { /**
/** * Close the menu automatically on window scroll.
* Generate the CSS styles for positioning the context menu. *
* * @type {boolean}
* @returns {object|null} */
*/ closeOnScroll: {
style () { type: Boolean,
return this.show default: true
? { top: `${this.top}px`, left: `${this.left}px` } }
: null; },
},
},
data () { computed: {
return { /**
top: null, * Generate the CSS styles for positioning the context menu.
left: null, *
show: false, * @returns {object|null}
data: null */
}; style () {
}, return this.show
? { top: `${this.top}px`, left: `${this.left}px` }
: null;
},
},
mounted () { data () {
if (this.closeOnScroll) { return {
this.addScrollEventListener(); top: null,
} left: null,
}, show: false,
data: null
};
},
beforeDestroy () { mounted () {
if (this.closeOnScroll) { if (this.closeOnScroll) {
this.removeScrollEventListener(); this.addScrollEventListener();
} }
}, },
methods: { beforeDestroy () {
/** if (this.closeOnScroll) {
* Add scroll event listener to close context menu. this.removeScrollEventListener();
*/ }
addScrollEventListener () { },
window.addEventListener('scroll', this.close);
},
/** methods: {
* Close the context menu. /**
*/ * Add scroll event listener to close context menu.
close () { */
this.top = null; addScrollEventListener () {
this.left = null; window.addEventListener('scroll', this.close);
this.data = null; },
this.show = false;
},
/** /**
* Open the context menu. * Close the context menu.
* */
* @param {MouseEvent} event close () {
* @param {array|object|string} data User provided data for the menu this.top = null;
*/ this.left = null;
open (event, data) { this.data = null;
this.data = data; this.show = false;
this.show = true; },
this.$nextTick(() => { /**
this.positionMenu(event.clientY, event.clientX); * Close the menu if `closeOnClick` is set to true.
this.$el.focus(); */
}); onClick () {
}, if (this.closeOnClick) {
this.close();
}
},
/** /**
* Set the context menu top and left positions. * Open the context menu.
* *
* @param {number} top * @param {MouseEvent} event
* @param {number} left * @param {array|object|string} data User provided data for the menu
*/ */
positionMenu (top, left) { open (event, data) {
const largestHeight = window.innerHeight - this.$el.offsetHeight - 25; this.data = data;
const largestWidth = window.innerWidth - this.$el.offsetWidth - 25; this.show = true;
if (top > largestHeight) { this.$nextTick(() => {
top = largestHeight; this.positionMenu(event.clientY, event.clientX);
} this.$el.focus();
});
},
if (left > largestWidth) { /**
left = largestWidth; * Set the context menu top and left positions.
} *
* @param {number} top
* @param {number} left
*/
positionMenu (top, left) {
const largestHeight = window.innerHeight - this.$el.offsetHeight - 25;
const largestWidth = window.innerWidth - this.$el.offsetWidth - 25;
this.top = top; if (top > largestHeight) {
this.left = left; top = largestHeight;
}, }
/** if (left > largestWidth) {
* Remove the scroll event listener to close the context menu. left = largestWidth;
*/ }
removeScrollEventListener () {
window.removeEventListener('scroll', this.close);
}
},
watch: { this.top = top;
/** this.left = left;
* Add or remove the scroll event listener when the prop value changes. },
*
* @param {boolean} value
* @param {boolean} oldValue
*/
closeOnScroll (value, oldValue) {
if (value === oldValue) {
return;
}
if (value) { /**
this.addScrollEventListener(); * Remove the scroll event listener to close the context menu.
} else { */
this.removeScrollEventListener(); removeScrollEventListener () {
} window.removeEventListener('scroll', this.close);
} }
} },
};
watch: {
/**
* Add or remove the scroll event listener when the prop value changes.
*
* @param {boolean} value
* @param {boolean} oldValue
*/
closeOnScroll (value, oldValue) {
if (value === oldValue) {
return;
}
if (value) {
this.addScrollEventListener();
} else {
this.removeScrollEventListener();
}
}
}
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
$blue600: #1e88e5; $blue600: #1e88e5;
$gray74: #bdbdbd; $gray74: #bdbdbd;
$gray93: #ededed; $gray93: #ededed;
$gray98: #fafafa; $gray98: #fafafa;
.v-context { .v-context {
background: $gray98; background: $gray98;
border: 1px solid $gray74; border: 1px solid $gray74;
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12); box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
display: block; display: block;
margin: 0; margin: 0;
padding: 0; padding: 0;
position: fixed; position: fixed;
width: 250px; width: 250px;
z-index: 99999; z-index: 99999;
ul { ul {
list-style: none; list-style: none;
padding: 10px 0; padding: 10px 0;
margin: 0; margin: 0;
font-size: 12px; font-size: 12px;
font-weight: 600; font-weight: 600;
li { li {
margin: 0; margin: 0;
padding: 10px 35px; padding: 10px 35px;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
background: $blue600; background: $blue600;
color: $gray98; color: $gray98;
} }
} }
} }
} }
</style> </style>
+1 -1
View File
@@ -10,7 +10,7 @@
Right click on me Right click on me
</p> </p>
<vue-context ref="menu" :close-on-scroll="close"> <vue-context ref="menu" :close-on-scroll="close" :close-on-click="false">
<ul slot-scope="child"> <ul slot-scope="child">
<li @click="onClick(child.data)">Option 1 {{ child.data && child.data.foo }}</li> <li @click="onClick(child.data)">Option 1 {{ child.data && child.data.foo }}</li>
<li>Option 2</li> <li>Option 2</li>
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long