Skip to content

Commit

Permalink
complete 05 practice
Browse files Browse the repository at this point in the history
  • Loading branch information
soyaine committed Dec 30, 2016
1 parent 49e124e commit 34a3999
Show file tree
Hide file tree
Showing 5 changed files with 660 additions and 0 deletions.
91 changes: 91 additions & 0 deletions 05 - Flex Panel Gallery/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# 05 Flex 实现可伸缩的图片墙 中文指南

> 作者:©[缉熙Soyaine](https://github.com/soyaine)
> 简介:[JavaScript30](https://javascript30.com)[Wes Bos](https://github.com/wesbos) 推出的一个 30 天挑战。项目免费提供了 30 个视频教程、30 个挑战的起始文档和 30 个挑战解决方案源代码。目的是帮助人们用纯 JavaScript 来写东西,不借助框架和库,也不使用编译器和引用。现在你看到的是这系列指南的第 5 篇。完整指南在 [GitHub](https://github.com/soyaine/JavaScript30),喜欢请 Star 哦♪(^∇^*)
## 实现效果

![可伸缩的图片墙演示](https://d17oy1vhnax1f7.cloudfront.net/items/0t0Y0m3D1B1O3x3R2U1D/Screen%20recording%202016-12-30%20at%2006.17.47%20PM.gif)

点击五张图片中的任意一张时,图片展开,同时图片中心的文字上下分别移入文字。点击已经展开的图片,图片被压缩,同时图片中上下两端的文字被挤走。若图片加载不出来[请点链接。](https://d17oy1vhnax1f7.cloudfront.net/items/3J2r2G0p0C0h0q2c3R3p/Screen%20recording%202016-12-30%20at%2005.33.01%20PM.gif)

## 初始文档

首先描述一下文档的 DOM 结构:以 `.panels` 为父 `div` 之下,有 5 个类名为 `.panel``div`,这 5 个各含有 3 个子 `p` 标签。

```
.panels div
├── .panel, .panel1 div
| ├── p
| ├── p
| └── p
├── .panel, .panel2 div
| ├── p
| ├── p
| └── p
├── .panel, .panel3 div
| ├── p
| ├── p
| └── p
├── .panel, .panel4 div
| ├── p
| ├── p
| └── p
└── .panel, .panel5 div
├── p
├── p
└── p
```

display: flex;

border: 1px solid #f00;

## 延伸思考

在 index-FINISHED.html 的解决方案中,用了两种 `class` 值来分别控制 `div` 元素和 `p` 元素的动画,这就会造成一个问题,当快速点击两下时,会出现相反的组合(图片缩小 + 上下文字出现)。

那为什么还要将文字的移动动画用 `.open-actived` 这个类来控制,同时还多加上了一个 `transitionend` 的事件监听,而不是直接用 `.open` 控制文字的移动,并且只采用一个 `click` 事件监听呢?

我试了一下,发现如果将要触发的文字移动(`transform`)用 `.open` 来控制,那么会出现有点不协调的状况。

要找到问题所在,可以先研究一下动画效果,由于录 GIF 很容易掉帧,最好打开网页来看细节。

当拉伸图片时,首先往里压缩(阶段①),然后再展开(阶段②),而文字是阶段②出现的;而当压缩图片时,也是同样的道理,先微微拉开一点(阶段①),然后再往里缩(阶段②),文字也是在阶段②才往上移动的,这样就形成了一种被 pia 飞的效果。

这就解释了为什么我改动之后出现了不协调,此时看到的动画,像是文字主导了图片的压缩伸展,原因就是文字动画的时机不太对,找到了这个原因,就很好解决了。(见 [index-SOYAINE2.html]()

```css
.panel > * {
/* ... */
transition:transform 0.5s 0.7s;
}

.panel.open p:first-child {
transform: translateY(0);
}

.panel.open p:last-child {
transform: translateY(0);
}
```

```js
const panels = document.querySelectorAll('.panel');

function toggleOpen(e) {
this.classList.toggle('open');
}

panels.forEach( panel => panel.addEventListener('click', toggleOpen, false));
```

`p` 标签的文字动画效果延迟一下,添加 `transition` 属性的 `delay` 值,使其到图片变换的阶段②再发生,此处我选用了图片的动画最长时间 0.7s,圆满解决。

这样也就可以回答我最开始的疑问,为何要多添加一个 [`transitioned` 的事件监听](https://developer.mozilla.org/zh-CN/docs/Web/Events/transitionend),这个事件会在 `transition` 结束之后被触发,所以目的是先让图片的压缩拉伸完成,再移动文字。

也就是说,如果出去字体大小的变化,具体的动画细节其实是这样的:
- 图片展开:微微压缩一段距离 -> 展开图片 -> 文字向中心移动
- 图片压缩:微微展开一段距离 -> 压缩图片 -> 文字向上下移动

##### 挑战 5 Pass ~\(≧▽≦)/~
145 changes: 145 additions & 0 deletions 05 - Flex Panel Gallery/index-FINISHED.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Flex Panels 💪</title>
<link href='https://fonts.googleapis.com/css?family=Amatic+SC' rel='stylesheet' type='text/css'>
</head>
<body>
<style>
html {
box-sizing: border-box;
background:#ffc600;
font-family:'helvetica neue';
font-size: 20px;
font-weight: 200;
}
body {
margin: 0;
}
*, *:before, *:after {
box-sizing: inherit;
}

.panels {
min-height:100vh;
overflow: hidden;
display: flex;
}

.panel {
background:#6B0F9C;
box-shadow:inset 0 0 0 5px rgba(255,255,255,0.1);
color:white;
text-align: center;
align-items:center;
/* Safari transitionend event.propertyName === flex */
/* Chrome + FF transitionend event.propertyName === flex-grow */
transition:
font-size 0.7s cubic-bezier(0.61,-0.19, 0.7,-0.11),
flex 0.7s cubic-bezier(0.61,-0.19, 0.7,-0.11),
background 0.2s;
font-size: 20px;
background-size:cover;
background-position:center;
flex: 1;
justify-content: center;
display: flex;
flex-direction: column;
}


.panel1 { background-image:url(https://source.unsplash.com/gYl-UtwNg_I/1500x1500); }
.panel2 { background-image:url(https://source.unsplash.com/1CD3fd8kHnE/1500x1500); }
.panel3 { background-image:url(https://images.unsplash.com/photo-1465188162913-8fb5709d6d57?ixlib=rb-0.3.5&q=80&fm=jpg&crop=faces&cs=tinysrgb&w=1500&h=1500&fit=crop&s=967e8a713a4e395260793fc8c802901d); }
.panel4 { background-image:url(https://source.unsplash.com/ITjiVXcwVng/1500x1500); }
.panel5 { background-image:url(https://source.unsplash.com/3MNzGlQM7qs/1500x1500); }

/* Flex Items */
.panel > * {
margin:0;
width: 100%;
transition:transform 0.5s;
flex: 1 0 auto;
display:flex;
justify-content: center;
align-items: center;
}

.panel > *:first-child { transform: translateY(-100%); }
.panel.open-active > *:first-child { transform: translateY(0); }
.panel > *:last-child { transform: translateY(100%); }
.panel.open-active > *:last-child { transform: translateY(0); }

.panel p {
text-transform: uppercase;
font-family: 'Amatic SC', cursive;
text-shadow:0 0 4px rgba(0, 0, 0, 0.72), 0 0 14px rgba(0, 0, 0, 0.45);
font-size: 2em;
}
.panel p:nth-child(2) {
font-size: 4em;
}

.panel.open {
flex: 5;
font-size:40px;
}

.cta {
color:white;
text-decoration: none;
}

</style>


<div class="panels">
<div class="panel panel1">
<p>Hey</p>
<p>Let's</p>
<p>Dance</p>
</div>
<div class="panel panel2">
<p>Give</p>
<p>Take</p>
<p>Receive</p>
</div>
<div class="panel panel3">
<p>Experience</p>
<p>It</p>
<p>Today</p>
</div>
<div class="panel panel4">
<p>Give</p>
<p>All</p>
<p>You can</p>
</div>
<div class="panel panel5">
<p>Life</p>
<p>In</p>
<p>Motion</p>
</div>
</div>

<script>
const panels = document.querySelectorAll('.panel');

function toggleOpen() {
console.log('Hello');
this.classList.toggle('open');
}

function toggleActive(e) {
console.log(e.propertyName);
if (e.propertyName.includes('flex')) {
this.classList.toggle('open-active');
}
}

panels.forEach(panel => panel.addEventListener('click', toggleOpen));
panels.forEach(panel => panel.addEventListener('transitionend', toggleActive));
</script>

</body>
</html>
158 changes: 158 additions & 0 deletions 05 - Flex Panel Gallery/index-SOYAINE.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Flex Panels 💪</title>
<link href='https://fonts.googleapis.com/css?family=Amatic+SC' rel='stylesheet' type='text/css'>
</head>
<body>
<style>
html {
box-sizing: border-box;
background:#ffc600;
font-family:'helvetica neue';
font-size: 20px;
font-weight: 200;
}
body {
margin: 0;
}
*, *:before, *:after {
box-sizing: inherit;
}

.panels {
min-height:100vh;
overflow: hidden;
display: flex;
}

.panel {
background:#6B0F9C;
box-shadow:inset 0 0 0 5px rgba(255,255,255,0.1);
color:white;
text-align: center;
align-items:center;
/* Safari transitionend event.propertyName === flex */
/* Chrome + FF transitionend event.propertyName === flex-grow */
transition:
font-size 0.7s cubic-bezier(0.61,-0.19, 0.7,-0.11),
flex 0.7s cubic-bezier(0.61,-0.19, 0.7,-0.11),
background 0.2s;
font-size: 20px;
background-size:cover;
background-position:center;
flex: 1;
justify-content: center;
align-items: center;
display: flex;
flex-direction: column;
}


.panel1 { background-image:url(https://source.unsplash.com/gYl-UtwNg_I/1500x1500); }
.panel2 { background-image:url(https://source.unsplash.com/1CD3fd8kHnE/1500x1500); }
.panel3 { background-image:url(https://images.unsplash.com/photo-1465188162913-8fb5709d6d57?ixlib=rb-0.3.5&q=80&fm=jpg&crop=faces&cs=tinysrgb&w=1500&h=1500&fit=crop&s=967e8a713a4e395260793fc8c802901d); }
.panel4 { background-image:url(https://source.unsplash.com/ITjiVXcwVng/1500x1500); }
.panel5 { background-image:url(https://source.unsplash.com/3MNzGlQM7qs/1500x1500); }

.panel > * {
margin:0;
width: 100%;
transition:transform 0.5s;
/* 帮助辨认元素所在的区域*/
/* border: 1px solid #f00;*/
flex: 1 0 auto;
display: flex;
justify-content: center;
align-items: center;
}

.panel > *:first-child {
transform: translateY(-100%);
}

.panel.open-actived > *:first-child {
transform: translateY(0);
}

.panel > *:last-child {
transform: translateY(100%);
}

.panel.open-actived > *:last-child {
transform: translateY(0);
}

.panel p {
text-transform: uppercase;
font-family: 'Amatic SC', cursive;
text-shadow:0 0 4px rgba(0, 0, 0, 0.72), 0 0 14px rgba(0, 0, 0, 0.45);
font-size: 2em;
}
.panel p:nth-child(2) {
font-size: 4em;
}

.panel.open {
flex: 5;
font-size:40px;
}

.cta {
color:white;
text-decoration: none;
}

</style>


<div class="panels">
<div class="panel panel1">
<p>Hey</p>
<p>Let's</p>
<p>Dance</p>
</div>
<div class="panel panel2">
<p>Give</p>
<p>Take</p>
<p>Receive</p>
</div>
<div class="panel panel3">
<p>Experience</p>
<p>It</p>
<p>Today</p>
</div>
<div class="panel panel4">
<p>Give</p>
<p>All</p>
<p>You can</p>
</div>
<div class="panel panel5">
<p>Life</p>
<p>In</p>
<p>Motion</p>
</div>
</div>

<script>
const panels = document.querySelectorAll('.panel');

function toggleOpen() {
this.classList.toggle('open');
}

function toggleWord(e) {
console.log(e.propertyName);
if(e.propertyName.includes('flex')){
this.classList.toggle('open-actived');
}

}

panels.forEach(panel => panel.addEventListener('click', toggleOpen));
panels.forEach(panel => panel.addEventListener('transitionend', toggleWord));
</script>

</body>
</html>
Loading

0 comments on commit 34a3999

Please sign in to comment.