Vue filters, calculation properties, listener graphical version at a glance

Learning objectives of this article

  1. Be able to understand the role of key, virtual Dom and diff algorithm
  2. Be able to master setting dynamic styles
  3. Be able to master filters, calculation properties and listeners
  4. Able to complete brand management cases

1. vue Foundation

1.0_vue basic v-for update monitoring

Target: when the target structure of v-for traversal changes, Vue triggers the update of v-for

Case 1: array flip

Case 2: array interception

Case 3: update value

Pithy formula:

Changing the array method will lead to v-for update and page update

If the array is not changed, returning a new array will not cause v-for update. You can overwrite the array or this$ set()

<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 three</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>

These methods trigger array changes, and v-for will monitor and update the page

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

These methods do not trigger v-for updates

  • slice()
  • filter()
  • concat()

Note: vue cannot be updated by monitoring the assignment action in the array. If necessary, please use vue Set () or this$ Set (), or overwrite the entire array

Summary: only by changing the method of the original array can v-for be updated

1.1_vue Foundation_ v-for in place update

Instead of trying to move in place, the default behavior of the for-v elements is modified.

Explain the v-for local update process in detail (you can watch ppt animation)

This virtual DOM comparison can improve performance - but it's not high enough

1.2_vue Foundation_ Virtual dom

Objective: to understand the concept of virtual DOM

The labels written in the template in the. vue file are all templates, which must be processed into virtual DOM objects by vue before they can be rendered and displayed on the real DOM page

  1. Generate the same virtual DOM structure in memory (essentially a JS object)

    Because there are hundreds of real DOM attributes, there is no way to quickly know which attribute has changed

    For example, label structure in template

    <template>
        <div id="box">
            <p class="my_p">123</p>
        </div>
    </template>
    

    Corresponding virtual DOM structure

    const dom = {
        type: 'div',
        attributes: [{id: 'box'}],
        children: {
            type: 'p',
            attributes: [{class: 'my_p'}],
            text: '123'
        }
    }
    
  2. Later vue data update

    • Generate a new virtual DOM structure
    • Compared with the old virtual DOM structure
    • Using diff algorithm, we can't find the difference. We only update the changed part (redraw / reflow) to the page - also known as patching

Benefit 1: it improves the performance of updating DOM (there is no need to delete and re render all pages)

Benefit 2: the virtual DOM contains only the necessary attributes (there are not hundreds of attributes in the real DOM)

Summary: the virtual DOM is stored in memory, only the key information of DOM is recorded, and the performance of DOM update is improved with diff algorithm

Compare the differences in memory, and then patch and update the real DOM

1.3_vue Foundation_ diff algorithm

vue uses diff algorithm to compare the new virtual DOM with the old virtual dom

Case 1: the root element has changed, delete and rebuild

Old virtual DOM

<div id="box">
    <p class="my_p">123</p>
</div>

New virtual DOM

<ul id="box">
    <li class="my_p">123</li>
</ul>

Case 2: the root element remains unchanged, the attribute changes, the element is reused, and the attribute is updated

Old virtual DOM

<div id="box">
    <p class="my_p">123</p>
</div>

New virtual DOM

<div id="myBox" title="title">
    <p class="my_p">123</p>
</div>

1.4_vue Foundation_ diff algorithm key

Case 3: the root element has not changed, the child element has not changed, and the element content has changed

No key - update in place

Instead of moving the DOM, v-for tries to reuse and update in place. If you need to move the DOM, you need to use a special attribute key to provide a sorting prompt

<ul id="myUL">
    <li v-for="str in arr">
        {{ str }} 
        <input type="text">
    </li>
</ul>
<button @click="addFn">Add a new one where the subscript is 1</button>
export default {
    data(){
        return {
            arr: ["boss", "incoming", "penis", "Old three"]
        }
    },
    methods: {
        addFn(){
            this.arr.splice(1, 0, 'incoming')
        }
    }
};

Comparison process between old virtual DOM structure and new virtual DOM structure

The performance is not high. It has been updated since the second li

There is a key value as the index
  • Or update in place

Because of the comparison between the old and new virtual DOM S, if the key exists, it will reuse this tag to update the content. If it does not exist, it will directly create a new one

<ul id="myUL">
    <li v-for="(str, index) in arr" :key="index">
        {{ str }} 
        <input type="text">
    </li>
</ul>
<button @click="addFn">Add a new one where the subscript is 1</button>
export default {
    data(){
        return {
            arr: ["boss", "incoming", "penis", "Old three"]
        }
    },
    methods: {
        addFn(){
            this.arr.splice(1, 0, 'incoming')
        }
    }
};

key is the index diagram process (updated locally)

  1. The v-for loop generates a new DOM structure first. The key is continuous and corresponds to the data

  2. Then compare the old and new DOM structures, find the differences, and patch them on the page

    Finally, add a li, and then update the content from the second one

