Skip to content

Instantly share code, notes, and snippets.

@Minasokoni
Forked from yyx990803/commits.vue
Created June 21, 2019 16:34
Show Gist options
  • Save Minasokoni/8ddb30529d31f8a98c37eeaa03e50465 to your computer and use it in GitHub Desktop.
Save Minasokoni/8ddb30529d31f8a98c37eeaa03e50465 to your computer and use it in GitHub Desktop.
Vue examples comparisons in 2.x and function-based APIs
<template>
<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">{{ record.commit.message | truncate }}</span><br>
by <span class="author"><a :href="record.author.html_url" target="_blank">{{ record.commit.author.name }}</a></span>
at <span class="date">{{ record.commit.author.date | formatDate }}</span>
</li>
</ul>
</div>
</template>
<script>
// filters are omitted since they are the same
const apiURL = 'https://api.github.com/repos/vuejs/vue/commits?per_page=3&sha='
function fetch(url, cb) {
const xhr = new XMLHttpRequest()
xhr.open('GET', apiURL + url)
xhr.onload = function () {
cb(JSON.parse(xhr.responseText))
}
xhr.send()
}
// 2.x
const oldAPI = {
data() {
return {
branches: ['master', 'dev'],
currentBranch: 'master',
commits: null
}
},
created: function () {
this.fetchData()
},
watch: {
currentBranch: 'fetchData'
},
methods: {
fetchData: function () {
fetch(this.currentBranch, data => {
this.commits = data
})
}
}
}
const newAPI = {
setup() {
const currentBranch = value('master')
const commits = value(null)
watch(currentBranch, branch => {
fetch(branch, data => {
commits.value = data
})
})
return {
branches: ['master', 'dev'],
currentBranch,
commits
}
}
}
</script>
<template>
<div>
Count is {{ count }}, count * 2 is {{ double }}
<button @click="increment">+</button>
</div>
</template>
<script>
const oldAPI = {
data() {
return {
count: 0
}
},
methods: {
increment() {
this.count++
}
},
computed: {
double() {
return this.count * 2
}
}
}
const newAPI = {
setup() {
const count = value(0)
const double = computed(() => count.value * 2)
const increment = () => { count.value++ }
return {
count,
double,
increment
}
}
}
</script>
<template>
<table v-if="filteredData.length">
<thead>
<tr>
<th v-for="key in columns"
@click="sortBy(key)"
:class="{ active: sortKey == key }">
{{ key | capitalize }}
<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>
<p v-else>No matches found.</p>
</template>
<script>
const oldAPI = {
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: {
sortBy: function (key) {
this.sortKey = key
this.sortOrders[key] = this.sortOrders[key] * -1
}
}
}
const newAPI = {
props: {
data: Array,
columns: Array,
filterKey: String
},
setup(props) {
const sortKey = value('')
const sortOrders = value({})
props.columns.forEach(key => {
sortOrders.value[key] = 1
})
const filteredData = computed(() => {
const filterKey = props.filterKey && props.filterKey.toLowerCase()
const sortKeyValue = sortKey.value
const order = sortOrders.value[sortKeyValue] || 1
let data = props.data
if (filterKey) {
data = data.filter(row => {
return Object.keys(row).some(key => {
return String(row[key]).toLowerCase().indexOf(filterKey) > -1
})
})
}
if (sortKeyValue) {
data = data.slice().sort((a, b) => {
a = a[sortKeyValue]
b = b[sortKeyValue]
return (a === b ? 0 : a > b ? 1 : -1) * order
})
}
return data
})
function sortBy(key) {
sortKey.value = key
sortOrders.value[key] = sortOrders.value[key] * -1
}
return {
sortKey,
sortOrders,
filteredData,
sortBy
}
}
}
</script>
<template>
<div>
<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 v-for="todo in filteredTodos"
class="todo"
:key="todo.id"
: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> {{ remaining | pluralize }} 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>
</div>
</template>
<script>
import { computed } from "../../packages/reactivity/src";
var STORAGE_KEY = 'todos-vuejs-2.0'
var todoStorage = {
fetch: function () {
// omitted since they are the same across implementations
},
save: function (todos) {
// omitted since they are the same across implementations
}
}
// visibility filters
var filters = {
// omitted since they are the same across implementations
}
const oldAPI = {
// 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
// https://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: {
addTodo: function () {
var value = this.newTodo && this.newTodo.trim()
if (!value) {
return
}
this.todos.push({
id: todoStorage.uid++,
title: value,
completed: false
})
this.newTodo = ''
},
removeTodo: function (todo) {
this.todos.splice(this.todos.indexOf(todo), 1)
},
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)
}
}
}
const newAPI = {
setup() {
const todos = value(todoStorage.fetch())
const newTodo = value('')
const editedTodo = value(null)
const visibility = value('all')
let beforeEditCache = ''
watch(todos, todos => {
todoStorage.save(todos)
}, { deep: true })
const computeds = {
filteredTodos: computed(() => filters[visibility.value](todos.value)),
remaining: computed(() => filters.active(todos.value).length),
allDone: computed(
() => computeds.remaining.value === 0,
() => todos.value.forEach(todo => {
todo.completed = true
})
)
}
const methods = {
addTodo() {
const value = newTodo.value && newTodo.value.trim()
if (value) {
todos.value.push({
id: todoStorage.uid++,
title: value,
completed: false
})
}
newTodo.value = ''
},
removeTodo(todo) {
todos.value = todos.value.filter(t => t !== todo)
},
editTodo(todo) {
beforeEditCache = todo.title
editedTodo.value = todo
},
doneEdit(todo) {
if (editedTodo.value) {
editedTodo.value = null
todo.title = todo.title.trim()
if (!todo.title) {
methods.removeTodo(todo)
}
}
},
cancelEdit() {
todo.title = todo.title.trim()
if (!todo.title) {
methods.removeTodo(todo)
}
},
removeCompleted() {
todos.value = filters.active(todos.value)
}
}
return {
todos,
newTodo,
editedTodo,
visibility,
...computeds,
...methods
}
}
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment