mirror of https://github.com/vuejs/vue.git
dynamic context computed properties
This commit is contained in:
parent
e4d06a10ea
commit
de1c1a1112
2
TODO.md
2
TODO.md
|
|
@ -1,3 +1,5 @@
|
|||
- tests
|
||||
- docs
|
||||
- sd-with
|
||||
- standarized way to reuse components (sd-component?)
|
||||
- plugins: seed-touch, seed-storage, seed-router
|
||||
|
|
@ -7,10 +7,8 @@
|
|||
</head>
|
||||
<body>
|
||||
<section id="todoapp" sd-controller="Todos">
|
||||
|
||||
<header id="header">
|
||||
<h1>todos</h1>
|
||||
<!-- main input box -->
|
||||
<input
|
||||
id="new-todo"
|
||||
autofocus
|
||||
|
|
@ -20,16 +18,13 @@
|
|||
sd-on="keyup:addTodo | key enter"
|
||||
>
|
||||
</header>
|
||||
|
||||
<section id="main" sd-show="total">
|
||||
<!-- toggle all checkbox-->
|
||||
<input
|
||||
id="toggle-all"
|
||||
type="checkbox"
|
||||
sd-checked="allDone"
|
||||
>
|
||||
<ul id="todo-list">
|
||||
<!-- a single todo item -->
|
||||
<li
|
||||
class="todo"
|
||||
sd-each="todo:todos"
|
||||
|
|
@ -56,8 +51,6 @@
|
|||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<!-- footer controls -->
|
||||
<footer id="footer" sd-show="total">
|
||||
<span id="todo-count">
|
||||
<strong sd-text="remaining"></strong> {{itemLabel}} left
|
||||
|
|
@ -71,17 +64,12 @@
|
|||
Remove Completed ({{completed}})
|
||||
</button>
|
||||
</footer>
|
||||
|
||||
</section>
|
||||
|
||||
<!-- info -->
|
||||
<footer id="info">
|
||||
<p>Double-click to edit a todo</p>
|
||||
<p>Powered by <a href="https://github.com/yyx990803/seed">Seed.js</a></p>
|
||||
<p>Created by <a href="http://evanyou.me">Evan You</a></p>
|
||||
</footer>
|
||||
|
||||
<!-- js -->
|
||||
<script src="../../dist/seed.js"></script>
|
||||
<script src="js/app.js"></script>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,27 @@
|
|||
var storageKey = 'todos-seedjs',
|
||||
todos = JSON.parse(localStorage.getItem(storageKey)) || [],
|
||||
filters = {
|
||||
Seed.controller('Todos', function (scope) {
|
||||
|
||||
// data persistence -------------------------------------------------------
|
||||
var STORAGE_KEY = 'todos-seedjs'
|
||||
function sync () {
|
||||
localStorage.setItem(STORAGE_KEY, scope.$serialize('todos'))
|
||||
}
|
||||
|
||||
// filters ----------------------------------------------------------------
|
||||
var filters = {
|
||||
all: function () { return true },
|
||||
active: function (v) { return !v },
|
||||
completed: function (v) { return v }
|
||||
}
|
||||
|
||||
Seed.controller('Todos', function (scope) {
|
||||
updateFilter()
|
||||
window.addEventListener('hashchange', updateFilter)
|
||||
function updateFilter () {
|
||||
if (!location.hash) return
|
||||
scope.filter = location.hash.slice(2) || 'all'
|
||||
}
|
||||
|
||||
// regular properties -----------------------------------------------------
|
||||
scope.todos = todos
|
||||
scope.remaining = todos.reduce(function (n, todo) {
|
||||
scope.todos = JSON.parse(localStorage.getItem(STORAGE_KEY)) || []
|
||||
scope.remaining = scope.todos.reduce(function (n, todo) {
|
||||
return n + (todo.completed ? 0 : 1)
|
||||
}, 0)
|
||||
|
||||
|
|
@ -27,12 +38,12 @@ Seed.controller('Todos', function (scope) {
|
|||
return scope.remaining > 1 ? 'items' : 'item'
|
||||
}}
|
||||
|
||||
// computed property using info from target scope
|
||||
// dynamic context computed property using info from target scope
|
||||
scope.filterTodo = {get: function (e) {
|
||||
return filters[scope.filter](e.scope.completed)
|
||||
}}
|
||||
|
||||
// computed property using info from target element
|
||||
// dynamic context computed property using info from target element
|
||||
scope.checkFilter = {get: function (e) {
|
||||
return scope.filter === e.el.textContent.toLowerCase()
|
||||
}}
|
||||
|
|
@ -52,8 +63,9 @@ Seed.controller('Todos', function (scope) {
|
|||
|
||||
// event handlers ---------------------------------------------------------
|
||||
scope.addTodo = function () {
|
||||
if (scope.newTodo.trim()) {
|
||||
scope.todos.unshift({ title: scope.newTodo.trim(), completed: false })
|
||||
var value = scope.newTodo.trim()
|
||||
if (value) {
|
||||
scope.todos.unshift({ title: value, completed: false })
|
||||
scope.newTodo = ''
|
||||
scope.remaining++
|
||||
sync()
|
||||
|
|
@ -99,19 +111,8 @@ Seed.controller('Todos', function (scope) {
|
|||
sync()
|
||||
}
|
||||
|
||||
// filters
|
||||
updateFilter()
|
||||
window.addEventListener('hashchange', updateFilter)
|
||||
function updateFilter () {
|
||||
if (!location.hash) return
|
||||
scope.filter = location.hash.slice(2) || 'all'
|
||||
}
|
||||
|
||||
// data persistence using localStorage
|
||||
function sync () {
|
||||
localStorage.setItem(storageKey, scope.$serialize('todos'))
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
Seed.bootstrap({ debug: true })
|
||||
var s = Date.now()
|
||||
Seed.bootstrap({ debug: false })
|
||||
console.log(Date.now() - s)
|
||||
|
|
@ -115,6 +115,13 @@ BindingProto.update = function (value) {
|
|||
this.pub()
|
||||
}
|
||||
|
||||
BindingProto.refresh = function () {
|
||||
var i = this.instances.length
|
||||
while (i--) {
|
||||
this.instances[i].refresh()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Notify computed properties that depend on this binding
|
||||
* to update themselves
|
||||
|
|
|
|||
|
|
@ -19,8 +19,9 @@ function catchDeps (binding) {
|
|||
observer.on('get', function (dep) {
|
||||
binding.deps.push(dep)
|
||||
})
|
||||
parseContextDependency(binding)
|
||||
binding.value.get({
|
||||
scope: createDummyScope(binding.value.get),
|
||||
scope: createDummyScope(binding),
|
||||
el: dummyEl
|
||||
})
|
||||
observer.off('get')
|
||||
|
|
@ -37,7 +38,7 @@ function filterDeps (binding) {
|
|||
dep = binding.deps[i]
|
||||
if (!dep.deps.length) {
|
||||
config.log(' └─' + dep.key)
|
||||
dep.subs.push.apply(dep.subs, binding.instances)
|
||||
dep.subs.push(binding)
|
||||
} else {
|
||||
binding.deps.splice(i, 1)
|
||||
}
|
||||
|
|
@ -53,18 +54,15 @@ function filterDeps (binding) {
|
|||
* the user expects the target scope to possess. They are all assigned
|
||||
* a noop function so they can be invoked with no real harm.
|
||||
*/
|
||||
function createDummyScope (fn) {
|
||||
function createDummyScope (binding) {
|
||||
var scope = {},
|
||||
str = fn.toString()
|
||||
var args = str.match(ARGS_RE)
|
||||
if (!args) return scope
|
||||
var argRE = new RegExp(args[1] + SCOPE_RE_STR, 'g'),
|
||||
matches = str.match(argRE)
|
||||
if (!matches) return scope
|
||||
var i = matches.length, j, path, key, level
|
||||
deps = binding.contextDeps
|
||||
if (!deps) return scope
|
||||
var i = binding.contextDeps.length,
|
||||
j, level, key, path
|
||||
while (i--) {
|
||||
level = scope
|
||||
path = matches[i].slice(args[1].length + 7).split('.')
|
||||
path = deps[i].split('.')
|
||||
j = 0
|
||||
while (j < path.length) {
|
||||
key = path[j]
|
||||
|
|
@ -76,6 +74,22 @@ function createDummyScope (fn) {
|
|||
return scope
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract context dependency paths
|
||||
*/
|
||||
function parseContextDependency (binding) {
|
||||
var fn = binding.value.get,
|
||||
str = fn.toString(),
|
||||
args = str.match(ARGS_RE)
|
||||
if (!args) return null
|
||||
var argRE = new RegExp(args[1] + SCOPE_RE_STR, 'g'),
|
||||
matches = str.match(argRE),
|
||||
base = args[1].length + 7
|
||||
if (!matches) return null
|
||||
binding.contextDeps = matches.map(function (key) { return key.slice(base) })
|
||||
binding.seed._contextBindings.push(binding)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
/*
|
||||
|
|
|
|||
36
src/seed.js
36
src/seed.js
|
|
@ -21,10 +21,13 @@ function Seed (el, options) {
|
|||
el = document.querySelector(el)
|
||||
}
|
||||
|
||||
this.el = el
|
||||
el.seed = this
|
||||
this._bindings = {}
|
||||
this._computed = []
|
||||
this.el = el
|
||||
el.seed = this
|
||||
this._bindings = {}
|
||||
// list of computed properties that need to parse dependencies for
|
||||
this._computed = []
|
||||
// list of bindings that has dynamic context dependencies
|
||||
this._contextBindings = []
|
||||
|
||||
// copy options
|
||||
options = options || {}
|
||||
|
|
@ -82,6 +85,9 @@ function Seed (el, options) {
|
|||
// extract dependencies for computed properties
|
||||
if (this._computed.length) depsParser.parse(this._computed)
|
||||
delete this._computed
|
||||
|
||||
if (this._contextBindings.length) this._bindContexts(this._contextBindings)
|
||||
delete this._contextBindings
|
||||
}
|
||||
|
||||
// for better compression
|
||||
|
|
@ -193,7 +199,10 @@ SeedProto._bind = function (directive) {
|
|||
seed = traceOwnerSeed(directive, seed)
|
||||
var binding = seed._bindings[key] || seed._createBinding(key)
|
||||
|
||||
// add directive to this binding
|
||||
if (binding.contextDeps) {
|
||||
console.log(1)
|
||||
}
|
||||
|
||||
binding.instances.push(directive)
|
||||
directive.binding = binding
|
||||
|
||||
|
|
@ -220,6 +229,23 @@ SeedProto._createBinding = function (key) {
|
|||
return binding
|
||||
}
|
||||
|
||||
/*
|
||||
* Process subscriptions for computed properties that has
|
||||
* dynamic context dependencies
|
||||
*/
|
||||
SeedProto._bindContexts = function (bindings) {
|
||||
var i = bindings.length, j, binding, depKey, dep
|
||||
while (i--) {
|
||||
binding = bindings[i]
|
||||
j = binding.contextDeps.length
|
||||
while (j--) {
|
||||
depKey = binding.contextDeps[j]
|
||||
dep = this._bindings[depKey]
|
||||
dep.subs.push(binding)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Call unbind() of all directive instances
|
||||
* to remove event listeners, destroy child seeds, etc.
|
||||
|
|
|
|||
Loading…
Reference in New Issue