Browse Source

add examples

dev
Evan You 9 years ago
parent
commit
eea62a23b2
  1. 63
      examples/commits/app.js
  2. 46
      examples/commits/index.html
  3. 104
      examples/elastic-header/index.html
  4. 44
      examples/elastic-header/style.css
  5. 50
      examples/firebase/app.js
  6. 34
      examples/firebase/index.html
  7. 32
      examples/firebase/style.css
  8. 67
      examples/grid/grid.js
  9. 50
      examples/grid/index.html
  10. 58
      examples/grid/style.css
  11. 34
      examples/markdown/index.html
  12. 32
      examples/markdown/style.css
  13. 55
      examples/svg/index.html
  14. 31
      examples/svg/style.css
  15. 90
      examples/svg/svg.js
  16. 83
      examples/todomvc/index.html
  17. 125
      examples/todomvc/js/app.js
  18. 24
      examples/todomvc/js/routes.js
  19. 18
      examples/todomvc/js/store.js
  20. 9
      examples/todomvc/package.json
  21. 78
      examples/todomvc/perf.js
  22. 28
      examples/todomvc/readme.md
  23. 61
      examples/tree/index.html
  24. 56
      examples/tree/tree.js

63
examples/commits/app.js

@ -0,0 +1,63 @@
var apiURL = 'https://api.github.com/repos/vuejs/vue/commits?per_page=3&sha='
var isPhantom = navigator.userAgent.indexOf('PhantomJS') > -1
/**
* Test mocks
*/
var mocks = {
master: [{sha:'111111111111', commit: {message:'one', author:{name:'Evan',date:'2014-10-15T13:52:58Z'}}},{sha:'111111111111', commit: {message:'hi', author:{name:'Evan',date:'2014-10-15T13:52:58Z'}}},{sha:'111111111111', commit: {message:'hi', author:{name:'Evan',date:'2014-10-15T13:52:58Z'}}}],
dev: [{sha:'222222222222', commit: {message:'two', author:{name:'Evan',date:'2014-10-15T13:52:58Z'}}},{sha:'111111111111', commit: {message:'hi', author:{name:'Evan',date:'2014-10-15T13:52:58Z'}}},{sha:'111111111111', commit: {message:'hi', author:{name:'Evan',date:'2014-10-15T13:52:58Z'}}}]
}
function mockData () {
this.commits = mocks[this.currentBranch]
}
/**
* Actual demo
*/
var demo = new Vue({
el: '#demo',
data: {
branches: ['master', 'dev'],
currentBranch: 'master',
commits: null
},
created: function () {
this.fetchData()
},
watch: {
currentBranch: 'fetchData'
},
methods: {
truncate: function (v) {
var newline = v.indexOf('\n')
return newline > 0 ? v.slice(0, newline) : v
},
formatDate: function (v) {
return v.replace(/T|Z/g, ' ')
},
fetchData: function () {
// CasperJS fails at cross-domain XHR even with
// --web-security=no, have to mock data here.
if (isPhantom) {
return mockData.call(this)
}
var xhr = new XMLHttpRequest()
var self = this
xhr.open('GET', apiURL + self.currentBranch)
xhr.onload = function () {
self.commits = JSON.parse(xhr.responseText)
console.log(self.commits[0].html_url)
}
xhr.send()
}
}
})

46
examples/commits/index.html

@ -0,0 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<title>Vue.js commits example</title>
<style>
#demo {
font-family: 'Helvetica', Arial, sans-serif;
}
a {
text-decoration: none;
color: #f66;
}
li {
line-height: 1.5em;
margin-bottom: 20px;
}
.author, .date {
font-weight: bold;
}
</style>
<script src="../../dist/vue.js"></script>
</head>
<body>
<div id="demo">
<h1>Latest Vue.js Commits</h1>
<template v-for="branch in branches">
<input type="radio"
:id="branch"
:value="branch"
name="branch"
v-model="currentBranch">
<label :for="branch">{{branch}}</label>
</template>
<p>vuejs/vue@{{currentBranch}}</p>
<ul>
<li v-for="record in commits">
<a :href="record.html_url" target="_blank" class="commit">{{record.sha.slice(0, 7)}}</a>
- <span class="message">{{truncate(record.commit.message)}}</span><br>
by <span class="author">{{record.commit.author.name}}</span>
at <span class="date">{{formatDate(record.commit.author.date)}}</span>
</li>
</ul>
</div>
<script src="app.js"></script>
</body>
</html>

