Vue compute properties, listeners, and filters

1. Calculation attribute

1.1 use method

summary:

Putting too much logic into the template will make the template too heavy and difficult to maintain. Using calculation properties can make the template simple and easy to maintain. Calculation attributes are cached based on their responsive dependencies. Calculation attributes are more suitable for returning a result value after processing multiple variables or objects, that is, if a value of several variables changes, the value we monitor will also change.

The calculation attribute is defined in Vue object, and functions are defined in the calculated attribute object through the keyword, and a value is returned. The calculation attribute is used in the same way as the data in data.

use:

When we do not use calculation attributes, we can write the results in the template in the following ways:

<div id="app">
    <!-- Method 1: vue When using, it is not recommended to write too much logic in the template -->
    <h3>{{ n1+n2 }}</h3>
    <!-- Method 2: for a calculation result, multiple results may be displayed on the current page, and the function will be called several times after several times of display, which will degrade the performance -->
    <h3>{{ sum() }}</h3>
    <h3>{{ sum() }}</h3>
    <h3>{{ sum() }}</h3>
</div>

<script>
    const vm = new Vue({
        el: '#app',
        data: {
            n1: 1,
            n2: 2
        },
        methods: {
            sum() {
                console.log('sum --- methods');
                return this.n1 + this.n2
            }
        }
    })
</script>

If you calculate a result, you can use the calculation properties provided by vue, and the calculation properties also have a caching function. If your dependency has not changed, it will read the data in the cache when it is called again.

<div id="app">
    <div>{{total}}</div>
    <div>{{total}}</div>
    <div>{{total}}</div>
</div>

<script>
    const vm = new Vue({
        el: '#app',
        data: {
            n1: 1,
            n2: 2
        },
        // Calculation [attribute]
        computed: {
            // When calling, you can write the name directly without writing parentheses
            // There can be one or N dependencies in the calculated property, depending on how many you call in the calculated property
            // Note: asynchronous cannot be written in this method
            // Abbreviation: the most commonly used way of writing
            total() {
                console.log('computed -- total')
                // In the calculation attribute, if n1 and n2 are called, n1 and n2 are its dependencies. If one of the two dependencies changes, it will be recalculated. If neither changes, it will be called after the second time to read the data in the cache
                return this.n1 + this.n2
            }
        },
        methods: {
            // Methods in calculation properties can also be called in methods
            sum() {
                console.log('sum --- methods', this.total);
                return this.n1 + this.n2
            }
        }
    })
</script>

be careful:

  1. When calculating attributes, you can write the name directly in the template without writing parentheses.
  2. In the calculation attribute, if n1 and n2 are called, n1 and n2 are its dependencies. If one of the two dependencies changes, it will be recalculated. If neither changes, it will be called after the second time to read the data in the cache. This is why the above calculation is performed three times, but the calculation method is called only once, because the dependencies in the calculation properties have not changed.
  3. There can be one or N dependencies in the calculated property, depending on how many you call in the calculated property.
  4. Asynchrony cannot be written in a method in a calculated property.
  5. The above calculation attribute is abbreviated. Abbreviation is the most used method.
  6. Calculation properties can be called not only in templates but also in method s.

If the defined calculation attribute is abbreviated, an error will be reported when assigning a value to the calculation attribute. It can assign values to calculated attributes only when it is written in a standard way. Let's take a look at the standard writing.

<div id="app">
    <h3>{{ sum() }}</h3>
    <h3>{{msg}}</h3>
</div>

<script>
    const vm = new Vue({
        el: '#app',
        data: {
            n1: 1,
            n2: 2,
            msg: ''
        },
        // Calculation [attribute]
        computed: {
            // standard notation 
            total: {
                // Abbreviation: it only implements the get method in the standard writing method
                get() {
                    return this.n1 + this.n2
                },
                set(newVal) {
                    if (newVal > 10) {
                        this.msg = 'The value is a little big'
                    }
                }
            }
        },
        methods: {
            sum() {
                // Assignment will only trigger the set method in the standard mode, and then you can get it and complete some other work
                if (this.total > 6) {
                    this.total = 101
                }
                return this.n1 + this.n2
            }
        }
    })
