mirror of
https://github.com/Hopiu/vue-material.git
synced 2026-04-28 10:34:53 +00:00
recreate ripple component and add a global toggle to it
This commit is contained in:
parent
8db86ef04b
commit
08ea6313c6
4 changed files with 195 additions and 35 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import 'scopedQuerySelectorShim/dist/scopedQuerySelectorShim';
|
||||
import './mdInkRipple.vue';
|
||||
import mdInkRipple from './mdInkRipple.vue';
|
||||
|
||||
export default function install(Vue) {
|
||||
let rippleParentClass = 'md-ink-ripple';
|
||||
|
|
@ -116,31 +116,5 @@ export default function install(Vue) {
|
|||
});
|
||||
});
|
||||
|
||||
Vue.component('md-ink-ripple', {
|
||||
props: {
|
||||
mdDisabled: Boolean
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement('div', {
|
||||
staticClass: 'md-ink-ripple'
|
||||
});
|
||||
},
|
||||
watch: {
|
||||
mdDisabled() {
|
||||
if (this.mdDisabled) {
|
||||
unregisterMouseEvent(this.$el.parentNode);
|
||||
} else {
|
||||
createRipple(this.$el.parentNode, this.$el);
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (!this.mdDisabled) {
|
||||
createRipple(this.$el.parentNode, this.$el);
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
unregisterMouseEvent(this.$el.parentNode);
|
||||
}
|
||||
});
|
||||
Vue.component('md-ink-ripple', Vue.extend(mdInkRipple));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,25 +8,32 @@
|
|||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
mask-image: radial-gradient(circle, white 100%, black 100%);
|
||||
-webkit-mask-image: radial-gradient(circle, white 100%, black 100%);
|
||||
transition: $swift-ease-in;
|
||||
}
|
||||
|
||||
.md-ripple {
|
||||
position: absolute;
|
||||
transform: scale(0);
|
||||
background-color: currentColor;
|
||||
opacity: .26;
|
||||
border-radius: 50%;
|
||||
opacity: .2;
|
||||
transform: scale(0) translateZ(0);
|
||||
transition: none;
|
||||
will-change: background-color, opacity, transform, width, height, top, left;
|
||||
|
||||
&.md-fadeout {
|
||||
opacity: 0;
|
||||
transition: $swift-ease-out;
|
||||
transition-duration: .6s;
|
||||
}
|
||||
|
||||
&.md-active {
|
||||
animation: ripple 1s $swift-ease-out-timing-function;
|
||||
animation: ripple 1s $swift-ease-out-timing-function forwards;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ripple {
|
||||
to {
|
||||
transform: scale(1.5);
|
||||
opacity: 0;
|
||||
transform: scale(2.2) translateZ(0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1,179 @@
|
|||
<template>
|
||||
<div class="md-ink-ripple" v-if="!disabled">
|
||||
<div class="md-ripple" :class="classes" :style="styles" ref="ripple"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" src="./mdInkRipple.scss"></style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
mdDisabled: Boolean
|
||||
},
|
||||
data: () => ({
|
||||
rippleElement: null,
|
||||
parentElement: null,
|
||||
parentDimensions: {
|
||||
width: null,
|
||||
height: null,
|
||||
top: null,
|
||||
left: null
|
||||
},
|
||||
awaitingComplete: false,
|
||||
hasCompleted: false,
|
||||
fadeOut: false,
|
||||
active: false
|
||||
}),
|
||||
computed: {
|
||||
classes() {
|
||||
return {
|
||||
'md-fadeout': this.fadeOut,
|
||||
'md-active': this.active
|
||||
};
|
||||
},
|
||||
styles() {
|
||||
return {
|
||||
width: this.parentDimensions.width,
|
||||
height: this.parentDimensions.height,
|
||||
top: this.parentDimensions.top,
|
||||
left: this.parentDimensions.left
|
||||
};
|
||||
},
|
||||
disabled() {
|
||||
return this.mdDisabled || !this.$material.inkRipple;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
disabled(disabled) {
|
||||
if (!disabled) {
|
||||
this.init();
|
||||
} else {
|
||||
this.destroy();
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
checkAvailablePositions(element) {
|
||||
const availablePositions = ['relative', 'absolute', 'fixed'];
|
||||
|
||||
return availablePositions.indexOf(getComputedStyle(element).position) > -1;
|
||||
},
|
||||
getClosestPositionedParent(element) {
|
||||
const parent = element.parentNode;
|
||||
|
||||
if (!element || !parent || parent.tagName.toLowerCase() === 'body') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.checkAvailablePositions(element)) {
|
||||
return element;
|
||||
}
|
||||
|
||||
return this.getClosestPositionedParent(element.parentNode);
|
||||
},
|
||||
getParentSize() {
|
||||
const parent = this.parentElement;
|
||||
|
||||
return Math.round(Math.max(parent.offsetWidth, parent.offsetHeight)) + 'px';
|
||||
},
|
||||
getClickPosition(event) {
|
||||
const rect = this.parentElement.getBoundingClientRect();
|
||||
const top = event.pageY - rect.top - this.$refs.ripple.offsetHeight / 2 - document.body.scrollTop + 'px';
|
||||
const left = event.pageX - rect.left - this.$refs.ripple.offsetWidth / 2 - document.body.scrollLeft + 'px';
|
||||
|
||||
return {
|
||||
top,
|
||||
left
|
||||
};
|
||||
},
|
||||
setDimensions() {
|
||||
const size = this.getParentSize();
|
||||
|
||||
this.parentDimensions.width = size;
|
||||
this.parentDimensions.height = size;
|
||||
},
|
||||
setPositions(event) {
|
||||
const positions = this.getClickPosition(event);
|
||||
|
||||
this.parentDimensions.top = positions.top;
|
||||
this.parentDimensions.left = positions.left;
|
||||
},
|
||||
clearState() {
|
||||
this.active = false;
|
||||
this.fadeOut = false;
|
||||
this.hasCompleted = false;
|
||||
this.setDimensions();
|
||||
window.clearTimeout(this.awaitingComplete);
|
||||
document.body.removeEventListener('mouseup', this.endRipple);
|
||||
},
|
||||
startRipple(event) {
|
||||
window.requestAnimationFrame(() => {
|
||||
this.clearState();
|
||||
this.awaitingComplete = window.setTimeout(() => {
|
||||
this.hasCompleted = true;
|
||||
}, 400);
|
||||
|
||||
document.body.addEventListener('mouseup', this.endRipple);
|
||||
|
||||
this.setPositions(event);
|
||||
|
||||
window.setTimeout(() => {
|
||||
this.active = true;
|
||||
});
|
||||
});
|
||||
},
|
||||
endRipple() {
|
||||
if (this.hasCompleted) {
|
||||
this.fadeOut = true;
|
||||
} else {
|
||||
this.awaitingComplete = window.setTimeout(() => {
|
||||
this.fadeOut = true;
|
||||
}, 200);
|
||||
}
|
||||
|
||||
document.body.removeEventListener('mouseup', this.endRipple);
|
||||
},
|
||||
registerMouseEvent() {
|
||||
this.parentElement.addEventListener('mousedown', this.startRipple);
|
||||
},
|
||||
unregisterMouseEvent() {
|
||||
if (this.parentElement) {
|
||||
this.parentElement.removeEventListener('mousedown', this.startRipple);
|
||||
document.body.removeEventListener('mouseup', this.endRipple);
|
||||
}
|
||||
},
|
||||
init() {
|
||||
this.$nextTick(() => {
|
||||
this.rippleElement = this.$el;
|
||||
this.parentElement = this.getClosestPositionedParent(this.$el.parentNode);
|
||||
|
||||
if (!this.parentElement) {
|
||||
this.$destroy();
|
||||
} else {
|
||||
this.rippleElement.parentNode.removeChild(this.rippleElement);
|
||||
this.parentElement.appendChild(this.rippleElement);
|
||||
this.registerMouseEvent();
|
||||
this.setDimensions();
|
||||
}
|
||||
});
|
||||
},
|
||||
destroy() {
|
||||
if (this.rippleElement && this.rippleElement.parentNode) {
|
||||
this.unregisterMouseEvent();
|
||||
this.rippleElement.parentNode.removeChild(this.rippleElement);
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (!this.disabled) {
|
||||
this.init();
|
||||
} else {
|
||||
this.destroy();
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.destroy();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -121,7 +121,8 @@ export default function install(Vue) {
|
|||
Vue.material = new Vue({
|
||||
data: () => ({
|
||||
styles: [],
|
||||
currentTheme: null
|
||||
currentTheme: null,
|
||||
inkRipple: true
|
||||
}),
|
||||
methods: {
|
||||
registerTheme(name, spec) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue