Last active
May 1, 2017 04:48
-
-
Save pjchender/72f1953ed2d2338a5988b934d64077ea to your computer and use it in GitHub Desktop.
[Flycan][Vue] CH3 - Part1(組件 component、轉場 transition、混合 mixin)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>03-01-registerComponent</title> | |
<link rel="stylesheet" type="text/css" href="css/normalize.css"> | |
<link rel="stylesheet" type="text/css" href="css/layout.css"> | |
<style type="text/css"> | |
[v-cloak]{ | |
display: none; | |
} | |
.global{ | |
color: blue | |
} | |
.local{ | |
color: red | |
} | |
.local .global{ | |
color: red | |
} | |
</style> | |
</head> | |
<body> | |
<div id="app" v-cloak> | |
<!-- 使用全域組件 --> | |
<global-component></global-component> | |
<!-- 使用區域組件 --> | |
<local-component></local-component> | |
</div> | |
<script src="js/vue.js"></script> | |
<script> | |
// 建立全域組件 | |
Vue.component('globalComponent', { | |
template: | |
` | |
<div class="global"> | |
globalComponent | |
</div> | |
` | |
}) | |
// 建立區域組件 | |
var localComponent = { | |
template: ` | |
<div class="local"> | |
<h1>localComponent</h1> | |
<global-component></global-component> | |
</div> | |
` | |
} | |
var vm = new Vue({ | |
el: '#app', | |
components: { | |
localComponent: localComponent | |
} | |
}) | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>03-02-componentData</title> | |
<link rel="stylesheet" type="text/css" href="css/normalize.css"> | |
<link rel="stylesheet" type="text/css" href="css/layout.css"> | |
<style type="text/css"> | |
[v-cloak]{ | |
display: none; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="app" v-cloak> | |
<!-- 使用 template --> | |
<counter></counter> | |
<counter></counter> | |
<counter></counter> | |
</div> | |
<script src="js/vue.js"></script> | |
<script> | |
// 代入資料到 component 中 | |
var data = function () { | |
return {count: 0} | |
} | |
// 製作 component | |
Vue.component('counter', { | |
data: data, | |
template: ` | |
<input type='button' | |
:value="count" | |
@click="count++" | |
> | |
` | |
}) | |
var vm = new Vue({ | |
el: '#app' | |
}) | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>03-03-propsEmit</title> | |
<link rel="stylesheet" type="text/css" href="css/normalize.css"> | |
<link rel="stylesheet" type="text/css" href="css/layout.css"> | |
<style type="text/css"> | |
[v-cloak]{ | |
display: none; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="app" v-cloak> | |
<!-- 父層組件 --> | |
<input type="button" :value="count" @click="count++"> | |
<!-- 子層組件 --> | |
<!-- 將父層的資料帶給子層 | |
1. :count-from-parent:在 HTML 中透過 v-bind 將資料從父層傳送到子層(在 HTML 中要使用 dash 命名) | |
2. props: ['countFromParent]:在 component 中透過 props 取得父層傳來的資料(在 JS 中使用駝峰式命名) | |
--> | |
<!-- 將子層的事件帶到父層 | |
1. @click="$emit('increment'),透過 $emit('自定義事件名稱', '資料'),將事件從子組件打到父組件 | |
2. @increment="count++",接收從 template 傳送過來的事件 | |
--> | |
<counter @increment="count++" :count-from-parent="count"></counter> | |
<counter @increment="count++" :count-from-parent="count"></counter> | |
<counter @increment="count++" :count-from-parent="count"></counter> | |
</div> | |
<script src="js/vue.js"></script> | |
<script> | |
var data = { | |
count: 0 | |
} | |
Vue.component('counter', { | |
props: ['countFromParent'], // 透過 props 接收從父組件傳送來的資料 | |
template: | |
// 程式中用單引號 | |
` | |
<input type="button" | |
:value="countFromParent" | |
@click="$emit('increment')" | |
> | |
` | |
}) | |
var vm = new Vue({ | |
el: '#app', | |
data: data | |
}) | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>03-04-slideShow</title> | |
<link rel="stylesheet" type="text/css" href="css/normalize.css"> | |
<link rel="stylesheet" type="text/css" href="css/layout.css"> | |
<link rel="stylesheet" type="text/css" href="css/03-04-slideShow.css"> | |
</head> | |
<body> | |
<div id="app" v-cloak> | |
<div class="container" v-if="imgList.length"> | |
<!-- SlideComponent | |
1. :active="active":將資料從父層傳到 component 中 | |
2. :img-list="imgList":將資料從父層傳到 component 中,記得要用 dash 命名 | |
3. @next="nextHandler":接收從子層打上來的 next 事件 | |
--> | |
<slide-component | |
:active="active" | |
:img-list="imgList" | |
@next="nextHandler" | |
></slide-component> | |
<!-- NavComponent | |
@change="changeHandler":接收從子層打上來的 change 事件 | |
--> | |
<nav-component | |
:active="active" | |
:total="imgList" | |
@change="changeHandler" | |
> | |
</nav-component> | |
</div> | |
</div> | |
<script src="js/vue.js"></script> | |
<script src="js/superagent.js"></script> | |
<script> | |
(function (window) { | |
var data = { | |
active: 0, | |
imgList: [ | |
'./images/children/0.jpg', | |
'./images/children/1.jpg', | |
'./images/children/2.jpg', | |
'./images/children/3.jpg', | |
'./images/children/4.jpg', | |
'./images/children/5.jpg', | |
'./images/children/6.jpg', | |
'./images/children/7.jpg' | |
] | |
} | |
var slideComponent = { | |
props: ['active', 'imgList'], // 使用父層傳來的資料 | |
template: | |
// 程式中的字串用單引號 | |
// @click="nextHandler",點一下圖片會換到下一張 | |
` | |
<div class="img" :style="{left: -100 * active + '%'}"> | |
<img | |
v-for="(item, index) in imgList" | |
:src="item" | |
:style="{left: 100 * index + '%'}" | |
@click="nextHandler" | |
> | |
</div> | |
`, | |
methods: { | |
nextHandler () { | |
this.$emit('next') // 打 next 事件到父層 | |
} | |
} | |
} | |
var navComponent = { | |
props: ['active', 'total'], | |
template: | |
// 點擊 nav 的時候要打事件到 root | |
` | |
<div class="nav"> | |
<a href="javascript:;" | |
v-for="(item, index) in total" | |
:class="{active: active === index}" | |
@click="clickHandler(index)" | |
> | |
</a> | |
</div> | |
`, | |
methods: { | |
clickHandler (index) { | |
this.$emit('change', index) | |
} | |
} | |
} | |
var vm = new Vue({ | |
el: '#app', | |
data: data, | |
components: { | |
slideComponent: slideComponent, | |
navComponent: navComponent | |
}, | |
methods: { | |
changeHandler (index) { | |
this.active = index | |
}, | |
nextHandler () { | |
this.active = (this.active + 1) % this.imgList.length | |
} | |
} | |
}) | |
})(window) | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>03-05-alphaShow</title> | |
<link rel="stylesheet" type="text/css" href="css/normalize.css"> | |
<link rel="stylesheet" type="text/css" href="css/layout.css"> | |
<style type="text/css"> | |
[v-cloak]{ | |
display: none; | |
} | |
.container{ | |
position: relative; | |
width: 550px; | |
padding-top: 300px; | |
overflow: hidden; | |
} | |
.img{ | |
position: absolute; | |
top:0%; | |
left:0%; | |
width: 100%; | |
height: 300px; | |
transition: left 0.5s; | |
} | |
.img > img{ | |
position: absolute; | |
top: 0%; | |
left: 0%; | |
} | |
.nav{ | |
text-align: center | |
} | |
.nav > a{ | |
display: inline-block; | |
width: 20px; | |
height: 20px; | |
border-radius: 10px; | |
margin: 5px; | |
background-color: white; | |
} | |
.nav > a.active{ | |
background-color: black; | |
} | |
/** | |
* 根據 transition 的 name 建立 Vue 中 transition 的 class | |
**/ | |
.fade-enter-active, .fade-leave-active { | |
transition: opacity .4s; | |
} | |
.fade-enter, .fade-leave-to { | |
opacity: 0; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="app" v-cloak> | |
<div class="container" v-if="imgList.length"> | |
<alpha-component | |
:active="active" | |
:list="imgList" | |
@next="nextHandler"> | |
</alpha-component> | |
<nav-component | |
:active="active" | |
:total="imgList.length" | |
@change="changeHandler"> | |
</nav-component> | |
</div> | |
</div> | |
<script src="js/vue.js"></script> | |
<script src="js/superagent.js"></script> | |
<script> | |
(function (window) { | |
var data = { | |
active: 0, | |
imgList: [ | |
'./images/children/0.jpg', | |
'./images/children/1.jpg', | |
'./images/children/2.jpg', | |
'./images/children/3.jpg', | |
'./images/children/4.jpg', | |
'./images/children/5.jpg', | |
'./images/children/6.jpg', | |
'./images/children/7.jpg' | |
] | |
} | |
var alphaComponent = { | |
props: ['active', 'list'], | |
template: | |
/** | |
* 一開始沒有淡入淡出的效果 | |
* 透過 <transition> 告訴 Vue 這裡要套用過渡狀態 | |
* name="fade",用來自定義 css 別名 | |
**/ | |
/** | |
* 把 v-if 改成 v-show,因為 v-if 在這裡會動態的改變 DOM 導致每次圖檔都需要重新 request 和重新載入 | |
* 而 v-show 會一次把圖檔全部載入,不用重複 request | |
**/ | |
/** | |
* 用 transition-group 的話,裡面的內容要加上 :key = "index" | |
* tag 告訴它外面要包的 tag 是 div (預設是 span) | |
**/ | |
` | |
<transition-group name="fade" appear class="img" @click="nextHandler" tag="div"> | |
<img :key="index" :src="item" v-show="active == index" v-for="(item,index) in list"> | |
</transition-group> | |
`, | |
methods: { | |
nextHandler: function () { | |
this.$emit('next') | |
} | |
} | |
} | |
var navComponent = { | |
props: ['active', 'total'], | |
template: ` | |
<div class="nav"> | |
<a href="javascript:;" v-for="index in total" | |
:class="{active : active == index-1}" | |
@click="clickHandler(index-1)"></a> | |
</div> | |
`, | |
methods: { | |
clickHandler: function (index) { | |
this.$emit('change', index) | |
} | |
} | |
} | |
var vm = new Vue({ | |
el: '#app', | |
data: data, | |
components: { | |
alphaComponent: alphaComponent, | |
navComponent: navComponent | |
}, | |
methods: { | |
changeHandler: function (index) { | |
this.active = index | |
}, | |
nextHandler: function () { | |
this.active = (this.active + 1) % this.imgList.length | |
} | |
} | |
}) | |
})(window) | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>03-06-mixin</title> | |
<link rel="stylesheet" type="text/css" href="css/normalize.css"> | |
<link rel="stylesheet" type="text/css" href="css/layout.css"> | |
<style type="text/css"> | |
[v-cloak]{ | |
display: none; | |
} | |
.container{ | |
position: relative; | |
width: 550px; | |
padding-top: 300px; | |
overflow: hidden; | |
} | |
.img{ | |
position: absolute; | |
top:0%; | |
left:0%; | |
width: 100%; | |
height: 300px; | |
transition: left 0.5s; | |
} | |
.img > img{ | |
position: absolute; | |
top: 0%; | |
left: 0%; | |
} | |
.nav{ | |
text-align: center | |
} | |
.nav > a{ | |
display: inline-block; | |
width: 20px; | |
height: 20px; | |
border-radius: 10px; | |
margin: 5px; | |
background-color: white; | |
} | |
.nav > a.active{ | |
background-color: black; | |
} | |
.fade-enter-active { | |
animation: fade-in .5s; | |
} | |
.fade-leave-active { | |
animation: fade-out .5s; | |
} | |
@keyframes fade-in { | |
0% { | |
opacity: 0; | |
} | |
50% { | |
opacity: 0.75; | |
} | |
100% { | |
opacity: 1; | |
} | |
} | |
@keyframes fade-out { | |
0% { | |
opacity: 1; | |
} | |
50% { | |
opacity: 0.75; | |
} | |
100% { | |
opacity: 0; | |
} | |
} | |
</style> | |
</head> | |
<body> | |
<div id="app" v-cloak> | |
<div class="container" v-if="imgList.length"> | |
<slide-component | |
:active="slide" | |
:list="imgList" | |
@next="nextHandler('slide')"> | |
</slide-component> | |
<nav-component | |
:active="slide" | |
:total="imgList.length" | |
@change="changeHandler($event,'slide')"> | |
</nav-component> | |
</div> | |
<div class="container" v-if="imgList.length"> | |
<alpha-component | |
:active="alpha" | |
:list="imgList" | |
@next="nextHandler('alpha')"> | |
</alpha-component> | |
<nav-component | |
:active="alpha" | |
:total="imgList.length" | |
@change="changeHandler($event,'alpha')"> | |
</nav-component> | |
</div> | |
</div> | |
<script src="js/vue.js"></script> | |
<script src="js/superagent.js"></script> | |
<script> | |
(function (window) { | |
var data = { | |
slide: 0, | |
alpha: 0, | |
imgList: [ | |
'./images/children/0.jpg', | |
'./images/children/1.jpg', | |
'./images/children/2.jpg', | |
'./images/children/3.jpg', | |
'./images/children/4.jpg', | |
'./images/children/5.jpg', | |
'./images/children/6.jpg', | |
'./images/children/7.jpg' | |
] | |
} | |
// 將重複的內容定義成 mixin | |
// 定義一個 mixin | |
var imgMixin = { | |
props: ['active', 'list'], | |
methods: { | |
nextHandler: function () { | |
this.$emit('next') | |
} | |
} | |
} | |
// 定義使用 mixin 物件的組件 | |
var slideComponent = { | |
mixins: [imgMixin], | |
template: ` | |
<div class="img" :style="{left:-100*active+'%'}" | |
@click="nextHandler"> | |
<img :src="item" v-for="(item,index) in list" | |
:style="{left:100*index+'%'}"> | |
</div> | |
` | |
} | |
var alphaComponent = { | |
mixins: [imgMixin], | |
template: ` | |
<div class="img" @click="nextHandler" style="overflow:hidden;"> | |
<transition name="fade" v-for="(item,index) in list" appear> | |
<img :src="item" v-if="active == index"> | |
</transition> | |
</div> | |
` | |
} | |
var navComponent = { | |
props: ['active', 'total'], | |
template: ` | |
<div class="nav"> | |
<a href="javascript:;" v-for="index in total" | |
:class="{active : active == index-1}" | |
@click="clickHandler(index-1)"></a> | |
</div> | |
`, | |
methods: { | |
clickHandler: function (index) { | |
this.$emit('change', index) | |
} | |
} | |
} | |
var vm = new Vue({ | |
el: '#app', | |
data: data, | |
components: { | |
slideComponent: slideComponent, | |
alphaComponent: alphaComponent, | |
navComponent: navComponent | |
}, | |
methods: { | |
changeHandler: function (index, type) { | |
this[type] = index | |
}, | |
nextHandler: function (type) { | |
this[type] = (this[type] + 1) % this.imgList.length | |
} | |
} | |
}) | |
})(window) | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>03-07-animateCss</title> | |
<link rel="stylesheet" type="text/css" href="css/normalize.css"> | |
<link rel="stylesheet" type="text/css" href="css/layout.css"> | |
<link rel="stylesheet" type="text/css" href="css/animate.min.css"> | |
<style type="text/css"> | |
[v-cloak]{ | |
display: none; | |
} | |
body{ | |
text-align: center; | |
} | |
a{ | |
display: inline-block; | |
text-decoration: none; | |
color: #0769AD; | |
background-color: #ffffff; | |
padding: 5px 10px; | |
font-size: 12px; | |
line-height: 20px; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="app" v-cloak> | |
<!-- | |
- 直接使用 css 的方式套用轉場效果 | |
- 這裡套用的是 animatedCSS | |
--> | |
<transition | |
enter-active-class="animated tada" | |
leave-active-class="animated tada" | |
> | |
<img :src="src" v-if="show"> | |
</transition> | |
<br> | |
<a href="javascript:;" @click="switchHandler">Switch</a> | |
</div> | |
<script src="js/vue.js"></script> | |
<script src="js/superagent.js"></script> | |
<script> | |
(function (window) { | |
var data = { | |
src: "./images/children/0.jpg", | |
show: true | |
} | |
var vm = new Vue({ | |
el: "#app", | |
data: data, | |
methods:{ | |
switchHandler: function () { | |
this.show = !this.show | |
} | |
} | |
}) | |
})(window) | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>03-05-alphaShow</title> | |
<link rel="stylesheet" type="text/css" href="css/normalize.css"> | |
<link rel="stylesheet" type="text/css" href="css/site.css"> | |
<style type="text/css"> | |
.active{ | |
font-weight: bolder; | |
color: #ffffff; | |
background-color: #40c297; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="app" v-cloak> | |
<header> | |
<h1>Flycan 飛肯設計學苑</h1> | |
<div> | |
<!-- 點擊的時候改變 view 的名稱 --> | |
<a href="javascript:;" | |
v-for="item in menu" | |
:class="{active:view == item.name}" | |
@click="view=item.name"> | |
{{item.text}} | |
</a> | |
</div> | |
</header> | |
<!-- :css="false" 解除 Vue 對 CSS 的偵測--> | |
<transition | |
@before-enter="beforeEnter" | |
@enter="enter" | |
@after-enter="afterEnter" | |
@leave="leave" | |
@after-leave="afterLeave" | |
:css="false" | |
> | |
<!-- 利用 v-bind:is="xxx" 選擇要顯示的 component --> | |
<component v-bind:is="view"></component> | |
</transition> | |
</div> | |
<script src="js/vue.js"></script> | |
<script src="js/velocity.min.js"></script> | |
<script> | |
(function(window){ | |
new Vue({ | |
el: '#app', | |
data: { | |
view: 'index', | |
menu:[ | |
{text:'首頁',name:'index'}, | |
{text:'課程',name:'course'}, | |
{text:'聯絡',name:'contact'}, | |
] | |
}, | |
components: { | |
'index': { | |
template: ` | |
<div class="page"> | |
<h2>首頁組件</h2> | |
</div> | |
` | |
}, | |
'course': { | |
template: ` | |
<div class="page"> | |
<h2>課程組件</h2> | |
</div> | |
` | |
}, | |
'contact': { | |
template: ` | |
<div class="page"> | |
<h2>聯絡組件</h2> | |
</div> | |
` | |
}, | |
}, | |
methods: { | |
// 準備需要的資料 | |
beforeEnter: function(el){ | |
el.style.opacity = 0 | |
el.style.position = 'absolute' // 避免兩個組件衝突,讓螢幕上一次指出現一個組件 | |
}, | |
// 動畫效果 | |
enter: function(el, done){ | |
Velocity(el, {opacity: 1}, { | |
duration: 500, | |
complete: done | |
}) | |
}, | |
// 對新的 DOM 綁定一些事件 | |
afterEnter: function (el, done) { | |
el.style.cssText = '' | |
}, | |
// 解除對 DOM 綁定的事件 | |
beforeLeave: function(){ | |
console.log('beforeLeave') | |
}, | |
// 動畫 | |
leave: function (el, done) { | |
Velocity(el, { opacity: 0 }, { | |
duration: 500 , | |
complete: done | |
}) | |
}, | |
// 清除不必要的資料 | |
afterLeave: function (el, done) { | |
console.log('component out') | |
} | |
} | |
}) | |
})(window) | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
03-08 使用 JavaScript 鉤子製作轉場效果
el
會自動回傳進退場的對象v-bind:css="false"
,Vue 會跳過 CSS 的檢測。這也可以避免過渡過程中 CSS 的影響。