Vue 实例的选项
通常,模板内容较简单时,使用 data 配合表达式即可;涉及复杂逻辑时,可以用到 computed \ methods \ watch ...
el
el,是 element 的缩写,用于提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标。
类型:string | HTMLElement 写法: el:'#app' // 表示挂载目标为 id是‘app’的元素; 或者 el:document.getElementById('app');
data
data,是 Vue 实例的数据对象。Vue 将会递归将 data 属性转换为 getter / setter,从而让 data 属性能响应数据变化。
类型:Object | Function
写法:组件的定义只接受 Function,所以推荐第二种;另,不应该对data使用箭头函数。
data:{
msg:'HelloWorld'
}
或
data() {
return {
msg:'HelloWorld'
}
}
- Vue 实例创建之后,可以通过
vm.$data访问原始数据对象( data )。Vue 实例代理了 data 对象上所有的属性,因此访问
vm.a等价于访问vm.$data.a。
以,因为它们可能和 Vue 内置的属性、API 方法冲突。_或$开头的属性 不会被 Vue 实例代理你可以使用例如
vm.$data._property的方式访问这些属性。
computed 计算属性
类型:{ [key: string]: Function | { get: Function, set: Function } }
# 代码示例1
computed:{
// 计算属性的getter,值为函数;this 指向 vm 实例
transMsg:function(){
return this.msg + '_你好,世界';
}
}
# 代码示例2:计算属性默认只有getter,不过在需要的时候,也可以提供一个setter
var vm = new Vue({
el:'#app',
data:{
name:'Hello'
},
computed:{
saying:{
get(){
return this.name;
},
set(val){
this.name = val;
}
}
}
});
console.log(vm.saying); // Hello
vm.saying = 'World';
console.log(vm.saying); // World
// 不应该为一个计算属性使用箭头函数
计算属性将被混入到 Vue 实例中。所有 getter 和 setter 的 this 上下文自动地绑定为 Vue 实例。
计算属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。
注意,如果某个依赖(比如非响应式属性)在该实例范畴之外,则计算属性是不会被更新的。
var vm = new Vue({
data: { a: 1 },
computed: {
// 仅读取,值只需为函数( 计算属性默认只有getter )
aDouble: function () {
return this.a * 2
},
// 读取和设置
aPlus: {
get: function () {
return this.a + 1
},
set: function (v) {
this.a = v - 1
}
}
}
})
vm.aPlus // => 2
vm.aPlus = 3
vm.a // => 2
vm.aDouble // => 4
filter 过滤器
计算属性和过滤器都是用来对数据进行相关的修改的方法。过滤器可以用在两个地方:双花括号插值和
v-bind表达式。严格来说,过滤器是计算属性的简化模式,运算比较简单的使用过滤器,比较复杂的则使用计算属性。
// HTML <div id="app"> <p>原始数字:{{num}}</p> // 展示原始数字 <p>修改后的数字:{{num | currencyFilter}}</p> // 展示修改后的数字 // 过滤器的调用方法是在变量后加上中隔线(|),在中隔线后加上过滤器的名字, // 这样过滤器就会自动把前面的数据作为参数添加进去。 </div> // JS var vm = new Vue({ el:'#app', data:{ num:100 }, // 过滤器 filters:{ currencyFilter:function(num){ // 过滤器名称及参数值 return num * 10; // 1000 // 返回处理后的结果 } } });[ 过滤器 & 计算属性 & 方法 ] 新建方法和计算属性没有多大的差别,重点在于调用。
与计算属性相比,过滤器可以在多个地方使用,不像计算属性那样只能处理同样的数据;
与方法相比,过滤器的调用更加简洁。如,当需要多个过滤器处理数据时:
{{ message | filterA | filterB }} // 使用过滤器处理数据,过滤器可以串联 {{ filterB(filterA(message)) }} // 使用方法处理数据
methods 方法
methods 将被混入到 Vue 实例中。可以直接通过 VM 实例访问这些方法,或者在指令表达式中使用。
类型:{ [key: string]: Function }
写法:不应该使用箭头函数来定义 method 函数
methods:{
add:function{
// 函数体
console.log(this.msg);
}
}
或
methods:{
add(){
// 需说明的是,this 指向 vm 实例
// 因此,可以直接使用 this.数据名 访问 data 选项中的数据
}
}
// 方法中的 this自动绑定为 Vue 实例。
var vm = new Vue({
data: { a: 1 },
methods: {
plus: function () {
this.a++
}
}
})
vm.plus()
vm.a // 2
[ 计算属性 - 依赖缓存 vs methods - 重新渲染 ] 对于最终的结果,两种方式确实是相同的。然而,不同的是计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。
这就意味着只要依赖的响应式属性还没有发生改变,多次访问,计算属性会立即返回之前的计算结果,而不必再次执行函数。相比而言,只要发生重新渲染,method 调用总会执行该函数。
我们为什么需要缓存?
假设有一个重要的计算属性 A,这个计算属性需要一个巨大的数组遍历和做大量的计算。然后我们可能有其他的计算属性依赖于 A。如果没有缓存,我们将不可避免的多次执行 A 的 getter !
如果你不希望有缓存,请用 method 替代。
watch 监听器
类型:{ [key: string]: string | Function | Object | Array }
代码示例(承 - 计算属性):
watch:{
// 键是“要观察的数据”,值是对应回调函数,其参数为新值和旧值。
name:function(val,oldVal){
// 函数体
}
}
或
watch:{
name(val,oldVal){
console.log('name值发生了变化,新值为'+ val + ',旧值为' + oldVal); // name值发生了变化,新值为World,旧值为Hello
}
}
// 不应该对watch使用箭头函数
Vue 提供了一种通用的方式来观察和响应 Vue 实例上的数据变动:watch 属性。watch 属性,是一个对象,键是需要观察的表达式,值是对应回调函数,其参数为新值和旧值。值也可以是方法名,或者包含选项的对象。
Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个属性。
var vm = new Vue({
data: {
a: 1,
b: 2,
c: 3,
d: 4,
e: {
f: {
g: 5
}
}
},
watch: {
a: function (val, oldVal) {
console.log('new: %s, old: %s', val, oldVal)
},
// 方法名
b: 'someMethod',
// 该回调会在任何被侦听的对象的 property 改变时被调用,不论其被嵌套多深
c: {
handler: function (val, oldVal) { /* ... */ },
deep: true
},
// 该回调将会在侦听开始之后被立即调用
d: {
handler: 'someMethod',
immediate: true
},
e: [
'handle1',
function handle2 (val, oldVal) { /* ... */ },
{
handler: function handle3 (val, oldVal) { /* ... */ },
/* ... */
}
],
// watch vm.e.f's value: {g: 5}
'e.f': function (val, oldVal) { /* ... */ }
}
})
vm.a = 2 // => new: 2, old: 1
props
类型:Array<String> | Object
props 可以是数组或对象,用于接收来自父组件的数据。
props 可以是简单的数组,或者使用对象作为替代,对象允许配置高级选项,如类型检测、自定义验证和设置默认值。
可以基于对象的语法使用以下选项:
type: 可以是下列原生构造函数中的一种:String、Number、Boolean、Ar ra y、Object、Da te、Function、Symbol、任何自定义构造函数、或上述内容组成的数组。会检查一个 prop 是否是给定类型,否则抛出警告。default:any为该 prop 指定一个默认值。如果该 prop 没有被传入,则换做用这个值。对象或数组的默认值必须从一个工厂函数返回。
required:Boolean定义该 prop 是否是必填项。在非生产环境中,如果这个值为 truthy 且该 prop 没有被传入的,则一个控制台警告将会被抛出。
validator:Function自定义验证函数会将该 prop 的值作为唯一的参数代入。在非生产环境下,如果该函数返回一个 falsy 的值 (也就是验证失败),一个控制台警告将会被抛出。
// 简单语法
Vue.component('props-demo-simple', {
props: ['size', 'myMessage']
})
// 对象语法,提供验证
Vue.component('props-demo-advanced', {
props: {
// 检测类型
height: Number,
// 检测类型 + 其他验证
age: {
type: Number,
default: 0,
required: true,
validator: function (value) {
return value >= 0
}
}
}
})
[ propsData ] // 创建实例时传递 props。主要作用是方便测试。
类型:{ [key: string]: any } 限制:只用于 new 创建的实例中。var Comp = Vue.extend({ props: ['msg'], template: '<div>{{ msg }}</div>' }) var vm = new Comp({ propsData: { msg: 'hello' } })
一般地,当模板内容较简单时,使用 data 选项配合表达式即可。
涉及到复杂逻辑时,需用到 computed、methods、watch 等选项,具体见 Vue 实例(选项及生命周期)?!
计算属性 computed
模板中绑定表达式非常的便利,但设计它们的初衷是用于简单运算。在模板中放入太多的逻辑会让模板过重且难以维护。
// 例如:
<div id="example">
{{ message.split('').reverse().join('') }}
</div>
在这种情况下,模板不再简单和清晰。你必须看一段时间才能意识到,这里是想要显示变量 message的翻转字符串。当你想要在模板中多次引用此处的翻转字符串时,就会更加难以处理。
所以,对于任何复杂逻辑,应当使用计算属性。
你可以像绑定普通属性一样在模板中绑定计算属性。Vue 知道
vm.reversedMessage依赖于vm.message,因此当vm.message发生改变时,依赖于vm.reversedMessage的绑定也会更新。而且,最妙的是我们是声明式地创建这种依赖关系:计算属性的 getter 是干净无副作用的,因此也是易于测试和理解的。
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
})
侦听器 watch
Vue.js 提供了一个方法 $watch,它用于观察 Vue 实例上的数据变动。
[ 计算属性 vs 选项 - watch ] 当一些数据需要根据其它数据变化时,
$watch很诱人。不过,通常更好的办法是使用计算属性,而不是一个命令式的
$watch回调。<div id="demo">{{ fullName }}</div>var vm = new Vue({ el: '#demo', data: { firstName: 'Foo', lastName: 'Bar', fullName: 'Foo Bar' }, watch: { firstName: function (val) { this.fullName = val + ' ' + this.lastName }, lastName: function (val) { this.fullName = this.firstName + ' ' + val } } })上述代码是命令式的和重复的,与计算属性对比(这样不是更好吗?):
var vm = new Vue({ el: '#demo', data: { firstName: 'Foo', lastName: 'Bar' }, computed: { fullName: function () { return this.firstName + ' ' + this.lastName } } })
[ 观察 Warchers ] 虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的 watcher 。
[ vm.$watch API?!] 这是为什么 Vue 提供一个更通用的方法通过
watch选项,来响应数据的变化。当你想要在数据变化响应时,执行异步操作或昂贵操作时,这是很有用的。
<div id="watch-example">
<p>
Ask a yes/no question:
<input v-model="question">
</p>
<p>{{ answer }}</p>
</div>
<!-- 因为 AJAX 库和通用工具的生态已经相当丰富,Vue 核心代码没有重复 -->
<!-- 提供这些功能以保持精简。这也可以让你自由选择自己更熟悉的工具。 -->
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script>
<script>
var watchExampleVM = new Vue({
el: '#watch-example',
data: {
question: '',
answer: 'I cannot give you an answer until you ask a question!'
},
watch: {
// 如果 `question` 发生改变,这个函数就会运行
question: function (newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.debouncedGetAnswer()
}
},
created: function () {
// `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
// 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
// AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
// `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,
// 请参考:https://lodash.com/docs#debounce
this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
},
methods: {
getAnswer: function () {
if (this.question.indexOf('?') === -1) {
this.answer = 'Questions usually contain a question mark. ;-)'
return
}
this.answer = 'Thinking...'
var vm = this
axios.get('https://yesno.wtf/api')
.then(function (response) {
vm.answer = _.capitalize(response.data.answer)
})
.catch(function (error) {
vm.answer = 'Error! Could not reach the API. ' + error
})
}
}
})
</script>
在这个示例中,使用
watch选项允许我们执行异步操作(访问一个 API),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态,这些都是计算属性无法做到的。