熟悉 Vue 的都知道 方法methods、计算属性computed、观察者watcher 在 Vue 中有着非常重要的作用,有些时候我们实现一个功能的时候可以使用它们中任何一个都是可以的,但是它们之间又存在一些不同之处,每一个都有一些适合自己的场景,我们要想知道合适的场景,肯定先对它们有一个清楚的了解,先看一个小例子。
<div> <input v-model="firstName" type="text"> <input v-model="secondName" type="text"> <p>{{fullName}}</p> </div>
methods 方式
var vm = new Vue({ el: "#app", data: { firstName: "Mo", secondName: "deng", fullName: "" }, methods: { getFullName () { this.fullName = this.firstName + "" + this.secondName; } }, mounted () { this.getFullName(); } });
computed 方式
var vm = new Vue({ el: "#app", data: { firstName: "liu", secondName: "deng" }, computed: { fullName () { return this.firstName + "" + this.secondName; } } });
watcher 方式
var vm = new Vue({ el: "#app", data: { firstName: "liu", secondName: "deng", fullName: "liudeng" }, watch: { firstName: function (value) { this.fullName = value+ "" + this.secondName }, secondName: function (value) { this.fullName = this.firstName + "" + value } } });
我们看到上面三种方法实现一个相同的效果,虽然效果相同,但是我们每个方法之间会有所区别。
methods 方法
在我们使用 Vue 时可能会有很多方法会被放到这里,比如它可能是我们的事件处理方法,一些操作方法的逻辑等等,但是它不能跟踪任何依赖,而且还会在每次组件重新加载时都会执行,这就会导致我们的方法会执行很多次,如果我们的 UI 操作频繁的话,会导致性能的问题,所以在一些开销比较大的计算时,我们应该尝试其他方案进行优化处理。
computed 计算属性
从名字我们其实大概的可以看出,它是一个依赖于其他属性的,当依赖的属性发生变化的时候就会触发我们计算属性的逻辑,而且是基于它们依赖的属性进行缓存的,也就是说只有当依赖的属性发生变化的时候才会从新求值。
相比 methods 的优势在于不必每次从新执行定义的函数,这给我们的性能上有着很大的优势,对我们已经存在的数据属性非常好的处理方式,例如我们案例中 fullName 的计算,优势非常明显。
watcher 观察者
当一些数据属性变化时,我们执行一些逻辑时观察者对我们非常重要,它可以帮助我们监听属性的变化,只要属性发生变化,我们就可以执行对应的一些操作。
如何实现一个 TodoList
在 methods 中我们放置了一些事件处理方法,我们可以在事件绑定中直接应用,不会依赖于任何的属性。
<button type="button" @click="removeTodoItem(item)">x</button>
export default { name: "TodoList", data() { return { todoType: "all", //任务类型 allTodoItems: [], }; }, methods: { //... 省略 //添加任务 addItem() { this.allTodoItems.push({ id: this.allTodoItems.length, text: this.itemText, completed: false }); this.itemText = ""; }, //删除任务 removeTodoItem(item) { this.allTodoItems = this.allTodoItems.filter( value => value.id != item.id ); } } };
我们可以看到计算属性都是依赖于其他属性的,只有当依赖的属性值发生改变时,我们的计算属性才会发生变化。
例如:passTodoItems 计算属性依赖于 todoType 属性,只要 todoType 属性发生变化,我们的 passTodoItems 也会发生变化,从而筛选出我们需要的数据。
export default { name: "TodoList", data() { return { todoType: "all", //任务类型 allTodoItems: [], }; }, computed: { //展示的任务 passTodoItems() { return this[this.todoType](this.allTodoItems); }, //是否显示底部的选项 isShowOptions() { return this.allTodoItems.length; } } }
可以看到我们利用 watcher 进行数据的存储逻辑操作,只要当我们监听的属性 allTodoItems 发生变化时,我们就把数据进行保存。
export default { name: "TodoList", data() { return { todoType: "all", //任务类型 allTodoItems: [], }; }, watch: { allTodoItems: { handler() { localStorage.setItem("todoItems", JSON.stringify(this.allTodoItems)); }, deep: true //深度监听对象属性的变化,如果没有检测不到对象属性的变化 } } }
总结
通过一个简单的 TodoList 案例展示了 methods、computed、watcher 三者的用法,当然我们的实战项目中不仅仅是这么简单。
我们再使用 methods、computed、watcher 时,应该选择它们合适的使用场景,虽然它们可以实现相同的结果。
methods 一般定义一些事件处理方法,操作方法,因为会频繁的触发,所以会引起性能问题,一般不会用在操作频繁的地方。
computed 会依赖于其他已经存在的属性,而且会进行缓存,只有在依赖的属性发生变化时,计算属性才会发生改变,开销大的地方使用较多。
watcher 它提供了一个更通用的方法来监听我们的属性,当我们的属性变化是执行一些逻辑的操作。