104
examples/elastic-header/index.html

@ -0,0 +1,104 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
<title></title>
<script src="../../dist/vue.js"></script>
<script src="http://dynamicsjs.com/lib/dynamics.js"></script>
<link rel="stylesheet" href="style.css">
<!-- template for the component -->
<script type="x/template" id="header-view-template">
<div class="draggable-header-view"
@mousedown="startDrag" @touchstart="startDrag"
@mousemove="onDrag" @touchmove="onDrag"
@mouseup="stopDrag" @touchend="stopDrag" @mouseleave="stopDrag">
<svg class="bg" width="320" height="560">
<path :d="headerPath" fill="#3F51B5"></path>
</svg>
<div class="header">
<slot name="header"></slot>
</div>
<div class="content" :style="contentPosition">
<slot name="content"></slot>
</div>
</div>
</script>
</head>
<body>
<div id="app" @touchmove.prevent>
<draggable-header-view>
<template slot="header">
<h1>Elastic Draggable SVG Header</h1>
<p>with <a href="http://vuejs.org">Vue.js</a> + <a href="http://dynamicsjs.com">dynamics.js</a></p>
</template>
<template slot="content">
<p>Note this is just an effect demo - there are of course many additional details if you want to use this in production, e.g. handling responsive sizes, reload threshold and content scrolling. Those are out of scope for this quick little hack. However, the idea is that you can hide them as internal details of a Vue.js component and expose a simple Web-Component-like interface.</p>
</template>
</draggable-header-view>
</div>
<script>
Vue.component('draggable-header-view', {
template: '#header-view-template',
data: function () {
return {
dragging: false,
// quadratic bezier control point
c: { x: 160, y: 160 },
// record drag start point
start: { x: 0, y: 0 }
}
},
computed: {
headerPath: function () {
return 'M0,0 L320,0 320,160' +
'Q' + this.c.x + ',' + this.c.y +
' 0,160'
},
contentPosition: function () {
var dy = this.c.y - 160
var dampen = dy > 0 ? 2 : 4
return {
transform: 'translate3d(0,' + dy / dampen + 'px,0)'
}
}
},
methods: {
startDrag: function (e) {
e = e.changedTouches ? e.changedTouches[0] : e
this.dragging = true
this.start.x = e.pageX
this.start.y = e.pageY
},
onDrag: function (e) {
e = e.changedTouches ? e.changedTouches[0] : e
if (this.dragging) {
this.c.x = 160 + (e.pageX - this.start.x)
// dampen vertical drag by a factor
var dy = e.pageY - this.start.y
var dampen = dy > 0 ? 1.5 : 4
this.c.y = 160 + dy / dampen
}
},
stopDrag: function () {
if (this.dragging) {
this.dragging = false
dynamics.animate(this.c, {
x: 160,
y: 160
}, {
type: dynamics.spring,
duration: 700,
friction: 280
})
}
}
}
})
new Vue({ el: '#app' })
</script>
</body>
</html>

44
examples/elastic-header/style.css

