最近在做uniapp项目,无奈小程序上对于vue的支持很有限,很多优秀的前端框架在小程序环境下都不能生效,点击效果这一块一直没时间整理,现在弄了一个凑合着还能看的效果分享一下
.ripple {
position: relative;
overflow: hidden;
}
.ripple:after {
content: "";
display: block;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
pointer-events: none;
background-image: radial-gradient(circle, #666 10%, transparent 60%);
background-repeat: no-repeat;
background-position: 50%;
transform: scale(10, 10);
opacity: 0;
transition: transform 0.8s, opacity 0.8s;
}
.ripple:active:after {
transform: scale(0, 0);
opacity: .1;
transition: 0s;
}
还有一个稍微复杂点的版本,这个需要全局注册才行
<template>
<view :id="'buttonRipple'+buttonRippleId" class="lu-button-ripple"
@tap="_tap">
<view class="button-content"><slot></slot></view>
<view class="ripple-cell"
v-for="item in rippleList"
:key="item.rippleId"
:id="item.rippleId"
:style="{ width: item.width + 'px', height: item.width + 'px', left: item.left + 'px', top: item.top + 'px','backgroundColor':rippleBackgroundColor,'opacity':rippleOpacity}"
:class="[item.startAnimate ?'ripple-animation' : '']"
></view>
</view>
</template>
<script>
export default {
name: 'lu-button-ripple',
props:{
buttonRippleId:{
type:[String,Number],
},
rippleBackgroundColor:{
type:String,
default:"#999"
},
rippleOpacity:{
type:Number,
default:0.05
}
},
data() {
return {
rippleList: [],
rippleId: 0,
};
},
methods: {
_tap(e) {
this._queryMultipleNodes("#buttonRipple"+this.buttonRippleId).then(res => {
const button = res[0],
viewPort = res[1];
const boxWidth = parseInt(button.width); // button的宽度
const boxHeight = parseInt(button.height); // button的长度
const rippleWidth = boxWidth > boxHeight ? boxWidth : boxHeight;
const rippleX = parseInt(e.touches[0].clientX)- button.left - rippleWidth / 2;
const rippleY = parseInt(e.touches[0].clientY) - button.top - rippleWidth / 2;
this.rippleList.push({
rippleId: `rippleCell-${this.buttonRippleId}-${this.rippleId++}`,
width: rippleWidth,
left: rippleX,
top: rippleY,
startAnimate: true
});
});
if (this.timer) {
clearTimeout(this.timer);
this.timer = setTimeout(this._deleteRipple, 300);
} else {
this.timer = setTimeout(this._deleteRipple, 300);
}
this.$emit("rippleTap",this.buttonRippleId);
},
_queryMultipleNodes(e) {
return new Promise((resolve, reject) => {
let view = uni.createSelectorQuery().in(this);
view.select(e).boundingClientRect();
view.selectViewport().scrollOffset();
view.exec(function (res) {
resolve(res);
});
})
},
_deleteRipple() {
this.rippleList = [];
clearTimeout(this.timer);
this.timer = null;
}
}
};
</script>
<style lang="scss">
/* #ifndef H5 */
lu-button-ripple {
position: absolute;
width: 100%;
height:100%;
left: 0;
top: 0;
right: 0;
bottom: 0;
overflow: hidden;
z-index: 0;
display: flex;
flex-flow: row wrap;
justify-content: center;
align-items: center;
}
/* #endif */
.lu-button-ripple{
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
right: 0;
bottom: 0;
overflow: hidden;
z-index: 0;
display: flex;
flex-flow: row wrap;
justify-content: center;
align-items: center;
.button-content{
display: flex;
flex-flow: row wrap;
justify-content: center;
align-items: center;
z-index: 1;
}
.ripple-cell {
border-radius: 100%;
background-color: rgba(#999,0.1);
left: 0px;
top: 0px;
opacity: 1;
transform: scale(1);
width: 10px;
height: 10px;
position: absolute;
z-index: 0;
}
.ripple-animation {
animation: ripple 2.5s ease-out;
animation-fill-mode: forwards;
}
}
@keyframes ripple {
0% {
transform: scale(0);
opacity: 0.2;
}
50% {
transform: scale(12);
opacity: 0.1;
}
100% {
transform: scale(24);
opacity: 0;
}
}
</style>