Pithy formula: the value of key has id, but index is used for no id

There is a key - the value is id

The value of key can only be a unique string or numeric value without repetition

Instead of moving the DOM, v-for tries to reuse and update in place. If you need to move the DOM, you need to use a special attribute key to provide a sorting prompt

The key of the data in the new DOM exists. Go to the old virtual DOM structure to find the tag of the key tag and reuse the tag

The key of the data in the new DOM exists. If the key tag is not found in the old virtual DOM structure, create it

If the key of the old DOM structure is lost in the new DOM structure, the tag of the key will be removed

<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>

Graphic effect:

Summary: no key is needed and the function is not affected (local update). Adding a key can improve the update performance

1.5_ Stage summary

When will v-for update the page?

  • The array adopts the update method, which causes v-for to update the page

How does vue improve update performance?

  • Using virtual DOM+diff algorithm to improve update performance

What is virtual DOM?

  • The essence is a JS object that holds the key information of dom

How does diff algorithm compare old and new virtual DOM?

  • Root element change – delete the current DOM tree and create a new one
  • Root element unchanged, attribute changed – update attribute
  • The root element remains unchanged and the child element / content changes
  • No key – update in place / with key – compare by key

1.6_vue basic dynamic class

Objective: use v-bind to set the dynamic value of label class

  • Syntax:
    • : class = "{class name: Boolean}"
<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>

Summary: save the class name in vue variable and assign it to tag

1.7_vue foundation - dynamic style

Objective: to dynamically set the value of style for the label

  • grammar
    • : style="{css attribute: value}"
<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>

Summary: all key s of dynamic style are css attribute names

2. vue filter

2.0_vue filter - define usage

Purpose: to convert the format, the filter is a function, and the incoming value returns the processed value

Filters can only be used in interpolation expressions and v-bind expressions

Filter scenarios in Vue

  • Convert letters to uppercase, enter "HELLO" and output "HELLO"
  • String flip, "input hello, world", output "dlrow, olleh"

Syntax:

  • Vue.filter("filter name", (value) = > {return "return processed value"})

  • filters: {filter name: (value) = > {return "return processed value"}

example:

  • Globally defines a filter for all uppercase letters
  • Filters that locally define string flipping
<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>

Summary: convert the value to another form and use the filter. Vue3 replaces the filter with a function

Global registration is best in main JS, a registration is used everywhere

2.1_vue filter - transfer parameter and multi filter

Objective: multiple filters can be used at the same time, or parameters can be passed to the filter

  • Syntax:
    • Filter parameters: vue variable | filter (argument)
    • Multiple filters: vue variable | filter 1 | filter 2
<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>

Summary: the filter can pass parameters, and it can also be used for a filter result. Later, a filter will be used

2.2_ Case - Brand Management (time format)

Objective: copy the previous case, and on this basis, format the time in the table into YYYY-MM-DD format with filter + moment module

Illustration:

  1. Download the third-party tool module of moment processing date

    Document on the official website of moment: http://momentjs.cn/docs/#/displaying/

    yarn add moment
    
  2. Define the filter, format the time with the moment module, and return the format we want

    // Target: processing time
    // 1. Download the moment module
    import moment from 'moment'
    
    
    // 2. Define filter and write internal code
    filters: { 
        formatDate (val){
            return moment(val).format('YYYY-MM-DD')
        }
    }
    
    <!-- 3. Use filter -->
    <td>{{ obj.time | formatDate }}</td>
    

3. vue calculation attribute

3.0_vue calculated attribute - computed

Goal: one data, the result calculated by relying on other data

Syntax:

  • computed: {
        "Calculated attribute name" () {
            return "value"
        }
    }
    

Requirements:

  • Demand: find the sum of 2 numbers and display them on the page
<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>

Note: 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

Summary: one data depends on the results calculated from other data

3.1_vue calculation properties - cache

Objective: the calculated attributes are cached based on the value results of their dependencies. As long as 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"
    }
  },
  // Advantages of computing attributes:
  // 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 taken from the cache
  // The dependency value - changes and the function "automatically" re executes - and caches the new value
  computed: {
    reverseMessage(){
      console.log("The calculation property is executed");
      return this.msg.split("").reverse().join("")
    }
  },
  methods: {
    getMessage(){
      console.log("Function executed");
      return this.msg.split("").reverse().join("")
    }
  }
}
</script>

<style>

</style>

Summary: the calculation attribute is cached according to the result of dependent variable, and the recalculation result of dependent change is stored in the cache, which has higher performance than ordinary methods

3.2_ Case - Brand Management (total price and average price)

Objective: Based on the previous cases, complete the calculation effect of total price and average price