@ -0,0 +1,44 @@
h1 {
font-weight: 300;
font-size: 1.8em;
margin-top: 0;
}
a {
color: #fff;
}
.draggable-header-view {
background-color: #fff;
box-shadow: 0 4px 16px rgba(0,0,0,.15);
width: 320px;
height: 560px;
overflow: hidden;
margin: 30px auto;
position: relative;
font-family: 'Roboto', Helvetica, Arial, sans-serif;
color: #fff;
font-size: 14px;
font-weight: 300;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.draggable-header-view .bg {
position: absolute;
top: 0;
left: 0;
z-index: 0;
}
.draggable-header-view .header, .draggable-header-view .content {
position: relative;
z-index: 1;
padding: 30px;
box-sizing: border-box;
}
.draggable-header-view .header {
height: 160px;
}
.draggable-header-view .content {
color: #333;
line-height: 1.5em;
}

50
examples/firebase/app.js

@ -0,0 +1,50 @@
var emailRE = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
// Firebase ref
var usersRef = new Firebase('https://vue-demo.firebaseIO.com/users')
// create Vue app
var app = new Vue({
// element to mount to
el: '#app',
// initial data
data: {
newUser: {
name: '',
email: ''
}
},
// firebase binding
// https://github.com/vuejs/vuefire
firebase: {
users: usersRef
},
// computed property for form validation state
computed: {
validation: function () {
return {
name: !!this.newUser.name.trim(),
email: emailRE.test(this.newUser.email)
}
},
isValid: function () {
var validation = this.validation
return Object.keys(validation).every(function (key) {
return validation[key]
})
}
},
// methods
methods: {
addUser: function () {
if (this.isValid) {
usersRef.push(this.newUser)
this.newUser.name = ''
this.newUser.email = ''
}
},
removeUser: function (user) {
usersRef.child(user['.key']).remove()
}
}
})

34
examples/firebase/index.html

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Vue.js Firebase example</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="style.css">
<!-- Vue -->
<script src="../../dist/vue.js"></script>
<!-- Firebase -->
<script src="https://cdn.firebase.com/js/client/2.4.2/firebase.js"></script>
<!-- VueFire -->
<script src="https://cdn.jsdelivr.net/vuefire/1.0.1/vuefire.min.js"></script>
</head>
<body>
<div id="app">
<ul>
<li class="user" v-for="user in users" transition>
<span>{{user.name}} - {{user.email}}</span>
<button v-on:click="removeUser(user)">X</button>
</li>
</ul>
<form id="form" v-on:submit.prevent="addUser">
<input v-model="newUser.name">
<input v-model="newUser.email">
<input type="submit" value="Add User">
</form>
<ul class="errors">
<li v-show="!validation.name">Name cannot be empty.</li>
<li v-show="!validation.email">Please provide a valid email address.</li>
</ul>
</div>
<script src="app.js"></script>
</body>
</html>

32
examples/firebase/style.css

@ -0,0 +1,32 @@
body {
font-family: Helvetica, Arial, sans-serif;
}
ul {
padding: 0;
}
.user {
height: 30px;
line-height: 30px;
padding: 10px;
border-top: 1px solid #eee;
overflow: hidden;
transition: all .25s ease;
}
.user:last-child {
border-bottom: 1px solid #eee;
}
.v-enter, .v-leave {
height: 0;
padding-top: 0;
padding-bottom: 0;
border-top-width: 0;
border-bottom-width: 0;
}
.errors {
color: #f00;
}

67
examples/grid/grid.js

@ -0,0 +1,67 @@
// register the grid component
Vue.component('demo-grid', {
template: '#grid-template',
replace: true,
props: {
data: Array,
columns: Array,
filterKey: String
},
data: function () {
var sortOrders = {}
this.columns.forEach(function (key) {
sortOrders[key] = 1
})
return {
sortKey: '',
sortOrders: sortOrders
}
},
computed: {
filteredData: function () {
var sortKey = this.sortKey
var filterKey = this.filterKey && this.filterKey.toLowerCase()
var order = this.sortOrders[sortKey] || 1
var data = this.data
if (filterKey) {
data = data.filter(function (row) {
return Object.keys(row).some(function (key) {
return String(row[key]).toLowerCase().indexOf(filterKey) > -1
})
})
}
if (sortKey) {
data = data.slice().sort(function (a, b) {
a = a[sortKey]
b = b[sortKey]
return (a === b ? 0 : a > b ? 1 : -1) * order
})
}
return data
}
},
methods: {
capitalize: function (str) {
return str.charAt(0).toUpperCase() + str.slice(1)
},
sortBy: function (key) {
this.sortKey = key
this.sortOrders[key] = this.sortOrders[key] * -1
}
}
})
// bootstrap the demo
var demo = new Vue({
el: '#demo',
data: {
searchQuery: '',
gridColumns: ['name', 'power'],
gridData: [
{ name: 'Chuck Norris', power: Infinity },
{ name: 'Bruce Lee', power: 9000 },
{ name: 'Jackie Chan', power: 7000 },
{ name: 'Jet Li', power: 8000 }
]
}
})

50
examples/grid/index.html

@ -0,0 +1,50 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Vue.js grid component example</title>
<link rel="stylesheet" href="style.css">
<script src="../../dist/vue.js"></script>
</head>
<body>
<!-- component template -->
<script type="text/x-template" id="grid-template">
<table>
<thead>
<tr>
<th v-for="key in columns"
@click="sortBy(key)"
:class="{ active: sortKey == key }">
{{ capitalize(key) }}
<span class="arrow" :class="sortOrders[key] > 0 ? 'asc' : 'dsc'">
</span>
</th>
</tr>
</thead>
<tbody>
<tr v-for="entry in filteredData">
<td v-for="key in columns">
{{entry[key]}}
</td>
</tr>
</tbody>
</table>
</script>
<!-- demo root element -->
<div id="demo">
<form id="search">
Search <input name="query" v-model="searchQuery">
</form>
<demo-grid
:data="gridData"
:columns="gridColumns"
:filter-key="searchQuery">
</demo-grid>
</div>
<script src="grid.js"></script>
</body>
</html>

58
examples/grid/style.css

@ -0,0 +1,58 @@
body {
font-family: Helvetica Neue, Arial, sans-serif;
font-size: 14px;
color: #444;
}
table {
border: 2px solid #42b983;
border-radius: 3px;
background-color: #fff;
}
th {
background-color: #42b983;
color: rgba(255,255,255,0.66);
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-user-select: none;
}
td {
background-color: #f9f9f9;
}
th, td {
min-width: 120px;
padding: 10px 20px;
}
th.active {
color: #fff;
}
th.active .arrow {
opacity: 1;
}
.arrow {
display: inline-block;
vertical-align: middle;
width: 0;
height: 0;
margin-left: 5px;
opacity: 0.66;
}
.arrow.asc {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-bottom: 4px solid #fff;
}
.arrow.dsc {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 4px solid #fff;
}

34
examples/markdown/index.html

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Vue.js markdown editor example</title>
<link rel="stylesheet" href="style.css">
<script src="https://cdn.jsdelivr.net/marked/0.3.5/marked.min.js"></script>
<script src="https://cdn.jsdelivr.net/lodash/4.11.1/lodash.min.js"></script>
<script src="../../dist/vue.js"></script>
</head>
<body>
<div id="editor">
<textarea :value="input" @input="update"></textarea>
<div v-html="marked(input)"></div>
</div>
<script>
new Vue({
el: '#editor',
data: {
input: '# hello'
},
methods: {
marked: marked,
update: function (e) {
this.input = e.target.value
}
}
})
</script>
</body>
</html>

32
examples/markdown/style.css

@ -0,0 +1,32 @@
html, body, #editor {
margin: 0;
height: 100%;
font-family: 'Helvetica Neue', Arial, sans-serif;
color: #333;
}
textarea, #editor div {
display: inline-block;
width: 49%;
height: 100%;
vertical-align: top;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 0 20px;
}
textarea {
border: none;
border-right: 1px solid #ccc;
resize: none;
outline: none;
background-color: #f6f6f6;
font-size: 14px;
font-family: 'Monaco', courier, monospace;
padding: 20px;
}
code {
color: #f66;
}