</script>

be careful:

  1. The shorthand method only implements the get method in the standard writing method.
  2. Assignment will only trigger the set method in the standard way, and then you can get a new value and complete some other work.

1.2 case: shopping cart total usage calculation attribute

<!DOCTYPE html>
<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>vue Learn to use</title>
        <!-- Step 1: Import vue Library file -->
        <script src="./js/vue.js"></script>
    </head>

    <body>
        <!-- Step 2: mount point -->
        <div id="app">
            <table border="1" width="600">
                <tr>
                    <th>Serial number</th>
                    <th>name</th>
                    <th>Unit Price</th>
                    <th>quantity</th>
                    <th>operation</th>
                </tr>
                <tr v-for="item,index in carts">
                    <td>{{index+1}}</td>
                    <td>{{item.name}}</td>
                    <td>{{item.price}}</td>
                    <td>
                        <button @click="setNum(1,index)">+++</button>
                        <input type="number" v-model="item.num">
                        <button @click="setNum(-1,index)">---</button>
                    </td>
                    <td>
                        <button @click="del(index)">delete</button>
                    </td>
                </tr>
            </table>
            <hr>
            <h3>
                total:
                {{totalPrice}}
            </h3>

        </div>

        <!-- Step 3: instantiate vue -->
        <script>
            const vm = new Vue({
                el: '#app',
                data: {
                    carts: [
                        { id: 1, name: 'Xiaomi 12 pro', price: 1, num: 1 },
                        { id: 2, name: 'Huawei mobile phone', price: 2, num: 1 },
                        { id: 3, name: 'Fruit mobile phone', price: 3, num: 1 },
                    ]
                },
                methods: {
                    setNum(n, index) {
                        this.carts[index].num += n
                        this.carts[index].num = Math.min(3, Math.max(1, this.carts[index].num))
                    },
                    del(index) {
                        confirm('Are you sure to delete') && this.carts.splice(index, 1)
                    }
                },
                // Calculation properties
                computed: {
                    totalPrice() {
                        return this.carts.reduce((prev, { price, num }) => {
                            // Dependencies
                            prev += price * num
                            return prev
                        }, 0)
                    }
                }
            })
        </script>

    </body>

</html>

2. Listener

summary:

Use the watch to listen for the changes of data in the data. The content in the watch must be the data that already exists in the data.

When it is necessary to monitor the change of an object, the ordinary watch method cannot monitor the change of the internal attribute of the object. Only the data in the data can monitor the change. At this time, the deep attribute is required to monitor the object in depth.

use:

Standard writing:

<div id="app">
    <div>
        <input type="text" v-model="username">
        <span>{{errorUsername}}</span>
    </div>
</div>