Only the changed code has been modified here

<tr style="background-color: #EEE">
     <td>Statistics:</td>
     <td colspan="2">The total price is: {{ allPrice }}</td>
     <td colspan="2">Average price: {{ svgPrice }}</td>
</tr>

<script>
// Target: total price and average price display
// 1. Add tr at the end - display total price and average price
export default {
  // ... Source code omission
  // 2. Calculation attribute
  computed: {
      allPrice(){
          // 3. Total price
          return this.list.reduce((sum, obj) => sum += obj.price, 0)
      },
      avgPrice(){
          // 4. Average price - keep 2 decimal places
          return (this.allPrice / this.list.length).toFixed(2)
      }
  }
}
</script>

Summary: the total price comes from the calculation results of all data, so the calculation attribute is adopted

3.3_vue complete attribute calculation

Objective: the calculation attribute is also a variable. If you want to assign a value directly, you need to use the complete writing method

Syntax:

computed: {
    "Attribute name": {
        set(value){
            
        },
        get() {
            return "value"
        }
    }
}

Requirements:

  • Calculate properties for v-model

Page preparation input box

<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>

Summary: to assign a value to a calculated attribute, you need to use the set method

3.4_ Case - small selection affects all selection

Objective: select all the small boxes (manually), and select all automatically

  • Requirement: select all the small boxes (manually), and select all automatically

analysis:

① First static, then dynamic, from md gets static tags and data

② Generate check boxes and text circularly, the c attribute of the object and the selected state of the small selection box, and bind them in both directions with v-model

③ Define the isAll calculation attribute. The value is obtained by counting the c attribute status through the small selection boxes

Illustration:

Template labels and data (copy directly and write vue code on this basis)

<template>
  <div>
    <span>Select all:</span>
    <input type="checkbox"/>
    <button>Reverse selection</button>
    <ul>
      <li>
        <input type="checkbox"/>
        <span>Task name</span>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      arr: [
        {
          name: "Zhu Bajie",
          c: false,
        },
        {
          name: "Sun WuKong",
          c: false,
        },
        {
          name: "Tang Monk",
          c: false,
        },
        {
          name: "White dragon horse",
          c: false,
        },
      ],
    };
  }
};
</script>

Correct code, cannot be copied

<template>
  <div>
    <span>Select all:</span>
    <!-- 4. v-model Associate select all - Selected status -->
    <input type="checkbox" v-model="isAll"/>
    <button>Reverse selection</button>
    <ul>
      <li v-for="(obj, index) in arr" :key="index">
        <!-- 3. object.c - Association selected status -->
        <input type="checkbox" v-model="obj.c"/>
        <span>{{ obj.name }}</span>
      </li>
    </ul>
  </div>
</template>

<script>
// Target: small selection box - > select all
// 1. Label + style + js ready
// 2. Display the data cycle on the page
export default {
  data() {
    return {
      arr: [
        {
          name: "Zhu Bajie",
          c: false,
        },
        {
          name: "Sun WuKong",
          c: false,
        },
        {
          name: "Tang Monk",
          c: false,
        },
        {
          name: "White dragon horse",
          c: false,
        },
      ],
    };
  },
  // 5. Calculation attribute - isAll
  computed: {
    isAll () {
         // 6. Statistics of small selection box status - > select all status
        // every formula: find the "unqualified" condition in the array and return false directly in place
        return this.arr.every(obj => obj.c === true)
    }
  }
};
</script>

3.5_ Case - select all

Objective: select all, affect small selection

  • Requirement 1: get all selected status - modify isAll calculation attribute
  • Requirement 2: select all status is synchronized to all small boxes

analysis:

① : isAll is changed to the full writing method, and the status value of all check boxes and checked boxes is obtained in set

② : traverse the data array and assign the attributes associated with all small boxes v-model

Illustration:

The correct code cannot be copied

<script>
export default {
  // ... Other codes
  // 5. Calculation attribute - isAll
  computed: {
    isAll: {
      set(val){
        // 7. Select all box - selected status (true/false)
        this.arr.forEach(obj => obj.c = val)
      },
      get(){
        // 6. Statistics of small selection box status - > select all status
        // every formula: find the "unqualified" condition in the array and return false directly in place
        return this.arr.every(obj => obj.c === true)
      }
    }
  }
};
</script>

3.6_ Case - reverse selection

Target: reverse selection function

  • Demand: click the inverse check to make all small check boxes take the opposite check status

analysis:

① : the check status of the small check box in the c attribute of the object

② : traverse all objects and give the c attribute of the object the opposite value

Illustration:

The correct code cannot be copied

<button @click="btn">Reverse selection</button>

