The difference between watch and computed in vue
1, Watch (listener: used to listen for changes in attributes in data or prop)
1. Listen for simple data types
It will not be executed during initial binding. The listening calculation will not be executed until the firstName is changed
<div> <div> <p>FullName: {{fullName}}</p> <p>FirstName: <input type="text" v-model="firstName"></p> </div> </div>
export default { data () { return { firstName: 'Foo', fullName: '', } }, watch: { firstName(newName, oldName){ this.fullName = newName } } }
2.handler method and immediate attribute
Note that the handler method must be used when using the immediate attribute. The watch method we wrote before actually writes this handler by default, Vue JS will handle this logic, and the final compiled handler is actually this handler. When the handler is false, as above, it will not be executed when Binding; When the handler is true, it means that the handler method in wacth will be executed immediately after the firstName is declared.
export default { data () { return { firstName: 'Foo', fullName: '', } }, watch: { firstName:{ handler(newName, oldName){ this.fullName = newName }, // *After declaring the firstName method in wacth, the delegate immediately executes the handler method* immediate: true } } }
3.deep attribute
The default value is false, which indicates whether to listen deeply
When it is necessary to monitor the changes of an object, the ordinary watch method cannot monitor the changes of the internal attributes of the object. Only the data in data can monitor the changes. At this time, the deep attribute is required to deeply monitor the object.
<div> <input type="text" v-model="cityName.name"/> </div>
export default { data () { return { cityName: {id: 1, name: 'shanghai'}, } }, watch: { cityName:{ handler(newName, oldName){ console.log("newName",newName) console.log("oldName",oldName) }, deep:true // Changes in the property values of the cityName object can be detected in depth } } }
console. The result of log printing shows that the oldName and newName values are the same, so although deep listening can monitor the changes of the object, it cannot monitor the changes of the attribute in the specific object
The reason why the oldName and newName values are the same is that they index the same object / array. Vue does not keep a copy of the value before modification - > vm.$ Deep monitoring of watch
3.1 single attribute of listening object
If you listen to an object (equivalent to adding listeners to all attributes of the object and traversing layer by layer), the performance overhead will be very large. Modifying any attribute in obj will trigger the handler in the listener, so we can use string listening.
Method 1: you can directly use the object The method of the property gets the property
watch: { 'cityName.name':{ handler(newName, oldName) { console.log("newName",newName) console.log("oldName",oldName) }, deep: true, immediate: true } }
Method 2: if the watch wants to monitor the change of a single attribute of the object, it must use computed as the middleware conversion, because computed can get the corresponding attribute value
computed:{ cityNameChange(){ return this.cityName.name } }, watch: { cityNameChange(newName, oldName){ console.log('cityName of name The attribute value has changed') } }
4. Monitor routing
You can use watch to listen for routes
watch: { '$route'(to,from){//To indicates the interface to go to, and from indicates which interface to come from console.log("to",to;"from",from); if(to.path=="/personal"){ console.log("Personal page"); } } }
5.watch does not support caching and supports asynchrony
<div> <p> Ask a yes/no question: <input v-model="question"> </p> <p>{{ answer }}</p> </div>
export default { data () { return { question: '', answer: 'I cannot give you an answer until you ask a question!' } }, watch: { question: function (newQuestion, oldQuestion) { this.answer = 'Waiting for you to stop typing...' this.debouncedGetAnswer() } }, mounted() { //Reference external js files //1. Simple and rough, directly in the index of Vue project Html is introduced in a global way: < script SRC = ".. / xxx. JS" > < / script > //2. If it is a static file downloaded locally, you can import it by using the import method: import {XXX} from '/ js/xxx. JS' / / note the path //3. After the Vue component is loaded, manually operate the DOM to insert the js plug-in, as shown in the following code let script = document.createElement('script'); script.type = 'text/javascript'; script.src = 'https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js'; document.body.appendChild(script); }, created: function () { this.debouncedGetAnswer = this.getAnswer }, 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 }) } } }
2, Computed (calculated attribute)
Computed properties are cached based on their responsive dependencies. They are re evaluated only when the relevant responsive dependencies change.
It is a calculation attribute, similar to a filter, which processes the data bound to the view.
When you have some data that needs to change with other data changes, you can easily abuse the watch. However, it is usually better to use calculated properties rather than mandatory watch callbacks.
1. computed is used to monitor the variables defined by itself. The variables are not declared in data, but directly defined in computed. Then, two-way data binding can be carried out on the page to display the results or used for other processing
You can bind calculated properties in the template as you bind ordinary properties. Vue knows VM Reversedmessage depends on VM Message, so when VM When message changes, all dependent VMS The binding of reversedmessage will also be updated. And the best thing is that we have created this dependency declaratively: the getter function that calculates the attribute has no side effects, which makes it easier to test and understand.
<div> <p>Original message: "{{ message }}"</p> <p>Computed reversed message: "{{ reversedMessage }}"</p> </div>
export default { data () { return { message: 'Hello' } }, computed: { // getter of calculated property reversedMessage: function () { // `this ` points to the vm instance return this.message.split('').reverse().join('') } } }
2. computed is more suitable for returning a result value after processing multiple variables or objects, that is, if a value in several variables changes, the value we monitor will also change
For example, the relationship between the commodity list in the shopping cart and the total amount should change as long as the quantity of commodities in the commodity list changes, or decreases or increases or deletes commodities. The total amount here is calculated using the calculated attribute, which is the best choice
<div> <table border=1 width="200"> <tr> <th width="100px">commodity</th> <th width="100px">Price</th> <th width="100px">quantity</th> </tr> <tr v-for="(item,index) in results" :key="index" align="center"> <td>{{item.name}}</td> <td>{{item.price | priceFilter}}</td> <td><input v-model="item.theNum"></td> </tr> <tr> <td colspan="3" style="text-align:right">total:{{totalMoney | priceFilter}}element</td> </tr> </table> </div>
export default { data () { return { results:[ { name:"Apple", price:1000, theNum:3 }, { name:"Banana", price:1500, theNum:2 }, { name:"watermelon", price:3000, theNum:1 }, ] } }, filters:{ priceFilter(value){ if (!value) return '' return '¥'+(value/100).toFixed(2) }, }, computed: { totalMoney(){ let total = 0; let _this = this; _this.results.forEach(item => { //Calculate total price total += item.price * item.theNum; }); return total } } }
3. Calculate the setter of the attribute
By default, there is only getter for calculating properties, but you can also provide a setter when necessary
<div> <p>firstName:{{ firstName }}</p> <p>lastName:{{ lastName }}</p> <p>fullName:{{ fullName }}</p> </div>
export default { data () { return { firstName: 'Foo', lastName: 'Bar' } }, computed: { fullName:{ get(){//The callback function is executed when the current property value needs to be read, and calculates and returns the value of the current property according to the relevant data return this.firstName + ' ' + this.lastName }, set(val){//Monitor the change of current attribute value, execute when the attribute value changes, and update relevant attribute data //val is the latest attribute value of fullName const names = val.split(' '); this.firstName = names[0]; this.lastName = names[1]; } } } }
Now run app When fullname = 'John Doe', setter will be called, app Firstname and app LastName will be updated accordingly.
3, The difference between computed and watch
1. watch characteristics
1. It is the action of observation
2. Application: listen to props, $emit or the value of this component to perform asynchronous operation
3. There is no caching, and the page will be executed without changing the value when it is re rendered
4. The monitored attribute in watch must already exist, either in data or calculated
5. You can only listen to one attribute at a time. This attribute function receives two parameters, one is the new value and the other is the old value
2. computed feature
1. Is the calculated value
2. Application: it is to simplify the calculation and processing of props or $emit value transfer in tempalt
3. With caching, the page re rendering value does not change, and the calculation attribute will immediately return the previous calculation result without executing the function again
4. The custom attributes in calculated cannot be duplicate with those in data, otherwise an error will be reported
5. It can listen to one or more data items it depends on