作为常用的vue实例属性,方法可以用于事件也可以被其他属性调用或则插值表达式以及v-指令中使用。但是与watch和computed的差异存在许多知识点值得去学习和区分。
methods属性
methods的结构相比watch和computed是最“正常”的。
methods: {
fn(){
......
},
fun:function(){
......
}
},
使用场景
- 事件中使用:
<button @click='fn()'>+1</button>
<button onclick='vm.fn()'>+1</button>
所有data属性和方法在实例vue的过程中赋值给实例对象,在v-指令或插值表达式外我们可以通过vue实例来访问。
- 插值表达式中:
<div>方法fn的返回值:{{fn()}}</div>
插值表达式以及后面的v-指令都是在被加载到真实dom后其中的方法就会被执行。
- v-指令(属性)中:
<div v-if="fn()">方法fn返回值为true</div>
- 其他实例属性调用:
computed: {
sum() {
this.fn();
return this.num1 + this.num2
},
}
这里其实就是去实例上找该方法。
差异比较
methods、computed、watch比较
-
最特别的watch,watch的中的方法必须与监听data变量名一致,不能主动调用。
-
其次是computed,虽然可以被调用,但是使用时当作变量而不是函数,得到的值就是返回值。如果按照函数格式写反而报错。computed目的是将
插值表达式中复杂运算专门写入函数中以此低耦复用。并且存在依赖缓存,只有返回值直接依赖的变量发生变化才会重新执行computed函数否则从缓存中取出上一次计算的结果直接使用。其次具有第二种写法,即包含set和get的集合对象。 -
methods上面也简单介绍了,如果需求场景不是上面两种我们就写成方法(废话)。
命名冲突
如果methods、computed、watch以及data中出现相同的变量名(方法也有变量名)结果会怎么样?
首先我要提出,规范问题:原则上不允许向this中添加的属性出现重名,其次eslint语法检测默认也会报错。
然后我们讨论底层可行性:通过initState函数初始化vue实例,我们将methods、computed、watch以及data等属性中的值挂载到this中去,而对象的赋值特点就是没有自动添加,有则进行覆盖,所以根据底层赋值顺序就可以知道谁在后面重名谁就会覆盖前面的同名变量。
- initState函数源码:
function initState(vm) {
vm._watchers = [];
var opts = vm.$options;
if(opts.props) {
initProps(vm, opts.props); //初始化props
}
if(opts.methods) {
initMethods(vm, opts.methods); //初始化methods
}
if(opts.data) {
initData(vm); //初始化data
} else {
observe(vm._data = {}, true /* asRootData */ );
}
if(opts.computed) {
initComputed(vm, opts.computed); //初始化computed
}
if(opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch); //初始化watch
}
}
引用他人文章: vue数据初始化--initState
watch要求与data中数据同名用于监听,所以不存在覆盖。其次如果vue组件实例中没有该属性则不能成功监听,属性必须存在于props、data或computed中。