55
examples/svg/index.html

@ -0,0 +1,55 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Vue.js SVG example</title>
<link rel="stylesheet" href="style.css">
<script src="../../dist/vue.js"></script>
</head>
<body>
<!-- template for the polygraph component. -->
<script type="text/x-template" id="polygraph-template">
<g>
<polygon :points="points"></polygon>
<circle cx="100" cy="100" r="80"></circle>
<axis-label
v-for="stat in stats"
:stat="stat"
:index="$index"
:total="stats.length">
</axis-label>
</g>
</script>
<!-- template for the axis label component. -->
<script type="text/x-template" id="axis-label-template">
<text :x="point.x" :y="point.y">{{stat.label}}</text>
</script>
<!-- demo root element -->
<div id="demo">
<!-- Use the component -->
<svg width="200" height="200">
<polygraph :stats="stats"></polygraph>
</svg>
<!-- controls -->
<div v-for="stat in stats">
<label>{{stat.label}}</label>
<input type="range" v-model="stat.value" min="0" max="100">
<span>{{stat.value}}</span>
<button @click="remove(stat)">X</button>
</div>
<form id="add">
<input name="newlabel" v-model="newLabel">
<button @click="add">Add a Stat</button>
</form>
<pre id="raw">{{json(stats)}}</pre>
</div>
<p style="font-size:12px">* input[type="range"] requires IE10 or above.</p>
<script src="svg.js"></script>
</body>
</html>