<script>
    const vm = new Vue({
        el: '#app',
        data: {
            username: '',
            errorUsername: ''
        },
        // Listener, which is used to monitor the data change in the data configuration. Once there is a change, it will be triggered automatically. By default, initialization does not trigger
        // You can get this object in the listener
        // The listener has only one dependency, one-to-one
        // Asynchronous can be written in the listener
        watch: {
            // The method name or attribute name is the attribute name in the data you want to observe
            // standard notation 
            username: {
                // newValue: the changed value; oldValue: value before change
                handler(newValue, oldValue) {
                    if (newValue.length >= 3) this.errorUsername = 'Account number is too long'
                    else this.errorUsername = ''
                }
            }
        })
</script>

be careful:

  1. The listener is used to monitor the data change in the data configuration. Once there is a change, it will be triggered automatically. By default, initialization does not trigger.
  2. You can get this object in the listener.
  3. There is only one dependency of the listener, one-to-one.
  4. Asynchronous (Ajax or setTimeout) can be written in the listener.

Abbreviation:

<div id="app">
    <div>
        <input type="text" v-model="username">
        <span>{{errorUsername}}</span>
    </div>
</div>

<script>
    const vm = new Vue({
        el: '#app',
        data: {
            username: '',
            errorUsername: ''
        },
        watch: {
            username(newValue, oldValue) {
                if (newValue.length >= 3) this.errorUsername = 'Account number is too long'
                else this.errorUsername = ''
            }
        }
    })
</script>

During initialization, enable listener writing:

<div id="app">
    <div>
        <input type="text" v-model="username">
        <span>{{errorUsername}}</span>
    </div>
</div>

<script>
    const vm = new Vue({
        el: '#app',
        data: {
            username: 'aaa',
            errorUsername: ''
        },
        watch: {
            // The method name or attribute name is the attribute name in the data you want to observe
            // standard notation 
            username: {
                handler(newValue, oldValue) {
                    if (newValue.length >= 3) this.errorUsername = 'Account number is too long'
                    else this.errorUsername = ''
                },
                // Initially, it is executed once --- generally, it is not enabled. This configuration is only available under the standard writing method
                immediate: true
            }
        })
</script>

Note: this configuration is only available in standard writing.

Listen for attribute changes in the object:

<div id="app">
    <div>
        <input type="number" v-model.number="user.id"> 
    </div>
</div>

<script>
    const vm = new Vue({
        el: '#app',
        data: {
            user: { id: 100, name: 'aaa' }
        },
        // It is recommended to monitor the change of the specified attribute data in the object. If you are monitoring the data change in an object, it is recommended to do so
        watch: {
            'user.id'(newValue, oldValue){
                console.log(newValue, oldValue);
            }
        }
    })
</script>

Monitoring object change:

<div id="app">
    <div>
        <input type="number" v-model.number="user.id"> 
    </div>
</div>

<script>
    const vm = new Vue({
        el: '#app',
        data: {
            user: { id: 100, name: 'aaa' }
        },
        watch: {
            // The listening object can only be written in the standard way
            // When the listening object changes, its front and rear values are the same, which cannot be distinguished
            user: {
                // Deep monitoring
                deep: true,
                handler(newValue, oldValue) {
                    console.log(newValue, oldValue);
                },
            }
        }
    })
</script>

be careful:

  1. The listening object can only be written in the standard way
  2. When the listening object changes, its front and rear values are the same, which cannot be distinguished

3. Filter

summary:

Before the data is rendered, it can be further processed, such as intercepting characters or converting lower case to upper case. The filter itself is a method.

The function of the filter is to process the data displayed in the interface.

Filters can define global or local.

To define a global filter:

<div id="app">
    <h3>{{ phone | phoneCrypt }}</h3>
</div>

<script>
    // Parameter 1: name of filter, which can be named at will
    // Parameter 2: callback function. There must be at least one parameter in the callback function. The first parameter always points to the data to be filtered
    Vue.filter('phoneCrypt', value => {
        return value.slice(0, 3) + '~~~~' + value.slice(7)
    })

    const vm = new Vue({
        el: '#app',
        data: {
            phone: '13523235235'
        }
    })
</script>

There is only one parameter in the callback function of the global filter above. We can also define multiple parameters:

<div id="app">
    <!-- The first parameter passed here,The second parameter defined in the callback function corresponding to the global filter -->
    <h3>{{ phone | phoneCrypt('!!!!') }}</h3>
</div>

<script>
    Vue.filter('phoneCrypt', (value, salt = '****') => {
        return value.slice(0, 3) + salt + value.slice(7)
    })

    const vm = new Vue({
        el: '#app',
        data: {
            phone: '13523235235'
        }
    })
</script>

Define local filters:

<div id="app">
    <h3>{{ phone | phoneCrypt('!!!!') }}</h3>
</div>

<script>
    const vm = new Vue({
        el: '#app',
        data: {
            phone: '13523235235'
        },
        // Local filter
        filters:{
            phoneCrypt(value, salt = '****'){
                return value.slice(0, 3) + salt + value.slice(7)
            }
        }
    })
</script>

Tags: Javascript Vue.js Vue Front-end

Posted by Sander on Sun, 04 Sep 2022 21:55:01 +0530