watch & events

This commit is contained in:
Evan You 2016-04-12 22:08:19 -04:00
parent 6bb90961fd
commit 7b8546378c
5 changed files with 120 additions and 30 deletions

View File

@ -1,3 +0,0 @@
export function apiMixin (Vue) {
}

View File

@ -1,7 +1,86 @@
export function initEvents (vm) {
import { toArray } from '../util/index'
export function initEvents (vm) {
vm._events = Object.create(null)
}
export function eventsMixin (Vue) {
Vue.prototype.$on = function (event, fn) {
(this._events[event] || (this._events[event] = []))
.push(fn)
return this
}
/**
* Adds an `event` listener that will be invoked a single
* time then automatically removed.
*
* @param {String} event
* @param {Function} fn
*/
Vue.prototype.$once = function (event, fn) {
var self = this
function on () {
self.$off(event, on)
fn.apply(this, arguments)
}
on.fn = fn
this.$on(event, on)
return this
}
/**
* Remove the given callback for `event` or all
* registered callbacks.
*
* @param {String} event
* @param {Function} fn
*/
Vue.prototype.$off = function (event, fn) {
var cbs
// all
if (!arguments.length) {
this._events = Object.create(null)
return this
}
// specific event
cbs = this._events[event]
if (!cbs) {
return this
}
if (arguments.length === 1) {
this._events[event] = null
return this
}
// specific handler
var cb
var i = cbs.length
while (i--) {
cb = cbs[i]
if (cb === fn || cb.fn === fn) {
cbs.splice(i, 1)
break
}
}
return this
}
/**
* Trigger an event on self.
*
* @param {String} event
*/
Vue.prototype.$emit = function (event) {
var cbs = this._events[event]
if (cbs) {
cbs = cbs.length > 1 ? toArray(cbs) : cbs
var args = toArray(arguments, 1)
for (var i = 0, l = cbs.length; i < l; i++) {
cbs[i].apply(this, args)
}
}
}
}

View File

@ -1,7 +1,6 @@
import { initState, stateMixin } from './state'
import { initRender, renderMixin } from './render'
import { initEvents, eventsMixin } from './events'
import { apiMixin } from './api'
export default function Vue (options) {
this.$options = options
@ -14,4 +13,3 @@ export default function Vue (options) {
stateMixin(Vue)
eventsMixin(Vue)
renderMixin(Vue)
apiMixin(Vue)

View File

@ -83,35 +83,14 @@ function makeComputedGetter (getter, owner) {
}
function initMethods (vm) {
var methods = vm.$options.methods
const methods = vm.$options.methods
if (methods) {
for (var key in methods) {
for (let key in methods) {
vm[key] = bind(methods[key], vm)
}
}
}
function proxy (vm, key) {
if (!isReserved(key)) {
Object.defineProperty(vm, key, {
configurable: true,
enumerable: true,
get: function proxyGetter () {
return vm._data[key]
},
set: function proxySetter (val) {
vm._data[key] = val
}
})
}
}
function unproxy (vm, key) {
if (!isReserved(key)) {
delete vm[key]
}
}
export function stateMixin (Vue) {
Object.defineProperty(Vue.prototype, '$data', {
get () {
@ -123,6 +102,18 @@ export function stateMixin (Vue) {
}
}
})
Vue.prototype.$watch = function (fn, cb, options) {
options = options || {}
options.user = true
const watcher = new Watcher(this, fn, cb, options)
if (options.immediate) {
cb.call(this, watcher.value)
}
return function unwatchFn () {
watcher.teardown()
}
}
}
function setData (vm, newData) {
@ -154,3 +145,24 @@ function setData (vm, newData) {
observe(newData, vm)
vm.$forceUpdate()
}
function proxy (vm, key) {
if (!isReserved(key)) {
Object.defineProperty(vm, key, {
configurable: true,
enumerable: true,
get: function proxyGetter () {
return vm._data[key]
},
set: function proxySetter (val) {
vm._data[key] = val
}
})
}
}
function unproxy (vm, key) {
if (!isReserved(key)) {
delete vm[key]
}
}

View File

@ -2,6 +2,7 @@ import config from '../config'
import Dep from './dep'
import { pushWatcher } from './batcher'
import {
warn,
extend,
isArray,
isObject,
@ -51,7 +52,10 @@ export default function Watcher (vm, expOrFn, cb, options) {
if (isFn) {
this.getter = expOrFn
} else {
this.getter = new Function(`with(this){return ${expOrFn}}`)
this.getter = function () {}
process.env.NODE_ENV !== 'production' && warn(
'Watcher only accpets function.'
)
}
this.value = this.lazy
? undefined