31
examples/svg/style.css

@ -0,0 +1,31 @@
body {
font-family: Helvetica Neue, Arial, sans-serif;
}
polygon {
fill: #42b983;
opacity: .75;
}
circle {
fill: transparent;
stroke: #999;
}
text {
font-family: Helvetica Neue, Arial, sans-serif;
font-size: 10px;
fill: #666;
}
label {
display: inline-block;
margin-left: 10px;
width: 20px;
}
#raw {
position: absolute;
top: 0;
left: 300px;
}

90
examples/svg/svg.js

@ -0,0 +1,90 @@
// The raw data to observe
var stats = [
{ label: 'A', value: 100 },
{ label: 'B', value: 100 },
{ label: 'C', value: 100 },
{ label: 'D', value: 100 },
{ label: 'E', value: 100 },
{ label: 'F', value: 100 }
]
// A resusable polygon graph component
Vue.component('polygraph', {
props: ['stats'],
template: '#polygraph-template',
computed: {
// a computed property for the polygon's points
points: function () {
var total = this.stats.length
return this.stats.map(function (stat, i) {
var point = valueToPoint(stat.value, i, total)
return point.x + ',' + point.y
}).join(' ')
}
},
components: {
// a sub component for the labels
'axis-label': {
props: {
stat: Object,
index: Number,
total: Number
},
template: '#axis-label-template',
computed: {
point: function () {
return valueToPoint(
+this.stat.value + 10,
this.index,
this.total
)
}
}
}
}
})
// math helper...
function valueToPoint (value, index, total) {
var x = 0
var y = -value * 0.8
var angle = Math.PI * 2 / total * index
var cos = Math.cos(angle)
var sin = Math.sin(angle)
var tx = x * cos - y * sin + 100
var ty = x * sin + y * cos + 100
return {
x: tx,
y: ty
}
}
// bootstrap the demo
new Vue({
el: '#demo',
data: {
newLabel: '',
stats: stats
},
methods: {
json: function (val) {
return JSON.stringify(val, null, 2)
},
add: function (e) {
e.preventDefault()
if (!this.newLabel) return
this.stats.push({
label: this.newLabel,
value: 100
})
this.newLabel = ''
},
remove: function (stat) {
if (this.stats.length > 3) {
this.stats.$remove(stat)
} else {
alert('Can\'t delete more!')
}
}
}
})

