1. Vue Foundation_ Update detection, key function
We mentioned the v-for array in the previous chapter, so our requirement is how the v-for array changes and needs to be updated to the page synchronously. However, not all array methods will cause v-for update.
<template> <div> <ul> <li v-for="(val, index) in arr" :key="index"> {{ val }} </li> </ul> <button @click="revBtn">Array flip</button> <button @click="sliceBtn">Intercept the first 3</button> <button @click="updateBtn">Update first element value</button> </div> </template> <script> export default { data(){ return { arr: [5, 3, 9, 2, 1] } }, methods: { revBtn(){ // 1. Array flipping allows v-for to update this.arr.reverse() }, sliceBtn(){ // 2. Array slice method will not cause v-for update // slice does not change the original array // this.arr.slice(0, 3) // Resolve v-for update - overwrite original array let newArr = this.arr.slice(0, 3) this.arr = newArr }, updateBtn(){ // 3. When updating a value, v-for cannot be monitored // this.arr[0] = 1000; // Solve - this$ set() // Parameter 1: update target structure // Parameter 2: update location // Parameter 3: update value this.$set(this.arr, 0, 1000) } } } </script> <style> </style>
The above lists the cases of array flip, array interception and array update value. Among them, push,pop,shift,unshift,splice,sort,reverse and other array methods will cause v-for update.
However, methods such as filter, concat and slice will not cause updates, so we can use the method of overwriting the array.
However, for the operation of assignment, we can use this$ set()
So how does v-for update the DOM?
Loop out the new virtual DOM structure, compare it with the old virtual DOM structure, and try to reuse the label to update the content in place. Compare the changes in memory and patch the real dom
Let's review the real DOM tree we learned before. On the document object, render to the label displayed on the browser
The essence of virtual DOM is a JS object that holds node information, attributes and content.
Why use virtual DOM? Due to too many real DOM attributes and time-consuming traversal, a diff algorithm is introduced below. If the root element changes in the same root comparison, the whole DOM tree will be deleted and rebuilt; Peer comparison if the root element remains unchanged, the attribute changes and the attribute is updated
If the sub tag or content in the tag changes, how does the diff algorithm change? Now let's introduce the keyword key to understand how the key is used
<template> <div> <ul> <li v-for="(val, ind) in arr" :key="ind"> {{ val }} </li> </ul> <button @click="btn">Insert new at subscript 1</button> </div> </template> <script> export default { data(){ return { arr: ['boss', "penis", 'Old three'] } }, methods: { btn(){ this.arr.splice(1, 0, 'incoming') } } } </script> <style> </style>
In the above code, I used: key=ind to indicate that the key is the index value, starting from 0. Generally, for arrays, this can be set. In this way, when we do not set the key, the update mechanism is shown in the figure below
We will try to modify / reuse elements of the same type to the greatest extent, that is, we have added a Li, and the values of the following three li will change.
After we set the key value as the index, we compare it according to the key and update it locally, that is, this method has the same effect as the above keyless method.
When we set the key value, the only string or number that does not duplicate is the id, as shown below
<template> <div> <ul> <li v-for="obj in arr" :key="obj.id"> {{ obj.name }} <input type="text"> </li> </ul> <button @click="btn">Insert new at subscript 1</button> </div> </template> <script> export default { data() { return { arr: [ { name: 'boss', id: 50 }, { name: 'penis', id: 31 }, { name: 'Old three', id: 10 } ], }; }, methods: { btn(){ this.arr.splice(1, 0, { id: 19, name: 'incoming' }) } } }; </script> <style> </style>
The final effect is shown in the figure below
In principle, there is id for id and no id for index, and the key can cooperate with the virtual DOM to improve the update performance.
The above contents are summarized
The next question is about dynamic class and dynamic style attributes
<template> <div> <!-- grammar: :class="{Class name: Boolean value}" Usage scenario: vue Variable controls whether the tag should have a class name --> <p :class="{red_str: bool}">dynamic class</p> </div> </template> <script> export default { data(){ return { bool: true } } } </script> <style scoped> .red_str{ color: red; } </style>
<template> <div> <!-- dynamic style grammar :style="{css Attribute name: value}" --> <p :style="{backgroundColor: colorStr}">dynamic style</p> </div> </template> <script> export default { data(){ return { colorStr: 'red' } } } </script> <style> </style>
2. Vue Foundation_ filter
The filter is a conversion format, which is a function. The incoming value returns the processed value. Filters can only be used in interpolation expressions and v-bind dynamic attributes. The properties of v-bind are listed below
v-bind:title Mouse over display v-bind:src Bind picture path v-bind:html binding HTML Text and labels v-bind:text Binding text v-bind:class Binding class style v-bind:style Dynamic binding style
<template> <div> <p>The original appearance: {{ msg }}</p> <!-- 2. Filter use grammar: {{ value | Filter name }} --> <p>Use flip filter: {{ msg | reverse }}</p> <p :title="msg | toUp">Long mouse pause</p> </div> </template> <script> export default { data(){ return { msg: 'Hello, Vue' } }, // Mode 2: local filter // Can only be used within the current vue file /* Syntax: filters: { Filter name (val){ return Processed value } } */ filters: { toUp (val) { return val.toUpperCase() } } } </script> <style> </style>
The above filter scenario is used for string flipping and string capitalization.
If it is in the main app In the Vue file, the global filter needs to use Vue Filter to define and declare. In a single Vue file, you can directly use filters. When using a filter, it must be the Vue variable of the former and the filter name of the latter. Since the filter is a function, it should be able to pass parameters to the filter, and multiple filters can be used for an interpolation expression or dynamic attribute. As shown below
<template> <div> <p>The original appearance: {{ msg }}</p> <!-- 1. Pass value to filter grammar: vue variable | Filter name(value) --> <p>Use flip filter: {{ msg | reverse('|') }}</p> <!-- 2. Use of multiple filters grammar: vue variable | Filter 1 | Filter 2 --> <p :title="msg | toUp | reverse('|')">Long mouse pause</p> </div> </template> <script> export default { data(){ return { msg: 'Hello, Vue' } }, filters: { toUp (val) { return val.toUpperCase() } } } </script> <style> </style>
3. Vue Foundation_ Calculation properties
When we need to change the a and b variables, how to update the value of num synchronously? Therefore, we introduce another syntax - computational properties.
<template> <div> <p>{{ num }}</p> </div> </template> <script> export default { data(){ return { a: 10, b: 20 } }, // Calculation properties: // Scenario: the value of a variable needs to be calculated from another variable /* Syntax: computed: { Calculated attribute name (){ return value } } */ // Note: both calculation attribute and data attribute are variables - cannot have the same name // Note 2: if the variable in the function changes, the result will be automatically recalculated and returned computed: { num(){ return this.a + this.b } } } </script> <style> </style>
The calculation attribute is also a vue data variable, so don't duplicate the name in data. The usage is the same as that in data. Similarly, we can use function calls to realize this function, so what are the advantages of calculating attributes?
Calculate attributes and cache them based on the value of dependencies. When the dependent variables remain unchanged, the results are directly fetched from the cache.
<template> <div> <p>{{ reverseMessage }}</p> <p>{{ reverseMessage }}</p> <p>{{ reverseMessage }}</p> <p>{{ getMessage() }}</p> <p>{{ getMessage() }}</p> <p>{{ getMessage() }}</p> </div> </template> <script> export default { data(){ return { msg: "Hello, Vue" } }, // Computing attribute advantages: // With cache // After the function corresponding to the calculated attribute is executed, the return value will be cached // The dependency remains unchanged, and multiple calls are fetched from the cache // The dependency value - changes and the function "automatically" re executes - and caches the new value computed: { reverseMessage(){ console.log("The calculated attribute is executed"); return this.msg.split("").reverse().join("") } }, methods: { getMessage(){ console.log("Function executed"); return this.msg.split("").reverse().join("") } } } </script> <style> </style>
The advantage of computing attributes is that they are cached, the dependencies remain unchanged, they are fetched directly from the cache, the dependencies change, and the functions are automatically executed and re cached. The calculation attribute can also be used in the input box for two-way binding. The set function receives the value to be given, and the specific value to be returned to the calculated property in get
<template> <div> <div> <span>full name:</span> <input type="text" v-model="full"> </div> </div> </template> <script> // Problem: assign a value to a calculated property - setter required // solve: /* Full syntax: computed: { "Calculated property name '() {}, "Calculated attribute name:{ set(Value){ }, get(){ return value } } } */ export default { computed: { full: { // Assigning a value to full triggers the set method set(val){ console.log(val) }, // Trigger the get method with the value of full get(){ return "anonymous person" } } } } </script> <style> </style>
4. Vue Foundation_ Listener
You can listen for changes in the value of the data/computed attribute
<template> <div> <input type="text" v-model="name"> </div> </template> <script> export default { data(){ return { name: "" } }, // Target: listen for change of name value /* Syntax: watch: { Variable name (newVal, oldVal){ // The change of the corresponding value of the variable name is automatically triggered here } } */ watch: { // newVal: current latest value // oldVal: last moment value name(newVal, oldVal){ console.log(newVal, oldVal); } } } </script> <style> </style>
Using the watch configuration item, key is the data to listen to and the object to listen to. If deep monitoring is required, it needs to be set
The above is part of the basic knowledge of the whole vue. In the next chapter, I will use these grammars in a small project.