CSS/JS:改变滑动时的不透明度
Posted
技术标签:
【中文标题】CSS/JS:改变滑动时的不透明度【英文标题】:CSS/JS: Change opacity on swipe 【发布时间】:2016-11-15 22:46:39 【问题描述】:我想在滑动元素时更改其不透明度。
我想实现类似于 sn-p 中的动画,根据我的手指/光标在滑动时拖动元素的程度逐渐应用。
编辑:动画与在 android 中清除通知相同
我的第一个想法是处理拖动事件并根据元素的位置和屏幕的宽度更改不透明度。这是一个好的解决方案吗?有没有更好的,也许只有 CSS?我正在使用 ionic(我的元素是一个 ion-item),所以任何与 ionic/angular1 相关的东西都可以。
div.animated
width: 100px;
height: 100px;
background: red;
position: absolute;
top: 31px;
animation: right 2s;
animation-iteration-count: infinite;
animation-direction: alternate;
animation-timing-function: linear;
.back
width: 100px;
height: 100px;
border: 1px solid blue;
position: fixed;
top: 30px;
left: 50px;
@keyframes right
0%
left: 0px;
opacity: 0.1;
50% opacity: 1;
100% left: 100px;opacity:0.1
The blue frame is the screen and the red square is the dragged element
<div class="animated"></div>
<div class="back"></div>
【问题讨论】:
这是一个由谷歌工程师youtube.com/watch?v=F3A6Skckh9c制作的精彩视频 看看hammer.js 【参考方案1】:google chrome devs 的好心人发起了一场秀电话SuperCharged,该秀背后的想法是向您展示制作网络应用效果的快速简单的方法。
他们做了一个关于可刷卡的episode(大约一个小时长),他们做了一个简短的 10 分钟 episode 只是为了给你基本的想法。
要回答您的问题,javascript 是使其响应的唯一方法,CSS 不会响应用户输入或操作。
另外,在屏幕上移动东西时最好使用变换,而不是左。他们在节目中非常详细地解释了原因,但快速的原因是 transform 可以使用 GPU。
无论如何,这里是他们在剧集中制作的代码的现场演示,看一眼,看看它是否是你要找的。无论如何,我建议您观看他们的视频,您可以学到很多东西(我当然做到了)。
/**
Copyright 2016 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
*/
'use strict';
class Cards
constructor()
this.cards = Array.from(document.querySelectorAll('.card'));
this.onStart = this.onStart.bind(this);
this.onMove = this.onMove.bind(this);
this.onEnd = this.onEnd.bind(this);
this.update = this.update.bind(this);
this.targetBCR = null;
this.target = null;
this.startX = 0;
this.currentX = 0;
this.screenX = 0;
this.targetX = 0;
this.draggingCard = false;
this.addEventListeners();
requestAnimationFrame(this.update);
addEventListeners()
document.addEventListener('touchstart', this.onStart);
document.addEventListener('touchmove', this.onMove);
document.addEventListener('touchend', this.onEnd);
document.addEventListener('mousedown', this.onStart);
document.addEventListener('mousemove', this.onMove);
document.addEventListener('mouseup', this.onEnd);
onStart(evt)
if (this.target)
return;
if (!evt.target.classList.contains('card'))
return;
this.target = evt.target;
this.targetBCR = this.target.getBoundingClientRect();
this.startX = evt.pageX || evt.touches[0].pageX;
this.currentX = this.startX;
this.draggingCard = true;
this.target.style.willChange = 'transform';
evt.preventDefault();
onMove(evt)
if (!this.target)
return;
this.currentX = evt.pageX || evt.touches[0].pageX;
onEnd(evt)
if (!this.target)
return;
this.targetX = 0;
let screenX = this.currentX - this.startX;
if (Math.abs(screenX) > this.targetBCR.width * 0.35)
this.targetX = (screenX > 0) ? this.targetBCR.width : -this.targetBCR.width;
this.draggingCard = false;
update()
requestAnimationFrame(this.update);
if (!this.target)
return;
if (this.draggingCard)
this.screenX = this.currentX - this.startX;
else
this.screenX += (this.targetX - this.screenX) / 4;
const normalizedDragDistance =
(Math.abs(this.screenX) / this.targetBCR.width);
const opacity = 1 - Math.pow(normalizedDragDistance, 3);
this.target.style.transform = `translateX($this.screenXpx)`;
this.target.style.opacity = opacity;
// User has finished dragging.
if (this.draggingCard)
return;
const isNearlyAtStart = (Math.abs(this.screenX) < 0.1);
const isNearlyInvisible = (opacity < 0.01);
// If the card is nearly gone.
if (isNearlyInvisible)
// Bail if there's no target or it's not attached to a parent anymore.
if (!this.target || !this.target.parentNode)
return;
this.target.parentNode.removeChild(this.target);
const targetIndex = this.cards.indexOf(this.target);
this.cards.splice(targetIndex, 1);
// Slide all the other cards.
this.animateOtherCardsIntoPosition(targetIndex);
else if (isNearlyAtStart)
this.resetTarget();
animateOtherCardsIntoPosition(startIndex)
// If removed card was the last one, there is nothing to animate. Remove target.
if (startIndex === this.cards.length)
this.resetTarget();
return;
const frames = [
transform: `translateY($this.targetBCR.height + 20px)`
,
transform: 'none'
];
const options =
easing: 'cubic-bezier(0,0,0.31,1)',
duration: 150
;
const onAnimationComplete = () => this.resetTarget();
for (let i = startIndex; i < this.cards.length; i++)
const card = this.cards[i];
// Move the card down then slide it up.
card
.animate(frames, options)
.addEventListener('finish', onAnimationComplete);
resetTarget()
if (!this.target)
return;
this.target.style.willChange = 'initial';
this.target.style.transform = 'none';
this.target = null;
window.addEventListener('load', () => new Cards());
/**
Copyright 2016 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
*/
html,
body
margin: 0;
padding: 0;
background: #FAFAFA;
font-family: Arial;
font-size: 30px;
color: #333;
*
box-sizing: border-box;
.card-container
width: 100%;
max-width: 450px;
padding: 16px;
margin: 0 auto;
.card
background: #FFF;
border-radius: 3px;
box-shadow: 0 3px 4px rgba(0, 0, 0, 0.3);
margin: 20px 0;
height: 120px;
display: flex;
align-items: center;
justify-content: space-around;
cursor: pointer;
<!--
https://github.com/GoogleChrome/ui-element-samples/tree/master/swipeable-cards
https://www.youtube.com/watch?v=rBSY7BOYRo4
/**
*
* Copyright 2016 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<div class="card-container">
<div class="card">Das Surma</div>
<div class="card">Aerotwist</div>
<div class="card">Kinlanimus Maximus</div>
<div class="card">Addyoooooooooo</div>
<div class="card">Gaunty McGaunty Gaunt</div>
<div class="card">Jack Archibungle</div>
<div class="card">Sam "The Dutts" Dutton</div>
</div>
【讨论】:
非常感谢您的回复!不知道这个节目,看起来真的很棒!这是一个有趣的解决方案,它帮助我编写了使用 ionic 指令on-drag
和 on-release
的我。【参考方案2】:
Ansrew's 非常有用。在 Ionic 中,使用 onDrag
和 onRelease
指令更容易。
<ion-item on-drag="onDrag($event)" on-release="onRelease($event)" />
并使用这些方法来设置 ion-item 的样式:
function onDrag (e)
var element = e.currentTarget.childNodes[0];
var screenW = element.offsetWidth;
var threshold = screenW * 0.16;
var delta = Math.abs(e.gesture.deltaX);
if(delta >= threshold)
var normalizedDragDistance = (Math.abs(delta) / screenW);
var opacity = 1 - Math.pow(normalizedDragDistance, 0.7);
element.style.opacity = opacity;
else
e.currentTarget.childNodes[0].style.opacity = 1;
function onRelease (e)
e.currentTarget.childNodes[0].style.opacity = 1;
【讨论】:
以上是关于CSS/JS:改变滑动时的不透明度的主要内容,如果未能解决你的问题,请参考以下文章