83
examples/todomvc/index.html

@ -0,0 +1,83 @@
<!doctype html>
<html data-framework="vue">
<head>
<meta charset="utf-8">
<title>Vue.js • TodoMVC</title>
<link rel="stylesheet" href="node_modules/todomvc-app-css/index.css">
<style> [v-cloak] { display: none; } </style>
</head>
<body>
<section class="todoapp">
<header class="header">
<h1>todos</h1>
<input class="new-todo"
autofocus autocomplete="off"
placeholder="What needs to be done?"
v-model="newTodo"
@keyup.enter="addTodo">
</header>
<section class="main" v-show="todos.length" v-cloak>
<input class="toggle-all" type="checkbox" v-model="allDone">
<ul class="todo-list">
<li class="todo"
v-for="todo in filteredTodos"
:class="{completed: todo.completed, editing: todo == editedTodo}">
<div class="view">
<input class="toggle" type="checkbox" v-model="todo.completed">
<label @dblclick="editTodo(todo)">{{todo.title}}</label>
<button class="destroy" @click="removeTodo(todo)"></button>
</div>
<input class="edit" type="text"
v-model="todo.title"
v-todo-focus="todo == editedTodo"
@blur="doneEdit(todo)"
@keyup.enter="doneEdit(todo)"
@keyup.esc="cancelEdit(todo)">
</li>
</ul>
</section>
<footer class="footer" v-show="todos.length" v-cloak>
<span class="todo-count">
<strong>{{ remaining }}</strong> {{ pluralize(remaining) }} left
</span>
<ul class="filters">
<li><a href="#/all" :class="{selected: visibility == 'all'}">All</a></li>
<li><a href="#/active" :class="{selected: visibility == 'active'}">Active</a></li>
<li><a href="#/completed" :class="{selected: visibility == 'completed'}">Completed</a></li>
</ul>
<button class="clear-completed" @click="removeCompleted" v-show="todos.length > remaining">
Clear completed
</button>
</footer>
</section>
<footer class="info">
<p>Double-click to edit a todo</p>
<p>Written by <a href="http://evanyou.me">Evan You</a></p>
<p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
</footer>
<!-- testing/benchmark only -->
<script>
var isPhantom = navigator.userAgent.indexOf('PhantomJS') > -1
if (isPhantom) {
localStorage.clear()
} else {
var now = window.performance && window.performance.now
? function () { return window.performance.now() }
: Date.now
var metrics = { beforeLoad: now() }
}
</script>
<!-- end testing/bench -->
<script src="../../dist/vue.js"></script>
<script>metrics.afterLoad = now()</script>
<script src="node_modules/director/build/director.js"></script>
<script src="js/store.js"></script>
<script>metrics.beforeRender = now()</script>
<script src="js/app.js"></script>
<script src="js/routes.js"></script>
<script>metrics.afterRender = now()</script>
<script src="perf.js"></script>
</body>
</html>

125
examples/todomvc/js/app.js

