background
In VUE, the same functional requirement can be implemented using normal methods as well as computed and Watch attributes, and there was some confusion at first about how to use them
When do you use methods, when do you use computed properties, and watch properties, that’s always a headache
Different methods are suitable for different scenarios. Here is the content of this article
Demand scenarios
Input A,B two numbers and sum, when the sum result meets the specified conditions, specify the age of the result
result <= 6=> A child result >6 && result <= 17= >"Age is a young man."
result > 17 && result <=40= >"Age is a young man"
result > 40 && result <=65= >"Age is a middle-aged man."
result > 65 && result <=100= >"Age is an old man."
isNaN(result))=> "Your input is incorrect."
result > 100 "Old, over a hundred years old, still on earth?"
Copy the code
Specific effect demonstration
Demand analysis
- The initialization value
A
.B
Two Numbers - Calculate the sum of the two numbers and make the corresponding logical judgment
Approach 1- Implemented using a template
In vUE templates, simple logical judgments can be made in interpolation expressions
The specific code is shown below
<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta < span style>. Box-sizing: border-box! Important; word-wrap: break-word! Important; 35%; margin-top: 100px; } </style> </head> <body> <div id="root"> <div class="box"> A: <input type="number" v-model:value="A" /> <span>+</span> B: <input type="number" v-model:value="B" /> <button>=</button> <span>{{ parseInt(A)+parseInt(B) }}</span><br /><br /> The < div > result: {{A}} + {{B}} = {{parseInt (A) + parseInt (B)}} < span v - if = "(parseInt (A) + parseInt (B)) is A children aged < = 6" > < / span > < span V - else - if = "(parseInt (A) + parseInt (B)) > 6 && (parseInt (A) + parseInt (B)) < =" > 17 years old boy < / span > < span V-else if="(parseInt(A)+parseInt(B)) > 17 && (parseInt(A)+parseInt(B)) <= 40" V-else if="(parseInt(A)+parseInt(B)) > 40 && (parseInt(A)+parseInt(B)) <= 65" V-else if="(parseInt(A)+parseInt(B)) > 65 && (parseInt(A)+parseInt(B)) <= 100" <span > <span style =" box-sizing: border-box; color: RGB (74, 74, 74); line-height: 22px; font-size: 14px! Important; word-break: inherit! Important; V - else = "isNaN (parseInt (A) + parseInt (B))" > the information you entered is wrong < / span > < / div > < / div > < / div > < script SRC = ". / js/vue. Js "> < / script > <script> const vm = new Vue({ el: "#root", data() { return { A: "4", B: '5', } } }) </script> </body> </html>Copy the code
Using expressions to handle simple logic in vUE templates is very convenient, but it is only suitable for simple operations. If the logic is complex, maintaining the template becomes cumbersome and unintuitive
advice
For complex logic, you should use methods or calculate computed properties
Additional development
Why is the value of data written as a function instead of an object?
* * * * briefly
When a component is defined,data must be declared as a function that returns an initial data object, because the component may be used to create multiple instances
That is, components defined on many pages can be reused across multiple pages
If data is a pure object, all instances will share references to the same data object, and any modification of data in any component instance will affect all component instances
If data is a function, the data function is called each time a new instance is created, returning a new copy of the original data as a data object
Each time a component is reused, a new data is returned, similar to creating a private data space for each component instance, so that each component instance is independent of each other
Method 2- Implemented using normal methods
The sample code is shown below, defining a method (function) in methods and calling a direct method (function name ()) in a VUE template
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>01- Implemented using normal methods</title>
<style>
.box {
margin-left: 35%;
margin-top: 100px;
}
</style>
</head>
<body>
<div id="root">
<div class="box">
A: <input type="number" v-model:value="A" />
<span>+</span>
B: <input type="number" v-model:value="B" />
<button>=</button>
<span>{{ addResult() }}</span><br /><br />
<div>Results: {{A}} +{{B}} = {{addResult()}} {{outPut()}}</div>
</div>
</div>
<script src="./js/vue.js"></script>
<script>
const vm = new Vue({
el: "#root".data() {
return {
A: "4".B: '5',}},methods: {
addResult() {
return parseInt(this.A)+parseInt(this.B)
},
outPut() {
const result = parseInt(this.A)+parseInt(this.B);
if(result <= 6) {
return "Age is a child."
}else if(result > 6 && result <= 17) {
return "Age is a young man."
} else if(result > 17 && result <=40) {
return "Age is a young man"
}else if(result > 40 && result <=65) {
return "Age is a middle-aged man."
}else if(result > 65 && result <=100) {
return "Age is an old man."
}else if(isNaN(result)) {
return "Your input is incorrect."
}else {
return "Old, over a hundred years old, still on earth?"}}}})</script>
</body>
</html>
Copy the code
The above is to define methods in methods to achieve
Matters needing attention
With normal methods, when implemented, every time a method is triggered, the page is re-rendered and the method function is executed, which is not cached
If you have a computationally expensive property, it needs to iterate over a large array and do a lot of computations, and the computationally expensive property has other dependencies, and if you don’t have a cache, you don’t need to compute the property, then you’re constantly executing the getter that collects the property, and if you don’t want a cache, you use a method instead
Method 3- Use computed properties for a computed implementation
In the VUE instance configuration option, add a computed property, where the value is an object, and add the computed property that corresponds to it
The computed value of the property is the result of a previously cached calculation and is not executed more than once
The example code is shown below
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>02- Implemented using computed attributes</title>
<style>
.box {
margin-left: 35%;
margin-top: 100px;
}
</style>
</head>
<body>
<div id="root">
<div class="box">
A: <input type="number" v-model:value="A" />
<span>+</span>
B: <input type="number" v-model:value="B" />
<button>=</button>
<span>{{ addResult }}</span><br /><br />
<div>{{A}} +{{B}} = {{addResult}} {{outPut}}</div>
</div>
</div>
<script src="./js/vue.js"></script>
<script>
const vm = new Vue({
el: "#root".data() {
return {
A: "4".B: '5',}},computed: {
addResult: { // The original way of writing
get() {
return parseInt(this.A)+parseInt(this.B)
}
},
outPut: {
get() {
const result = parseInt(this.A)+parseInt(this.B);
if(result <= 6) {
return "Age is a child."
}else if(result > 6 && result <= 17) {
return "Age is a young man."
} else if(result > 17 && result <=40) {
return "Age is a young man"
}else if(result > 40 && result <=65) {
return "Age is a middle-aged man."
}else if(result > 65 && result <=100) {
return "Age is an old man."
}else if(isNaN(result)) {
return "Your input is incorrect."
}else {
return "Old, over a hundred years old, still on earth?"}}}}})</script>
</body>
</html>
Copy the code
Warm prompt
Once you determine that the calculated property reads only (get) and does not modify the set, you can use the shorthand form, equivalent to the following
// Other ellipses, as shown above
computed: {
// Once you are sure that the calculated property only reads (get) and does not modify set, you can use the shorthand form
// If it is read-only, you can use the shorthand form
addResult() {
return parseInt(this.A)+parseInt(this.B)
},
outPut() {
const result = parseInt(this.A)+parseInt(this.B);
if(result <= 6) {
return "Age is a child."
}else if(result > 6 && result <= 17) {
return "Age is a young man."
} else if(result > 17 && result <=40) {
return "Age is a young man"
}else if(result > 40 && result <=65) {
return "Age is a middle-aged man."
}else if(result > 65 && result <=100) {
return "Age is an old man."
}else if(isNaN(result)) {
return "Your input is incorrect."
}else {
return "Old, over a hundred years old, still on earth?"}}}})Copy the code
Matters needing attention
-
The result of calculating a property, instead of mounting it under data to initialize the data, can be used directly in the Vue template without parentheses to calculate the property name (), which is different from ordinary method calls
-
Putting too much logic into a template can make it too heavy, hard to maintain, and unintuitive (simple logic can be handled in a template)
-
For complex logic, you can use calculated properties (the getter function of calculated properties has no side effects, but you can also use methods, but the calculated properties have a large amount of calculation, caching the calculation results, and higher performance. Frequent method calls, template parsing, and page rendering consume performance).
-
Computed properties are cached based on their reactive dependencies, they are reevaluated only when the associated reactive dependencies change, and the vUE template is parsed each time a rerender is triggered, as opposed to a call to a normal method that executes a function
Method 4- using the Watch listening property
- through
vm
The object’s$watch()
orwatch
Configure to monitor the specified properties - When the property changes, the callback function is called automatically and evaluated inside the function
Concrete example code
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>03- Listen to the watch method implementation</title>
<style>
.box {
margin-left: 35%;
margin-top: 100px;
}
</style>
</head>
<body>
<div id="root">
<div class="box">
A: <input type="number" v-model:value="A" />
<span>+</span>
B: <input type="number" v-model:value="B" />
<button>=</button>
<span>{{ addResult }}</span><br /><br />
<div>{{A}} +{{B}} = {{addResult}} {{outPut}}</div>
</div>
</div>
<script src="./js/vue.js"></script>
<script>
const vm = new Vue({
el: "#root".data() {
return {
A: "4".B: '5'.addResult: ' '.outPut: ' '}},watch: {
A: {
immediate: true.// Call it when it is initialized by handler. Default is false
handler(newVal,oldVal) {
console.log("A has changed."."The latest :",newVal,"Old.",oldVal);
this.addResult = parseInt(newVal)+parseInt(this.B)
const result = parseInt(this.addResult);
if(result <= 6) {
this.outPut = "Age is a child."
}else if(result > 6 && result <= 17) {
this.outPut = "Age is a young man."
} else if(result > 17 && result <=40) {
this.outPut = "Age is a young man"
}else if(result > 40 && result <=65) {
this.outPut = "Age is a middle-aged man."
}else if(result > 65 && result <=100) {
this.outPut = "Age is an old man."
}else if(isNaN(result)) {
this.outPut= "Your input is incorrect."
}else {
this.outPut = "Old, over a hundred years old, still on earth?"}}},B: {
immediate: true.handler(newVal, oldVal) {
console.log("B has changed."."Up to date",newVal,"Old",oldVal);
this.addResult = parseInt(this.A)+parseInt(newVal);
const result = parseInt(this.addResult);
if(result <= 6) {
this.outPut = "Age is a child."
}else if(result > 6 && result <= 17) {
this.outPut = "Age is a young man."
} else if(result > 17 && result <=40) {
this.outPut = "Age is a young man"
}else if(result > 40 && result <=65) {
this.outPut = "Age is a middle-aged man."
}else if(result > 65 && result <=100) {
this.outPut = "Age is an old man."
}else if(isNaN(result)) {
this.outPut= "Your input is incorrect."
}else {
this.outPut = "Old, over a hundred years old, still on earth?"}}}},})</script>
</body>
</html>
Copy the code
If the data in the response does not require immediate:true,deep: true, we can abbreviate the above watch, which is equivalent to the following
Pay attention to
If written in shorthand, configuration options cannot be written
// Other parts are omitted, as shown above
watch: {
// Equivalent to the following
A(newVal) { // The newVal parameter refers to the current monitoring attribute, the latest value, can be one or two (newVal,oldVal)
this.addResult = parseInt(newVal)+parseInt(this.B)
const result = parseInt(this.addResult);
if(result <= 6) {
this.outPut = "Age is a child."
}else if(result > 6 && result <= 17) {
this.outPut = "Age is a young man."
} else if(result > 17 && result <=40) {
this.outPut = "Age is a young man"
}else if(result > 40 && result <=65) {
this.outPut = "Age is a middle-aged man."
}else if(result > 65 && result <=100) {
this.outPut = "Age is an old man."
}else if(isNaN(result)) {
this.outPut= "Your input is incorrect."
}else {
this.outPut = "Old, over a hundred years old, still on earth?"}},B(newVal) {
console.log("B has changed."."Up to date",newVal,"Old");
this.addResult = parseInt(this.A)+parseInt(newVal);
const result = parseInt(this.addResult);
if(result <= 6) {
this.outPut = "Age is a child."
}else if(result > 6 && result <= 17) {
this.outPut = "Age is a young man."
} else if(result > 17 && result <=40) {
this.outPut = "Age is a young man"
}else if(result > 40 && result <=65) {
this.outPut = "Age is a middle-aged man."
}else if(result > 65 && result <=100) {
this.outPut = "Age is an old man."
}else if(isNaN(result)) {
this.outPut= "Your input is incorrect."
}else {
this.outPut = "Old, over a hundred years old, still on earth?"}}}})Copy the code
Of course,Vue provides the $watch instance method, which can also be written this way
<script>
const vm = new Vue({
el: "#root".data() {
return {
A: "4".B: '5'.addResult: ' '.outPut: ' '}},// Equivalent to the following
vm.$watch('A', {immediate: true.The default value is false. If you do not write this, you will not call the handler function for the first time
handler(newVal,oldVal) {
console.log("A has changed."."The latest :",newVal,"Old.",oldVal);
this.addResult = parseInt(newVal)+parseInt(this.B)
const result = parseInt(this.addResult);
if(result <= 6) {
this.outPut = "Age is a child."
}else if(result > 6 && result <= 17) {
this.outPut = "Age is a young man."
} else if(result > 17 && result <=40) {
this.outPut = "Age is a young man"
}else if(result > 40 && result <=65) {
this.outPut = "Age is a middle-aged man."
}else if(result > 65 && result <=100) {
this.outPut = "Age is an old man."
}else if(isNaN(result)) {
this.outPut= "Your input is incorrect."
}else {
this.outPut = "Old, over a hundred years old, still on earth?"}}})// Equivalent to monitoring the B property as shown below
vm.$watch('B', {
immediate: true.// Call some handler functions during initialization. Otherwise, the handler function would not be called the first time
handler(newVal, oldVal) {
console.log("B has changed."."Up to date",newVal,"Old",oldVal);
this.addResult = parseInt(this.A)+parseInt(newVal);
const result = parseInt(this.addResult);
if(result <= 6) {
this.outPut = "Age is a child."
}else if(result > 6 && result <= 17) {
this.outPut = "Age is a young man."
} else if(result > 17 && result <=40) {
this.outPut = "Age is a young man"
}else if(result > 40 && result <=65) {
this.outPut = "Age is a middle-aged man."
}else if(result > 65 && result <=100) {
this.outPut = "Age is an old man."
}else if(isNaN(result)) {
this.outPut= "Your input is incorrect."
}else {
this.outPut = "Old, over a hundred years old, still on earth?"}}})</script>
Copy the code
For the watch attribute, it is a very useful attribute. If some data needs to be monitored, such as comparison and transformation of old and new data, and some logical operations when certain conditions are met, watch can monitor the attributes under data and also monitor the attributes of calculated results
About the writing time of watch and $watch
-
If it is clear which data you want to monitor, say Watch when preaching concept examples
-
If you don’t know which data to monitor at instance creation time and which data to monitor later based on some user behavior, you can use the $watch API
-
When the monitored property changes, the callback function is called automatically to perform the related operation
-
The monitoring attribute must exist in order to monitor
-
There are two ways to monitor data: one is to pass in the watch configuration option when a Vue object is instantiated, and the other is vm.$watch
Deep monitoring in Watch
These are all directly listening for properties mounted directly under data. What if we want to listen for individual properties under an object? As shown below.
const vm = new Vue({
el: '#root'.data() {
return {
info: {
name: 'itclanCoder'.// Want to listen for a single attribute in the INFO object
age: 4}}},// Listen for changes to an attribute in a multilevel structure
watch: {
'info.name': {
console.log("Name property under info changed"); }}})Copy the code
In Vue, internal value changes are not monitored by default. If you want to monitor changes in every property under an object (that is, monitoring multi-hierarchies), you can turn on the deep: True configuration, as shown below
const vm = new Vue({
el: '#root'.data() {
return {
info: {
name: 'itclanCoder'.age: 4}}},// Listen for changes to an attribute in a multilevel structure
watch: {
info: {
immediate: true.// The handler function is called immediately upon initialization
deep: true.// Enable depth monitoring
handler() {
console.log("Name and age are both triggered."); }}}})// this is equivalent to the following notation
vm.$watch('info', {immediate: true.// The handler function is called immediately upon initialization
deep: true.// Enable depth monitoring
handler() {
console.log("Name and age are both triggered."); }})Copy the code
: : : tip
vm.$watch('info'.function(newVal,oldVal) { // Do not write arrow function here, write normal function, otherwise this binding will be wrong
console.log("New value",newVal,"Old value",oldVal); }, {immediate:true.deep: true
})
Copy the code
When you change (not replace) an object or array, the old value is the same as the new value because their references point to the same object/array. Vue does not keep a copy of the value before the change
warning
-
Do not write arrow functions for vUE – managed functions
-
Evaluate property get,set cannot be written as an arrow function
Watch supports asynchronous task maintenance data
Key contents:
Using Watch is most useful when you need to perform asynchronous or expensive operations when data changes, and computed doesn’t do that (by returning values)
watch: {
// Equivalent to the following
A(newVal) { // The newVal parameter refers to the current monitoring attribute, the latest value, can be one or two (newVal,oldVal)
setTimeout(() = > { // The callback function cannot be written as a normal function, otherwise this will point to the window and cause problems
this.addResult = parseInt(newVal)+parseInt(this.B)
const result = parseInt(this.addResult);
if(result <= 6) {
this.outPut = "Age is a child."
}else if(result > 6 && result <= 17) {
this.outPut = "Age is a young man."
} else if(result > 17 && result <=40) {
this.outPut = "Age is a young man"
}else if(result > 40 && result <=65) {
this.outPut = "Age is a middle-aged man."
}else if(result > 65 && result <=100) {
this.outPut = "Age is an old man."
}else if(isNaN(result)) {
this.outPut= "Your input is incorrect."
}else {
this.outPut = "Old, over a hundred years old, still on earth?"}},2000)}}})Copy the code
Sometimes, we want to delay the implementation of the corresponding logic, so watch can effectively start an asynchronous task
From the picture above
-
Computed: Monitors dependency values. If the dependency values remain unchanged, the cache is directly read for reuse, and if the dependency values change, the cache is recalculated
-
Watch: Monitors the value of the property, and any change to the property triggers the execution of a callback function to perform a series of operations
However,computed does not work. Computed depends on the return value, and watch depends on the code you write by yourself
There is no way to start asynchronous tasks in computing properties, which must be executed synchronously to maintain data, but Watch can
Computed is recommended when both watch and computed are possible, but watch is required when you are dealing with implementing some asynchronous tasks
The difference between computed and Watch
The watch can do what computed can do
Computed tomography may not be able to do what watch can, for example, do
Two important little differences
-
Vue-managed functions are best written as normal functions so that this refers to a VM or component instance object
-
All functions not managed by VUE (timer callbacks, Ajax callbacks, Promise callbacks, etc.) are best written as arrow functions, so that this points to the VM or component instance object
conclusion
The same function can be realized in VUE. For simple logical functions, templates can be used, followed by methods (but without the ability of data caching). If the logic is very complex and data needs to be cached, computational attributes can be used, and watch attributes can also be realized
In normal development, computational attributes are preferred, which is easier and more convenient, but if you want to perform asynchronous tasks, you have to use watch, which can do everything computed, but not the other way around
Comparison of computed and Watch in Vuejs