animate + ng-repeat 优雅的解决方案?
animate + ng-repeat in an elegant solution?
我有一个用 ng-repeat
构建的列表,我正在尝试在元素改变位置时为列表设置动画。
我试图将这个想法建立在 this codepen 的基础上,但是,我一直没有很好地让它发挥作用。
需要发生的是:
- 用户点击图钉
- 如果 pin 是灰色的(现在是红色的),固定的项目需要转到列表的顶部(在其过滤范围内)
- 如果引脚是红色的,现在是灰色的,它需要在其范围内的所有红色引脚下方。
- 需要为这种情况制作动画,用户可以看到新的红色图钉到达新位置,反之亦然,新的灰色图钉到达新位置。
如果有人能帮助我,那就太棒了。
This is what I have been working with (JSFiddle)
控制器
angular.module('MyApp', ['ngAnimate'])
.controller('App', function($scope){
$scope.myData = [{
id: 1,
historyContact: [
{
"date": "2017-05-30T04:00:00.000Z",
"time": "12:12pm",
"method": "Incoming",
"direction": "Inbound",
"result": "answered",
"notes": "a",
"pin": true,
"_id": 1
}, {
"date": "2017-05-30T04:00:00.000Z",
"time": "12:12pm",
"method": "Incoming",
"result": "answered",
"direction": "Inbound",
"notes": "b",
"pin": false,
"_id": 2
}, {
"date": "2017-05-30T04:00:00.000Z",
"time": "12:12pm",
"method": "Incoming",
"result": "answered",
"direction": "Inbound",
"notes": "c",
"pin": false,
"_id": 3
}
]
}];
$scope.noteClicked = function(note) {
console.log("clicked", note)
if (note.pin == true) {
note.pin = false;
} else {
note.pin = true;
}
};
});
模板
<div ng-controller="App" >
<p>
<p>
<div class="note-wrapper itemPin" ng-repeat="note in myData[0].historyContact | orderBy: ['-pin', '-date' ] track by note._id">
<div class="contact-history-date-device-wrapper">
<p class="contact-history-date-device-text">
{{note.date | date:'MMMM dd, yyyy'}} - {{note.time}}
</p>
</div>
<div class="chat-wrap">
<p class="chat-identifier">
{{note.method}} | {{note.direction}}
</p>
<p class="chat-identifier">
Contact Result: {{note.result}}
</p>
</div>
<div class="pin-container">
<div >
<div ng-if="note.pin == true" >
<img class="pin" src="http://i.imgur.com/QdFPdjY.png" ng-click="noteClicked(note)">
</div>
<div ng-if="note.pin == false" >
<img class="pin" src="http://i.imgur.com/nNpprk2.png" ng-click="noteClicked(note)">
</div>
</div>
</div>
<div class="contact-history-note-text-wrapper">
<p class="contact-history-note-atext">
{{note.notes}}
</p>
</div>
<hr>
</div>
</div>
样式
$font-stack: 'Roboto', sans-serif;
.metawrapper {
position: relative;
}
.scrollbox-contact {
width:100%;
// no needed because #grid-container--ui-view has already overflow scroll param by kei
/*
overflow:auto;
*/
overflow-x: hidden;
height: 100%;
position: absolute;
padding-top: 50px; /* header height*/
top: 0px;
}
.contact-history-header {
background-color: #F8F8F8;
height: 50px;
width: 100%;
position: absolute;
top: 0px;
left: 0px;
}
.header-title {
font-family: $font-stack;
font-size: 15px;
color: #364350;
font-weight: 400;
text-align: left;
line-height: 50px;
letter-spacing: 1px;
margin-left: 30px;
}
.pencil-icon {
position: relative;
margin-left: 20px;
margin-top: 15px;
}
.contact-history-date-device-text {
font-family: $font-stack;
font-size: 16px;
font-weight: 500;
color: rgb(80, 92, 100);
text-transform: capitalize;
}
.contact-history-date-device-wrapper {
margin-top: 25px;
margin-left: 25px;
display: inline-block;
}
.contact-history-note-text-wrapper {
height: auto;
width: 80%;
overflow: hidden;
margin-left: 25px;
display: block;
position: relative;
bottom: 5px;
margin-top: 4px;
}
.contact-history-note-text {
font-family: 'Lato', sans-serif;
font-weight: 400;
color: #505C64;
// height: 14px;
}
.contact-history-horizontal-line {
height: 1px;
width: 90%;
margin-left: 5%;
margin-right: 5%;
background-color: rgba(80, 92, 100, 0.1);
margin-top: 20px;
margin-bottom: 20px;
}
.contact-history-horizontal-line2 {
height: 1px;
width: 85%;
margin-left: 5%;
margin-right: 10%;
background-color: rgba(80, 92, 100, 0.1);
margin-top: 40px;
margin-bottom: 30px;
}
.contact-history-button {
width: 175px;
height: 36px;
border-radius: 3px;
border: 1px solid;
border-color: rgba(119, 119, 119, 0.4);
position: relative;
left: 75%;
bottom: 20px;
}
// ANIMATION FOR PIN MOVEMENT
// like .list-item in the animation walkthough
.note-wrapper {
&:after {
clear: both;
content: '';
display: block;
}
&.ng-move {
animation: list-sort-flip-top 0.4s ease-in;
transform: translate(0, 100%);
z-index: 2;
& + .note-wrapper {
transform: translate(0, -100%);
z-index: -1;
}
&.ng-move-active {
& + .note-wrapper {
animation: list-sort-flip-bottom 0.4s ease-in;
}
}
}
}
@keyframes list-sort-flip-top {
0% {
transform: rotate(0) translate(0, 100%) rotate(0);
}
50% {
transform: rotate(45deg) translate(0, 50%) rotate(-45deg)
}
100% {
transform: rotate(90deg) translate(0, 0) rotate(-90deg)
}
}
@keyframes list-sort-flip-bottom {
0% {
transform: rotate(0) translate(0, -100%) rotate(0);
}
50% {
transform: rotate(45deg) translate(0, -50%) rotate(-45deg);
}
100% {
transform: rotate(90deg) translate(0, 0) rotate(-90deg);
}
}
@keyframes list-sort-slide-top {
0% {
transform:translate(0, 100%);
}
75% {
transform:translate(0, 100%);
}
100% {
transform:translate(0, 0);
}
}
@keyframes list-sort-slide-bottom {
0% {
transform: translate(0, -100%);
}
25% {
transform: translate(100%, -100%);
}
75% {
transform: translate(100%, 80%);
}
80% {
transform: translate(90%, 60%) skew(-50deg, 1deg);
}
100% {
transform: translate(0, 0) skew(0, 0);
}
}
//END ANIMATIONB
.edit-note-wrapper {
display: none;
margin-left: 20px;
margin-top: 20px;
width: 100%;
}
.save-btn {
left: 1% !important;
}
.edit-contact-history-button {
width: 25%;
height: 36px;
border-radius: 3px;
border: 1px solid;
border-color: rgba(119, 119, 119, 0.4);
display: inline-block !important;
position: relative;
}
.chat-identifier {
font-size: 14px;
font-family: $font-stack;
font-weight: 300;
color: #505C64;
}
.chat-wrap {
position: relative;
left: 25px;
top: 5px;
}
.pin-container {
position: relative;
left: 90%;
bottom: 35px;
}
.who-wrote-this {
position: relative;
left: 25%;
p {
color: #3da5d9;
font-weight: 500;
font-family: $font-stack;
}
}
.pin {
cursor: pointer;
cursor: hand;
}
.patient-info-blue88 {
width: 160px;
height: 40px;
border: 1px solid;
border-radius: 4px;
color: white;
background-color: #3DA5D9;
border-color: #3DA5D9;
position: relative;
right: 6px;
bottom: 60px;
cursor: pointer;
float: right;
cursor: hand;
}
.itemPin {
-webkit-transition: top 1s ease-out, opacity 1s;
-moz-transition: top 1s ease-out, opacity 1s;
}
我添加了带有时间戳的位置字段来控制音符位置,还请注意 CSS 类 用于 ng-move,ng-active 等。您可以按顺序修改它让它更花哨
CSS:
.ng-enter {
-webkit-transition: s;
transition: 1s;
margin-top: 100%;
}
.ng-enter-active {
margin-top: 0;
}
.ng-leave {
-webkit-transition: 1s;
transition: 1s;
margin-top: 0;
}
.ng-leave-active {
margin-top: 100%;
}
.ng-move {
-webkit-transition: 1s;
transition: 1s;
background: gold;
}
.ng-move-active {
background: #fff;
}
这是工作 fiddle:
我有一个用 ng-repeat
构建的列表,我正在尝试在元素改变位置时为列表设置动画。
我试图将这个想法建立在 this codepen 的基础上,但是,我一直没有很好地让它发挥作用。
需要发生的是:
- 用户点击图钉
- 如果 pin 是灰色的(现在是红色的),固定的项目需要转到列表的顶部(在其过滤范围内)
- 如果引脚是红色的,现在是灰色的,它需要在其范围内的所有红色引脚下方。
- 需要为这种情况制作动画,用户可以看到新的红色图钉到达新位置,反之亦然,新的灰色图钉到达新位置。
如果有人能帮助我,那就太棒了。
This is what I have been working with (JSFiddle)
控制器
angular.module('MyApp', ['ngAnimate'])
.controller('App', function($scope){
$scope.myData = [{
id: 1,
historyContact: [
{
"date": "2017-05-30T04:00:00.000Z",
"time": "12:12pm",
"method": "Incoming",
"direction": "Inbound",
"result": "answered",
"notes": "a",
"pin": true,
"_id": 1
}, {
"date": "2017-05-30T04:00:00.000Z",
"time": "12:12pm",
"method": "Incoming",
"result": "answered",
"direction": "Inbound",
"notes": "b",
"pin": false,
"_id": 2
}, {
"date": "2017-05-30T04:00:00.000Z",
"time": "12:12pm",
"method": "Incoming",
"result": "answered",
"direction": "Inbound",
"notes": "c",
"pin": false,
"_id": 3
}
]
}];
$scope.noteClicked = function(note) {
console.log("clicked", note)
if (note.pin == true) {
note.pin = false;
} else {
note.pin = true;
}
};
});
模板
<div ng-controller="App" >
<p>
<p>
<div class="note-wrapper itemPin" ng-repeat="note in myData[0].historyContact | orderBy: ['-pin', '-date' ] track by note._id">
<div class="contact-history-date-device-wrapper">
<p class="contact-history-date-device-text">
{{note.date | date:'MMMM dd, yyyy'}} - {{note.time}}
</p>
</div>
<div class="chat-wrap">
<p class="chat-identifier">
{{note.method}} | {{note.direction}}
</p>
<p class="chat-identifier">
Contact Result: {{note.result}}
</p>
</div>
<div class="pin-container">
<div >
<div ng-if="note.pin == true" >
<img class="pin" src="http://i.imgur.com/QdFPdjY.png" ng-click="noteClicked(note)">
</div>
<div ng-if="note.pin == false" >
<img class="pin" src="http://i.imgur.com/nNpprk2.png" ng-click="noteClicked(note)">
</div>
</div>
</div>
<div class="contact-history-note-text-wrapper">
<p class="contact-history-note-atext">
{{note.notes}}
</p>
</div>
<hr>
</div>
</div>
样式
$font-stack: 'Roboto', sans-serif;
.metawrapper {
position: relative;
}
.scrollbox-contact {
width:100%;
// no needed because #grid-container--ui-view has already overflow scroll param by kei
/*
overflow:auto;
*/
overflow-x: hidden;
height: 100%;
position: absolute;
padding-top: 50px; /* header height*/
top: 0px;
}
.contact-history-header {
background-color: #F8F8F8;
height: 50px;
width: 100%;
position: absolute;
top: 0px;
left: 0px;
}
.header-title {
font-family: $font-stack;
font-size: 15px;
color: #364350;
font-weight: 400;
text-align: left;
line-height: 50px;
letter-spacing: 1px;
margin-left: 30px;
}
.pencil-icon {
position: relative;
margin-left: 20px;
margin-top: 15px;
}
.contact-history-date-device-text {
font-family: $font-stack;
font-size: 16px;
font-weight: 500;
color: rgb(80, 92, 100);
text-transform: capitalize;
}
.contact-history-date-device-wrapper {
margin-top: 25px;
margin-left: 25px;
display: inline-block;
}
.contact-history-note-text-wrapper {
height: auto;
width: 80%;
overflow: hidden;
margin-left: 25px;
display: block;
position: relative;
bottom: 5px;
margin-top: 4px;
}
.contact-history-note-text {
font-family: 'Lato', sans-serif;
font-weight: 400;
color: #505C64;
// height: 14px;
}
.contact-history-horizontal-line {
height: 1px;
width: 90%;
margin-left: 5%;
margin-right: 5%;
background-color: rgba(80, 92, 100, 0.1);
margin-top: 20px;
margin-bottom: 20px;
}
.contact-history-horizontal-line2 {
height: 1px;
width: 85%;
margin-left: 5%;
margin-right: 10%;
background-color: rgba(80, 92, 100, 0.1);
margin-top: 40px;
margin-bottom: 30px;
}
.contact-history-button {
width: 175px;
height: 36px;
border-radius: 3px;
border: 1px solid;
border-color: rgba(119, 119, 119, 0.4);
position: relative;
left: 75%;
bottom: 20px;
}
// ANIMATION FOR PIN MOVEMENT
// like .list-item in the animation walkthough
.note-wrapper {
&:after {
clear: both;
content: '';
display: block;
}
&.ng-move {
animation: list-sort-flip-top 0.4s ease-in;
transform: translate(0, 100%);
z-index: 2;
& + .note-wrapper {
transform: translate(0, -100%);
z-index: -1;
}
&.ng-move-active {
& + .note-wrapper {
animation: list-sort-flip-bottom 0.4s ease-in;
}
}
}
}
@keyframes list-sort-flip-top {
0% {
transform: rotate(0) translate(0, 100%) rotate(0);
}
50% {
transform: rotate(45deg) translate(0, 50%) rotate(-45deg)
}
100% {
transform: rotate(90deg) translate(0, 0) rotate(-90deg)
}
}
@keyframes list-sort-flip-bottom {
0% {
transform: rotate(0) translate(0, -100%) rotate(0);
}
50% {
transform: rotate(45deg) translate(0, -50%) rotate(-45deg);
}
100% {
transform: rotate(90deg) translate(0, 0) rotate(-90deg);
}
}
@keyframes list-sort-slide-top {
0% {
transform:translate(0, 100%);
}
75% {
transform:translate(0, 100%);
}
100% {
transform:translate(0, 0);
}
}
@keyframes list-sort-slide-bottom {
0% {
transform: translate(0, -100%);
}
25% {
transform: translate(100%, -100%);
}
75% {
transform: translate(100%, 80%);
}
80% {
transform: translate(90%, 60%) skew(-50deg, 1deg);
}
100% {
transform: translate(0, 0) skew(0, 0);
}
}
//END ANIMATIONB
.edit-note-wrapper {
display: none;
margin-left: 20px;
margin-top: 20px;
width: 100%;
}
.save-btn {
left: 1% !important;
}
.edit-contact-history-button {
width: 25%;
height: 36px;
border-radius: 3px;
border: 1px solid;
border-color: rgba(119, 119, 119, 0.4);
display: inline-block !important;
position: relative;
}
.chat-identifier {
font-size: 14px;
font-family: $font-stack;
font-weight: 300;
color: #505C64;
}
.chat-wrap {
position: relative;
left: 25px;
top: 5px;
}
.pin-container {
position: relative;
left: 90%;
bottom: 35px;
}
.who-wrote-this {
position: relative;
left: 25%;
p {
color: #3da5d9;
font-weight: 500;
font-family: $font-stack;
}
}
.pin {
cursor: pointer;
cursor: hand;
}
.patient-info-blue88 {
width: 160px;
height: 40px;
border: 1px solid;
border-radius: 4px;
color: white;
background-color: #3DA5D9;
border-color: #3DA5D9;
position: relative;
right: 6px;
bottom: 60px;
cursor: pointer;
float: right;
cursor: hand;
}
.itemPin {
-webkit-transition: top 1s ease-out, opacity 1s;
-moz-transition: top 1s ease-out, opacity 1s;
}
我添加了带有时间戳的位置字段来控制音符位置,还请注意 CSS 类 用于 ng-move,ng-active 等。您可以按顺序修改它让它更花哨
CSS:
.ng-enter {
-webkit-transition: s;
transition: 1s;
margin-top: 100%;
}
.ng-enter-active {
margin-top: 0;
}
.ng-leave {
-webkit-transition: 1s;
transition: 1s;
margin-top: 0;
}
.ng-leave-active {
margin-top: 100%;
}
.ng-move {
-webkit-transition: 1s;
transition: 1s;
background: gold;
}
.ng-move-active {
background: #fff;
}
这是工作 fiddle: