Enjoy the Vue.js
@andywoodme
<html>
<head>
<title>My Fab App</title>
</head>
<body>
<my-fabulous-app></my-fabulous-app>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Fab App</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="app">
<my-fabulous-app></my-fabulous-app>
</div>
<script src="app.js"></script>
</body>
</html>
Vue.js can do this*
Vue.js 2.0
Progressive Web Framework
by Evan You
Less More
React Vue Angular Ember MeteorTemplating!
Engines
Backbone
<body>
<div id="app">
{{ name }}
</div>
<script src="vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
name: 'Hello!'
}
})
</script>
</body>
index.html
DOM
(Page)
Data
(State)
Reactive
<body>
<div id="app">
<input v-model="name">
{{ name }}
</div>
<script src="vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
name: 'Hello!'
}
})
</script>
</body>
index.html
<div id="app">
<select v-model="type">
<option value="icon-dice">Board Game</option>
<option value="icon-spades">Card Game</option>
</select>
<input v-model="name">
<p>
<span :class="type"></span>
{{ name }}
</p>
</div>
index.html
!
data: {
name: 'Snakes and Ladders',
type: 'icon-dice'
}
One-way text interpolation
!
{{ message }}
!
!
One-way binding
!
<option v-bind:selected="value">...</option>
!
!
Two-way binding
!
<input v-model="message">
</select>
<input v-model="game">
<button
@click="games.push({name: name, type: type})”>Add</button>
!
<p v-if="games.length == 0">Zarro Boords!</p>
<ul v-else>
<li v-for="game in games">
<span :class="game.type"></span>
{{ game.name }}
</li>
</ul>
</div>
index.html
!
data: {
name: 'Snakes and Ladders',
type: 'icon-dice',
games: []
}
<input v-model="name">
<button
@click="games.push({name: name, type: type})">Add</button>
<p v-if="empty">Zarro Boords!</p>
<ul v-else>
<li v-for="game in games">
!
index.html
!
data: {
name: '',
type: 'dice',
games: []
},
computed: {
empty: function() {
return this.games.length == 0
}
}
</select>
<input v-model="name" @keyup.enter="addGame">
<button @click="addGame">Add</button>
<p v-if="empty">Zarro Boords!</p>
<ul v-else>
!
index.html
computed: {
empty: function() {
return this.games.length == 0
}
},
methods: {
addGame: function () {
this.games.push({
name: this.name,
type: this.type
})
}
}
<select v-model="type">
<option value="dice">Board Game</option>
<option value="spades">Card Game</option>
</select>
:
:
<span :class="icon(game.type)"></span>
index.html
computed: {
empty: function() {
return this.games.length == 0
}
},
methods: {
icon: function (type) {
return 'icon-' + type
},
addGame: function () {
this.games.push({
<div id="app">
<select v-model="type">
<option value="dice">Board Game</option>
<option value="spades">Card Game</option>
</select>
<input v-model="name" @keyup.enter="addGame">
<button @click="addGame">Add</button>
<p v-if="empty">Zarro Boords!</p>
<ul v-else>
<li v-for="game in games">
<span :class="icon(game.type)"></span>
{{ game.name }}
</li>
</ul>
</div>
index.html
<script>
var app = new Vue({
el: '#app',
data: {
name: '',
type: 'dice',
games: []
},
computed: {
empty: function() {
return this.games.length == 0
}
},
methods: {
addGame: function () {
this.games.push({
name: this.name,
type: this.type
})
},
icon: function (type) {
return 'icon-' + type
}
}
})
</script>
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Fab App</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="app">
<my-fabulous-app></my-fabulous-app>
</div>
<script src="app.js"></script>
</body>
</html>
Components
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>iBoards</title>
<link rel="stylesheet" href="css/fonts.css">
</head>
<body>
<div id="app">
<board-library></board-library>
</div>
<script src="dist/app.js"></script>
</body>
</html>
index.html
var Vue = require('vue')
var BoardLibrary = require('./BoardLibrary.vue')
!
Vue.component('board-library', BoardLibrary)
var app = new Vue({
el: '#app'
})
main.js
<template>
<div>
<select v-model="type">
<option value="dice">Board Game</option>
:
</div>
</template>
!
<script>
module.exports = {
data: function() {
return {
game: '',
type: 'dice',
games: []
:
</script>
BoardLibrary.vue
!
// dependencies
var Vue = require('vue')
!
// module implementation
function myFunc() {
:
}
!
// exported
module.exports = {
myFunc: myFunc
}
CommonJS
Node / Server Side
BoardLibrary.vue
main.js
app.js
npm install -g vue-cli
vue init browserify-simple my-project
!
Using grunt or gulp already? vueify or vue-loader slot straight in
vue.js
Components
Component
Sub-components
Properties
:data="value"
props: ['data']
<p v-if="empty">Zarro Boords!</p>
<ul v-else>
<board-game
v-for="game in games"
:type="game.type"
:name="game.name"></board-game>
</ul>
BoardLibrary.vue
<script>
var BoardGame = require('./BoardGame.vue')
!
module.exports = {
data: function() {
:
components: {
BoardGame: BoardGame
}
}
</script>
<template>
<li>
<span :class="icon"></span>
{{ name }}
</li>
</template>
!
<script>
module.exports = {
props: [
'name',
'type'
],
computed: {
icon: function () {
return 'icon-' + this.type
}
}
}
</script>
BoardGame.vue
<ul>
<board-game
v-for="game in games"
:type="game.type"
:name=“game.name"></board-game>
</ul>
BoardLibrary.vue
!
props: ['name', ‘type’],
computed: { icon: ...
BoardGame.vue
<li>
<span :class="icon"></span>
{{ name }}
</li>
!
data: { games: [
{ name: 'Carcasonne', type: 'dice' },
{ name: 'Linkee', type: 'spade' }
] }
kebab
camel
Events
props: ['data']
@event="handler"
this.$emit('event')
:data="value"
<template>
<div>
<board-add @add="handleAdd"></board-add>
<p v-if="empty">Zarro Boords!</p>
<ul v-else>
<board-game v-for="game in games" :type="game.type" :name="game.name"></board-game>
</ul>
</div>
</template>
!
<script>
var BoardAdd = require('./BoardAdd.vue')
var BoardGame = require('./BoardGame.vue')
!
module.exports = {
data: function() {
return {
games: []
}
},
:
methods: {
handleAdd: function (game) {
this.games.push(game)
}
},
components: {
BoardAdd: BoardAdd,
BoardGame: BoardGame
}
}
</script>
BoardLibrary.vue
<template>
<div>
<select v-model="type">
<option value="dice">Board Game</option>
<option value="spades">Card Game</option>
</select>
<input v-model="name" @keyup.enter="add">
<button @click="add">Add</button>
</div>
</template>
!
<script>
module.exports = {
data: function() {
return {
name: '',
type: 'dice',
}
},
methods: {
add: function () {
this.$emit('add', {
name: this.name,
type: this.type
})
}
}
}
</script>
BoardAdd.vue
<template>
<span class="icon-bin" @click="del"></span>
</template>
!
<script>
module.exports = {
props: [
'index'
],
methods: {
del: function () {
this.$emit('delete', this.index)
}
}
}
</script>
BoardDelete.vue
<board-game
v-for="(game, index) in games"
:type="game.type"
:name="game.name">
<board-delete
:index="index"
@delete="handleDelete"></board-delete>
</board-game>
BoardLibrary.vue
methods: {
handleAdd: function (game) {
this.games.push(game)
},
handleDelete: function (index) {
this.games.splice(index, 1)
}
},
components: {
BoardDelete: BoardDelete,
<template>
<tr>
<td><span :class="icon"></span></td>
<td>{{ name }}</td>
<td><slot></slot></td>
</tr>
</template>
BoardGame.vue
<table v-else>
<thead>
<tr>
<board-sort
v-model="sortCol"
col="type">Type</board-sort>
<board-sort
v-model="sortCol"
col="name">Name</board-sort>
<th></th>
</tr>
</thead>
<tbody>
<board-game
v-for="game in sorted"
:type="game.type"
:name="game.name">
<board-delete
:index="game.index"
@delete="handleDelete"></board-delete>
</board-game>
</tbody>
</table>
BoardLibrary.vue
BoardLibrary.vue
data: function() {
return {
sortCol: 'type',
games: []
}
},
computed: {
sorted: function() {
// update each game with its index in the array
this.games.forEach(function (value, index) {
value.index = index
})
return _.sortBy(this.games, [this.sortCol])
},
:
!
_.sortBy(this.games, [this.sortCol])
!
[
{ name: 'Codenames', type: 'Card', index: 2 },
{ name: 'Snake Oil', type: ‘Card', index: 0 },
{ name: 'Star Wars', type: 'Board', index: 1 }
]
games: [
{ name: 'Snake Oil', type: 'Card' },
{ name: 'Star Wars', type: 'Board' },
{ name: 'Codenames', type: 'Card' }
],
sortCol: 'name'
sorted()
data
<board-game v-for="game in sorted" ...>
<button class="button-primary"
:disabled="blankName"
@click="add">Add</button>
BoardAdd.vue
computed: {
blankName: function() {
return this.name.trim().length == 0
}
},
methods: {
add: function () {
if (!this.blankName) {
this.$emit('add', {
name: this.name.trim(),
type: this.type
})
this.name = ''
}
}
},
mounted: function() {
this.$refs.name.focus()
}
BoardAdd.vue
}
</script>
!
<style scoped>
input,
select {
width: 100%;
}
button {
margin-top: 2.9rem;
}
button[disabled] {
opacity: 0.5;
}
button[disabled]:hover {
background-color: #33C3F0;
border-color: #33C3F0;
}
</style>
1. It’s Approachable
Alice Bartlett
Origami Components Lead, FT
2. Single File Components
concern
concern
concern
concern
concern
concern
concern
concern
concern
concern
3. Incremental Adoptability
more Library-ish than Framework-esque
Vue Resource
!
Vue Router
!
Vuex
AJAXy GET/POSTs
!
Single Page App URLs
!
State Machine
4. Plays well with Others
<script lang="coffee">
module.exports =
props: ['options']
methods:
sort: (event) ->
@$emit ‘change' event.target.value
</script>
!
<style lang="sass">
@import "components";
div.dashboard-sort {
margin-right: 1.45em;
margin-bottom: 1em;
@include select(1.25em);
}
</style>
5. Goes with the Grain
One of Ruby’s friends really makes her crazy. When they try to
wrap Christmas presents together Ruby wants to be creative
and have many different ways of using the wrapping paper. 
!
- No, says Django. 
There is one - and only one - obvious way to wrap a present. 
Gotchas
google vue events
!
use of this.
!
array manipulations
</thead>
<transition-group name="board-list" tag="tbody">
<board-game
v-for="game in sorted"
:type="game.type"
:name="game.name"
:key="game.id">
<board-delete
:id="game.id"
@delete="handleDelete"></board-delete>
</board-game>
</transition-group>
</table>
BoardLibrary.vue
methods: {
handleAdd: function (game) {
game.id = idGenerator++
this.games.push(game)
},
<style>
.board-list-move {
transition: transform 1s;
}
.board-list-enter-active, .board-list-leave-active {
transition: all 0.5s;
}
.board-list-enter, .board-list-leave-active {
opacity: 0;
}
.board-list-enter {
transform: translateX(960px);
}
.board-list-leave-active {
transform: translateX(-960px);
}
:
BoardLibrary.vue
Thank you
@andywoodme
Credits
Doge / Minecraft - http://www.yoyowall.com/wallpaper/dog-mountains.html
LED Lightbulb - http://edisonlightglobes.com/
Bricksauria T.rex - https://www.flickr.com/photos/115291125@N07/12107675253/
CSS Windows - https://twitter.com/neonick/status/747423962783748096
DJECO - http://www.djeco.com/en
!
JS Framework Spectrum - The Progressive Framework, Evan You
Documentation isn’t Complicated - Can't you make it more like Bootstrap, Alice Bartlett
Only one obvious way to wrap a present - Ruby & Django, Linda Liukas
!
Further Reading
!
Vue.js - https://vuejs.org
Vue Awesome - https://github.com/vuejs/awesome-vue
How popular is Vue.js - https://www.quora.com/How-popular-is-VueJS-in-the-industry
iBoards code examples - https://github.com/woodcoder/vue-2-list-example
AMD — RequireJS / client side
!
	 define(['vue'], function (Vue) { …
UMD — two-in-one
!
	 (function (root, factory) {
if (typeof define === 'function' && define.amd) { …
ES2015 / ES6 — tree shakeable
!
	 import Vue from ‘vue’
!
export default {...
XKCD 927 — standards

Enjoy the vue.js