<script>
export default {
  // ... Other codes are omitted
  methods: {
    btn(){
      // 8. Reverse the c attribute of the object in the array and give it back
      this.arr.forEach(obj => obj.c = !obj.c)
    }
  }
};
</script>

4. vue listener

4.0_vue listener watch

Target: you can listen for data/computed attribute value changes

Syntax:

  • watch: {
        "The name of the property being listened on" (newVal, oldVal){
            
        }
    }
    

Complete example code:

<template>
  <div>
    <input type="text" v-model="name">
  </div>
</template>

<script>
export default {
  data(){
    return {
      name: ""
    }
  },
  // Target: listen for the 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>

Summary: if you want to listen for a property change, you can use the listening property watch

4.1_vue listener - deep listening and immediate execution

Target: listen for complex types, or execute the listening function immediately

  • Syntax:

    watch: {
        "Property name to listen on": {
            immediate: true, // Execute immediately
            deep: true, // Deep listening changes within complex types
            handler (newVal, oldVal) {
                
            }
        }
    }
    

Complete example code:

<template>
  <div>
    <input type="text" v-model="user.name">
    <input type="text" v-model="user.age">
  </div>
</template>

<script>
export default {
  data(){
    return {
      user: {
        name: "",
        age: 0
      }
    }
  },
  // Target: listening object
  /*
  Syntax:
    watch: {
      Variable name (newVal, oldVal){
        // The change of the corresponding value of the variable name is automatically triggered here
      },
      Variable name:{
        handler(newVal, oldVal){

        },
        deep: true, // Deep listening (the value of the layer inside the object changes)
        immediate: true // Listen now (the web page opens and the handler executes once)
      }
    }
  */
  watch: {
    user: {
      handler(newVal, oldVal){
        // Objects in user
        console.log(newVal, oldVal);
      },
      deep: true,
      immediate: true
    }
  }
}
</script>

<style>

</style>

Summary: immediate listen, deep listen, handler fixed method trigger

4.2_ Case - Brand Management (data cache)

Target: listen for list changes and synchronize to the local browser

  • Requirement: synchronize the data of brand management to the local cache in real time

analysis:

① when the watch listens for changes in the list, convert the latest array list into a JSON string and store it in the local storage

② in data, the list variable is taken locally by default. If it cannot be obtained, a default empty array is given

effect:

Add / delete – refresh page – data still exists

Write on the basis of the previous case code

Correct code, cannot be copied

<script>
import moment from "moment";
export default {
  data() {
    return {
      name: "", // name
      price: 0, // Price
      // 3. Fetch cache list locally
      list: JSON.parse(localStorage.getItem('pList')) || [],
    };
  },
  // ... Other codes are omitted
  watch: {
    list: {
      handler(){
        // 2. Deposit locally
        localStorage.setItem('pList', JSON.stringify(this.list))
      },
      deep: true
    }
  }
};
</script>

Today's summary

  • What array method changes can v-for monitor and update the page
  • What is the function of key
  • Virtual dom benefits, diff algorithm effect
  • Dynamically set class or style
  • Function and classification of vue filter
  • vue calculation attribute function
  • Role of vue listener

Interview questions

1. How to customize filters in Vue

​ Vue.js allows custom filters that can be used for some common text formatting. Filters can be used in two places: Double curly bracket interpolation and v-bind expressions

Global Vue filter()

Local filters attribute

2. Vue: key function, why can't index be used

: key is a unique identifier issued to the v-for loop generation tag for performance optimization

Because the order of v-for data items changes, Vue will not move DOM elements to match the order of data items, but update each element in place

: key if the index is continuous, deleting one of them will cause the last one to be deleted

When we delete again, when: key compares the old and new DOMS according to the data, delete the corresponding tag that: key does not exist (it is the same to add, insert it into the specified position, and nothing else will move)

3. When updating arrays, v-for does not render sometimes

Because vue can only monitor the change of array order / position / quantity, but the value is re assigned, and the change cannot be monitored, vue can be used set() / vm.$ set()

Write at the end

✨ primary create no easy , still Hope at various position large Guy branch hold one lower \textcolor{blue} {original is not easy. I hope you guys can support it} It's not easy to be original. I hope you guys can support it

👍 spot fabulous , you of recognize can yes I create do of move power ! \textcolor{green} {praise, your recognition is the driving force of my creation!} Your creativity is my motivation!

⭐️ collect hide , you of young look at yes I Try power of square towards ! \textcolor{green} {collection, your favor is the direction of my efforts!} Collection, your favor is the direction of my efforts!

✏️ review theory , you of meaning see yes I enter step of wealth rich ! \textcolor{green} {comment, your opinion is the wealth of my progress!} Comment, your opinion is the wealth of my progress!

Keywords: Javascript Front-end Vue Vue.js

Added by alex_funky_dj on Mon, 14 Feb 2022 03:13:53 +0200