@ -0,0 +1,125 @@
/*global Vue, todoStorage */
(function (exports) {
'use strict';
var filters = {
all: function (todos) {
return todos;
},
active: function (todos) {
return todos.filter(function (todo) {
return !todo.completed;
});
},
completed: function (todos) {
return todos.filter(function (todo) {
return todo.completed;
});
}
};
exports.app = new Vue({
// the root element that will be compiled
el: '.todoapp',
// app initial state
data: {
todos: todoStorage.fetch(),
newTodo: '',
editedTodo: null,
visibility: 'all'
},
// watch todos change for localStorage persistence
watch: {
todos: {
handler: function (todos) {
todoStorage.save(todos);
},
deep: true
}
},
// computed properties
// http://vuejs.org/guide/computed.html
computed: {
filteredTodos: function () {
return filters[this.visibility](this.todos);
},
remaining: function () {
return filters.active(this.todos).length;
},
allDone: {
get: function () {
return this.remaining === 0;
},
set: function (value) {
this.todos.forEach(function (todo) {
todo.completed = value;
});
}
}
},
// methods that implement data logic.
// note there's no DOM manipulation here at all.
methods: {
pluralize: function (n) {
return n === 1 ? 'item' : 'items'
},
addTodo: function () {
var value = this.newTodo && this.newTodo.trim();
if (!value) {
return;
}
this.todos.push({ title: value, completed: false });
this.newTodo = '';
},
removeTodo: function (todo) {
this.todos.$remove(todo);
},
editTodo: function (todo) {
this.beforeEditCache = todo.title;
this.editedTodo = todo;
},
doneEdit: function (todo) {
if (!this.editedTodo) {
return;
}
this.editedTodo = null;
todo.title = todo.title.trim();
if (!todo.title) {
this.removeTodo(todo);
}
},
cancelEdit: function (todo) {
this.editedTodo = null;
todo.title = this.beforeEditCache;
},
removeCompleted: function () {
this.todos = filters.active(this.todos);
}
},
// a custom directive to wait for the DOM to be updated
// before focusing on the input field.
// http://vuejs.org/guide/custom-directive.html
directives: {
'todo-focus': function (el, value) {
if (value) {
el.focus();
}
}
}
});
})(window);

24
examples/todomvc/js/routes.js

@ -0,0 +1,24 @@
/*global app, Router */
(function (app, Router) {
'use strict';
var router = new Router();
['all', 'active', 'completed'].forEach(function (visibility) {
router.on(visibility, function () {
app.visibility = visibility;
});
});
router.configure({
notfound: function () {
window.location.hash = '';
app.visibility = 'all';
}
});
router.init();
})(app, Router);

18
examples/todomvc/js/store.js

@ -0,0 +1,18 @@
/*jshint unused:false */
(function (exports) {
'use strict';
var STORAGE_KEY = 'todos-vuejs';
exports.todoStorage = {
fetch: function () {
return JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
},
save: function (todos) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(todos));
}
};
})(window);

9
examples/todomvc/package.json

@ -0,0 +1,9 @@
{
"private": true,
"dependencies": {
"director": "^1.2.0",
"vue": "^1.0.0",
"todomvc-common": "^1.0.1",
"todomvc-app-css": "^2.0.0"
}
}

78
examples/todomvc/perf.js

@ -0,0 +1,78 @@
setTimeout(function () {
if (window.isPhantom) return
// Initial load & render metrics
metrics.afterRenderAsync = now()
console.log('Vue load : ' + (metrics.afterLoad - metrics.beforeLoad).toFixed(2) + 'ms')
console.log('Render sync : ' + (metrics.afterRender - metrics.beforeRender).toFixed(2) + 'ms')
console.log('Render async : ' + (metrics.afterRenderAsync - metrics.beforeRender).toFixed(2) + 'ms')
console.log('Total sync : ' + (metrics.afterRender - metrics.beforeLoad).toFixed(2) + 'ms')
console.log('Total async : ' + (metrics.afterRenderAsync - metrics.beforeLoad).toFixed(2) + 'ms')
// Benchmark
// add 100 items
// toggle them one by one
// then delete them one by one
var benchSetting = window.location.search.match(/\bbenchmark=(\d+)/)
if (!benchSetting) return
var itemsToAdd = +benchSetting[1],
render,
bench,
addTime,
toggleTime,
removeTime
var start = now(),
last
add()
function add() {
last = now()
var newTodo = '12345',
todoInput = document.getElementById('new-todo')
for (var i = 0; i < itemsToAdd; i++) {
var keyupEvent = document.createEvent('Event');
keyupEvent.initEvent('keyup', true, true);
keyupEvent.keyCode = 13;
app.newTodo = 'Something to do ' + i;
todoInput.dispatchEvent(keyupEvent)
}
setTimeout(toggle, 0)
}
function toggle () {
addTime = now() - last
var checkboxes = document.querySelectorAll('.toggle')
for (var i = 0; i < checkboxes.length; i++) {
checkboxes[i].click()
}
last = now()
setTimeout(remove, 0)
}
function remove () {
toggleTime = now() - last
var deleteButtons = document.querySelectorAll('.destroy');
for (var i = 0; i < deleteButtons.length; i++) {
deleteButtons[i].click()
}
last = now()
setTimeout(report, 0)
}
function report () {
bench = now() - start
removeTime = now() - last
console.log('\nBenchmark x ' + itemsToAdd)
console.log('add : ' + addTime.toFixed(2) + 'ms')
console.log('toggle : ' + toggleTime.toFixed(2) + 'ms')
console.log('remove : ' + removeTime.toFixed(2) + 'ms')
console.log('total : ' + bench.toFixed(2) + 'ms')
}
}, 0)

