VUE2中⽂⽂档:语法基础笔记
Vue.js 的核⼼是,可以采⽤简洁的模板语法来声明式的将数据渲染为 DOM:
<div id="app">
{{ message }} //模板语法
</div>
var app = new Vue({ //新建vue实例(响应式)
el: '#app', //挂载到#app
data: {
message: 'Hello Vue!' //数据
}
})
除了⽂本插值(text interpolation),我们还可以采⽤这样的⽅式绑定 DOM 元素属性:
差距英文<div id="app-2">
<span v-bind:title="message"> //v-bind:属性=“数据”
⿏标悬停此处⼏秒,
可以看到此处动态绑定的 title!
</span>
</div>
var app2 = new Vue({
el: '#app-2',
data: {
message: '页⾯加载于 ' + new Date().toLocaleString()
藉口
}
})
在 Vue 中,⼀个组件本质上是⼀个被预先定义选项的 Vue 实例,在 Vue 中注册组件很简单:
// 定义⼀个被命名为 todo-item 的新组件
template: '<li>这是⼀个 todo 项</li>'
})
现在你可以在另⼀个组件模板中组合使⽤它:
<ol>
<!-- 创建⼀个 todo-item 组件的实例 -->
<todo-item></todo-item>
</ol>
将数据从⽗作⽤域传到⼦组件。让我们来修改下组件的定义,使它可以接受⼀个:
var app7 = new Vue({ //vue实例挂载到app-7
el: '#app-7',
data: {
groceryList: [
{ id: 0, text: '蔬菜' },
{ id: 1, text: '奶酪' },
{ id: 2, text: '其他⼈类⾷物' }
]
}
})
<div id="app-7"> //组件模板app-7
<ol>
<!--
现在我们为每个 todo-item 提供了 todo 对象,
其中它的内容是动态的。
我们还需要为每个组件提供⼀个 "key",
这将在之后详细解释。
-->
wishwing
<todo-item v-for="item in groceryList"
v-bind:todo="item" //将遍历的每个item对象传递给todo
v-bind:key="item.id"> //由于vue对组件渲染是可复⽤的,如果不给每⼀个添加不同的key,后⾯循环的组件不会重新渲染 </todo-item> //⽽是直接复⽤第⼀次渲染的结果
</ol>
</div>
props: ['todo'], //⼦组件⽤props接受todo
template: '<li>{{ }}</li>' //⼦组件模板
})
下⾯正式开始:
Vue 实例
var vm = new Vue({ //创建
// 选项
})
Vue 应⽤程序由「⼀个使⽤new Vue创建的 Vue 根实例」、「嵌套的树结构(可选)」和「可复⽤的组件」组成。
在创建 Vue 实例时,会将所有在data对象中找到的属性,都添加到 Vue 的响应式系统中。每当这些属性的值发⽣变化时,视图都会“及时响应”,并更新相应的新值。
每当 data 对象发⽣变化,都会触发视图重新渲染。值得注意的是,如果实例已经创建,那么只有那些data中的原本就已经存在的属性,才是响应式的。也就是说,如果在实例创建之后,添加⼀个新的属性,
例如:vm.b = ' hide';
然后,修改b不会触发任何视图更新。如果你已经提前知道,之后将会⽤到⼀个开始是空的或不存在的属性,你需要预先设置⼀些初始值。例如:
data: {
newTodoText: '',
眼部化妆步骤
visitCount: 0,
hideCompletedTodos: fal,
todos: [],
error: null
}
唯⼀的例外是,使⽤Object.freeze()来防⽌已有属性被修改,这也意味着响应式系统⽆法追踪变化。
除了 data 属性, Vue 实例还暴露了⼀些有⽤的实例属性和⽅法。这些属性与⽅法都具有前缀$,以便与⽤户定义(ur-defined)的属性有所区分。例如:
var data = { a: 1 }
var vm = new Vue({
el: '#example',
data: data
})
vm.$data === data // => true 实例属性,获取实例data
vm.$el === ElementById('example') // => true 获取挂载的DOM对象
// $watch 是⼀个实例⽅法
vm.$watch('a', function (newValue, oldValue) {
// 此回调函数将在 `vm.a` 改变后调⽤
})
点击,来获取实例属性(instance property)和⽅法(methods)的完整列表。
每个 Vue 实例在被创建之前,都要经过⼀系列的初始化过程 - 例如:
Vue 实例需要设置数据观察(t up data obrvation)、
编译模板(compile the template)、
在 DOM 挂载实例(mount the instance to the DOM),
数据变化时更新 DOM(update the DOM when data change)。
在这个过程中,Vue 实例还会调⽤执⾏⼀些⽣命周期钩⼦函数,这样⽤户能够在特定阶段添加⾃⼰的代码。
模板语法
所有 Vue.js 的模板都是有效的 HTML,能够被遵循规范的浏览器和 HTML 解析器解析。
在底层的实现上,Vue 将模板编译为可以⽣成 Virtual DOM 的 render 函数。结合响应式系统,在应⽤程序状态改变时,Vue 能够智能地找出重新渲染的最⼩数量的组件,并应⽤最少量的 DOM 操作。
如果你熟悉虚拟 DOM 的概念,并且倾向于使⽤原⽣ JavaScript,还可以不使⽤模板,⽽是,具备可选的 JSX 语法⽀持。
⽂本(Text)
使⽤ “mustache” 语法(双花括号)的⽂本插值(text interpolation),也可以通过使⽤,执⾏⼀次性插
值,也就是说,在数据改变时,插值内容不会随之更新。但是请牢记,这也将影响到同⼀节点上的其他所有绑定。
(不建议使⽤)
有个限制是,每个绑定都只能包含单个表达式。
computed 属性和 watcher
你可以像绑定普通属性⼀样,将 computed 属性的数据,绑定(data-bind)到模板中的表达式上。Vue 能够意识到computed属性依赖于实例的数据,也会在⽰例数据修改后,更新所有依赖于computed属性的数据绑定。最恰到好处的部分是,我们是通过声明式来创建这种依赖关系:computed 属性的 getter 函数并⽆副作⽤(side effect),因此也更加易于测试和理解。
computed 属性会基于它所依赖的数据进⾏缓存。每个 computed 属性,只有在它所依赖的数据发⽣变化时,才会重新取值(re-evaluate)。这就意味着,只要computed属性函数依赖的实例数据没有发⽣变化,多次访问 computed 属性,将会⽴刻返回之前计算过的结果,⽽不必每次都重新执⾏函数。
为什么我们需要将依赖数据缓存起来?假设⼀种场景,我们有⼀个⾼性能开销(expensive)的 computed 属性 A,在 computed 属性的 getter 函数内部,需要遍历循环⼀个巨⼤数组,并进⾏⼤量
计算。然后还有其他 computed 属性直接或间接依赖于 A。如果没有缓存,我们将不可避免地多次执⾏ A 的 getter 函数,这远多余实际需要执⾏的次数!然⽽在某些场景下,你可能不希望有缓存,请使⽤ method ⽅法替代。
更推荐的⽅式是,使⽤ computed 属性,⽽不是命令式(imperative)的watch回调函数。例如:
computed版本
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName //需要⼀个返回值加⼊到实例数据或者修改实例数据
} //computed属性会检测其依赖的实例数据
}
含蓄什么意思})
watch版本
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar' //watch属性,检测已经存在的属性数据,不会⾃动返回为新实例属性数据,所以要先声明
},
watch: {
firstName: function (val) { //观测发⽣改变的属性对象,⽽不观测其依赖的实例数据,所以需要分为两个函数实现功能。
this.fullName = val + ' ' + this.lastName
雅思考试报名费},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
})
对⽐ computed 属性实现的版本,以上代码是命令式和重复的。
computed 属性默认只设置 getter 函数,不过在需要时,还可以提供 tter 函数:
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
computed: {
fullName: {
// getter 函数
get: function () { //get函数观测对象依赖,并返回变化acquire
return this.firstName + ' ' + this.lastName
},
// tter 函数
t: function (newValue) { //t函数观测对象,让你可以在computed中更改对象依赖的数据
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
淘换}
}
}
})
现在当你运⾏vm.fullName = 'John Doe',将会调⽤ tter,然后会对应更新vm.firstName和vm.lastName。
虽然在⼤多数情况下,更适合使⽤ computed 属性,然⽽有些时候,还是需要⼀个⾃定义 watcher。当你需要在数据变化响应时,执⾏异步操作,或⾼性能消耗的操作,⾃定义 watcher 的⽅式就会很有帮助。
<div id="watch-example">
<p>
问⼀个答案是 yes/no 的问题:
<input v-model="question"> //v-modle会将input输⼊值传给question
</p>
<p>{{ answer }}</p>
</div>
<!-- 对于 ajax 库(ajax libraries)和通⽤⼯具⽅法的集合(collections of general-purpo utility methods)来说, -->
<!-- 由于已经存在⼤量与其相关的⽣态系统, -->stir
<!-- 这也可以使你⾃由随意地选择⾃⼰最熟悉的。 -->
<script src="cdn.jsdelivr/npm/axios@0.12.0/dist/axios.min.js"></script>
<script src="cdn.jsdelivr/npm/lodash@4.13.1/lodash.min.js"></script>
<script>
var watchExampleVM = new Vue({
el: '#watch-example',
data: {
question: '',
answer: '你要先提出问题,我才能给你答案!'
},
watch: { //这种需求,不是更新观测对象()或者更新其依赖(computed.t), ⽽是观测变化去做与数据⽆关的操作,computed⽆法实现
// 只要 question 发⽣改变,此函数就会执⾏
question: function (newQuestion, oldQuestion) { //不是很懂两个参数,但我想可能这是watch能监测到的改变之前和之后的对象,
this.answer = '等待输⼊停⽌……'
}
怜悯的意思
},
methods: {
// _.debounce 是由 lodash 提供的函数,
// 在运⾏特别消耗性能的操作时,
// 可以使⽤ _.debounce 来限制频率。
// 在下⾯这种场景中,我们需要限制访问 yesno.wtf/api 的频率,
// 等到⽤户输⼊完毕之后,ajax 请求才会发出。
getAnswer: _.debounce(
function () {
if (this.question.indexOf('?') === -1) {
this.answer = '问题通常需要包含⼀个中⽂问号。;-)'
return
}
this.answer = '思考中……'
var vm = this //ajax请求中的this可能没有指向实例,所以在请求之前先把实例对象this赋值给变量vm
<('yesno.wtf/api')
.then(function (respon) {
vm.answer = _.capitalize(respon.data.answer)
})
.catch(function (error) {
vm.answer = '错误!API ⽆法处理。' + error
})
},
// 这是⽤户停⽌输⼊操作后所等待的毫秒数。
// (译者注:500毫秒之内,⽤户继续输⼊,则重新计时)
500
)
}
})
</script>
class 和 style 绑定
(内联、外部引⽤)这两种⽅式的渲染结果相同。我们还可以将 class 和 style 与某个绑定在⼀起,此 computed 属性所对应的 getter 函数需要返回⼀个对象。这是⼀种常⽤且强⼤的⽤法
<div v-bind:class="classObject"></div> //简写 :class="classObject"
data: {
isActive: true,
error: null
},
computed: { //通过computed属性控制classObjecr对其它class的影响
classObject: function () { //如果classObject属性去除了,先前computed return的样式会恢复吗?
return {
active: this.isActive && !,
'text-danger': && pe === 'fatal'
}
}
}