Open wangbinyq opened 8 years ago
html
<div id="app">
<input v-model="newtodo" v-on:keyup.enter="addTodo"></input>
<ul>
<li v-for="todo in todos">
<span>{{ todo }}</span><button v-on:click="remove($index)">X</button>
</li>
</ul>
</div>
</div>
js
var vue = new Vue({
el: '#app',
data: {
newtodo: '',
todos: ['Add som todos'],
},
methods: {
remove: function(index) {
this.todos.splice(index, 1);
},
addTodo: function() {
var text = this.newtodo.trim();
if(text) {
this.todos.push(this.newtodo);
this.newtodo = '';
}
},
},
});
new Vue
创建 ViewMode
l实例Vue.extend
创建选项预定义并且可复用的组件构造器, (自定义组件/元素)Vue
实例都会代理其 data
对象里所有的属性$
实例属性和方法{{ }}
双向绑定{{ * }}
单次绑定, 不会更新{{{ }}}
<div id="item-{{ id }}"></div>
{{ a + 1 }}
{{ message.split('').reverse().join('') }}
{{ var a = 1 }}
{{ message | capitalize }}
{{ message | capitalize | lowercase }}
{{ message | filterA 'arg1' arg2 }}
指令 (Directives) 是特殊的带有前缀 v-
的特性. 指令的值限定为绑定表达式, 因此上面提到的都适用于指令.
v-dir:args.modifiers
v-bind
<!-- 完整语法 -->
<a v-bind:href="url"></a>
<!-- 缩写 -->
<a :href="url"></a>
<!-- 完整语法 -->
<button v-bind:disabled="someDynamicCondition">Button</button>
<!-- 缩写 -->
<button :disabled="someDynamicCondition">Button</button>
<!-- 完整语法 -->
<a v-on:click="doSomething"></a>
<!-- 缩写 -->
<a @click="doSomething"></a>
在模板中表达式非常便利,但是它们实际上只用于简单的操作。模板是为了描述视图的结构。在模板中放入太多的逻辑会让模板过重且难以维护。这就是为什么 Vue.js 将绑定表达式限制为一个表达式。如果需要多于一个表达式的逻辑,应当使用计算属性。
Vue.js 提供了一个方法 $watch,它用于观察 Vue 实例上的数据变动。当一些数据需要根据其它数据变化时, $watch 很诱人 —— 特别是如果你来自 AngularJS。不过,通常更好的办法是使用计算属性而不是一个命令式的 $watch 回调
A dep is an observable that can have multiple directives subscribing to it.
A watcher parses an expression, collects dependencies, and fires callback when the expression value changes. This is used for both the $watch() api and directives.
Like EventEmitter
, addSub -> on
, noitfy -> emit
.
class Dep {
...
depend () {
if (Dep.target) {
Dep.target.addDep(this)
}
}
...
}
class Watcher {
...
addDep (dep: Dep) {
const id = dep.id
if (!this.newDepIds.has(id)) {
this.newDepIds.add(id)
this.newDeps.push(dep)
if (!this.depIds.has(id)) {
dep.addSub(this) // register this watcher callback on the dep
}
}
}
...
}
export default class Watcher {
constructor (
vm: Component,
expOrFn: string | Function, // dependencies
cb: Function, // callback
options?: ?Object,
isRenderWatcher?: boolean
) {
...
this.getter = parse(expOrFn) // getter traverse dependecy
this.value = this.get() // run get to collect dependencies
}
get () {
pushTarget(this) // set Dep.target = this
let value
const vm = this.vm
try {
value = this.getter.call(vm, vm)
} catch (e) {
if (this.user) {
handleError(e, vm, `getter for watcher "${this.expression}"`)
} else {
throw e
}
} finally {
// "touch" every property so they are all tracked as
// dependencies for deep watching
if (this.deep) {
traverse(value)
}
popTarget()
this.cleanupDeps()
}
return value
},
update (); // run callback
}
Observer class that is attached to each observed object. Once attached, the observer converts the target object's property keys into getter/setters that collect dependencies and dispatch updates.
class Observer {
dep: Dep // store watchers of this observer
constructor (value: any) {
...
this.walk(value)
...
}
walk (obj: Object) {
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i])
}
}
}
function defineReactive(obj, key, val, customSetter, shallow) {
const dep = new Dep() // store property's watchers
...
childOb = !shallow && observe(val) // observe on child property
Object.defineProperty(obj, key, {
get: function reactiveGetter () {
const value = getter ? getter.call(obj) : val // get value from predefined getter or provided value.
if (Dep.target) { // `Dep.target` is depend on this property
dep.depend() // add `dep` to `Dep.target`'s deps
if (childOb) { // if this property value is obj or array, then property is depend on child
childOb.dep.depend()
if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
},
set: function reactiveSetter (newVal) {
const value = getter ? getter.call(obj) : val
/* eslint-disable no-self-compare */
if (newVal === value || (newVal !== newVal && value !== value)) {
return
}
/* eslint-enable no-self-compare */
if (process.env.NODE_ENV !== 'production' && customSetter) {
customSetter()
}
if (setter) {
setter.call(obj, newVal)
} else {
val = newVal // save new value
}
childOb = !shallow && observe(newVal)
dep.notify() // trigger update on dep's subs
}
})
})
...
}
Hello world
html
js