28
examples/todomvc/readme.md

@ -0,0 +1,28 @@
# Vue.js TodoMVC Example
> Vue.js is a library for building interactive web interfaces.
It provides data-driven, nestable view components with a simple and flexible API.
> _[Vue.js - vuejs.org](http://vuejs.org)_
## Learning Vue.js
The [Vue.js website](http://vuejs.org/) is a great resource to get started.
Here are some links you may find helpful:
* [Official Guide](http://vuejs.org/guide/)
* [API Reference](http://vuejs.org/api/)
* [Examples](http://vuejs.org/examples/)
* [Building Larger Apps with Vue.js](http://vuejs.org/guide/application.html)
Get help from other Vue.js users:
* [Vue.js official forum](http://forum.vuejs.org)
* [Vue.js on Twitter](https://twitter.com/vuejs)
* [Vue.js on Gitter](https://gitter.im/vuejs/vue)
_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._
## Credit
This TodoMVC application was created by [Evan You](http://evanyou.me).

61
examples/tree/index.html

@ -0,0 +1,61 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Vue.js tree-view demo</title>
<style>
body {
font-family: Menlo, Consolas, monospace;
color: #444;
}
.item {
cursor: pointer;
}
.bold {
font-weight: bold;
}
ul {
padding-left: 1em;
line-height: 1.5em;
list-style-type: dot;
}
</style>
<script src="../../dist/vue.js"></script>
</head>
<body>
<!-- item template -->
<script type="text/x-template" id="item-template">
<li>
<div
:class="{bold: isFolder}"
@click="toggle"
@dblclick="changeType">
{{model.name}}
<span v-if="isFolder">[{{open ? '-' : '+'}}]</span>
</div>
<ul v-show="open" v-if="isFolder">
<item
class="item"
v-for="model in model.children"
:model="model">
</item>
<li @click="addChild">+</li>
</ul>
</li>
</script>
<p>(You can double click on an item to turn it into a folder.)</p>
<!-- the demo root element -->
<ul id="demo">
<item
class="item"
:model="treeData">
</item>
</ul>
<!-- demo code -->
<script src="tree.js"></script>
</body>
</html>

56
examples/tree/tree.js

@ -0,0 +1,56 @@
// demo data
var data = {
name: 'My Tree',
children: [
{ name: 'hello' }
]
}
// define the item component
Vue.component('item', {
template: '#item-template',
props: {
model: Object
},
data: function () {
return {
open: false
}
},
updated: function () {
console.log(this._vnode)
},
computed: {
isFolder: function () {
return this.model.children &&
this.model.children.length
}
},
methods: {
toggle: function () {
if (this.isFolder) {
this.open = !this.open
}
},
changeType: function () {
if (!this.isFolder) {
Vue.set(this.model, 'children', [])
this.addChild()
this.open = true
}
},
addChild: function () {
this.model.children.push({
name: 'new stuff'
})
}
}
})
// boot up the demo
var demo = new Vue({
el: '#demo',
data: {
treeData: data
}
})
Loading…
Cancel
Save