Vue 快速入门(四)

我心飞翔 分类:vue

前面已经介绍Vue常用指令的基本应用,这篇介绍Vue的一些特殊属性的使用。

01 - 计算属性Computed

计算属性关键词:Computed。
计算属性在处理一些复杂逻辑时是很有用的。

  • 普通的写法

比如字符串反转普通写法,如下:

<!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>Document</title>
</head>
<body>

    <div id="app">
            {{ message.split('').reverse().join('')}}
    </div>

</body>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            message: 'Python!'
        }
    })
</script>
</html>
  • 计算属性的写法

接下来我们看看使用了计算属性的实例:

<!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>Document</title>
</head>
<body>

    <div id="app">
            {{ message.split('').reverse().join('')}}
            <p>计算后反转字符串: {{ reserseMsg }}</p>
    </div>

</body>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
    var msg = new Vue({
        el: '#app',
        data: {
            message: 'Python!'
        },
        computed: {
             // 计算属性的 getter
            reserseMsg: function(){
                // `this` 指向 msg 实例
                return this.message.split('').reverse().join('')
            }
        }
    })
</script>
</html>

上图中声明了一个计算属性 reserseMsg。

提供的函数将用作属性 msg.reserseMsg 的 getter 。

msg.reserseMsg依赖于 msg.message,在 msg.message 发生改变时,msg.reserseMsg也会更新。

  • 计算属性与方法

上面示例如果不用计算属性,也可以用函数。我们可以使用 methods 来替代 computed,效果上两个都是一样的,但是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。而使用 methods ,在重新渲染的时候,函数总会重新调用执行。

<!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>Document</title>
</head>
<body>

    <div id="app">
            {{ message.split('').reverse().join('')}}
            <p>计算后反转字符串: {{ reserseMsg }}</p>
            <p>计算后反转字符串: {{ reserseMsg2() }}</p>
    </div>

</body>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
    var msg = new Vue({
        el: '#app',
        data: {
            message: 'Python!'
        },
        computed: {
             // 计算属性的 getter
            reserseMsg: function(){
                // `this` 指向 msg 实例
                return this.message.split('').reverse().join('')
            }
        },
        methods: {
            reserseMsg2: function(){
                // `this` 指向 msg 实例
                return this.message.split('').reverse().join('')
            }
        },
    })
</script>
</html>

可以看出,方法和计算属性的区别:

  • 声明发生不一样,调用不一样方法要用(), 计算属性调用不要加()

第二个区别:

  • 计算属性: 当方法中使用的数据发生改变,方法会自动调用。 
  • methods : 当方法中使用的数据发生改变,方法会自动调用。

如下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>计算属性和侦听器</title>
</head>

<body>
    <div id="app">
        <!-- 实现一个购物车功能
        1. 数据初始化处理
        2.计算商品总价
        3.选择商品数量:当商品数量超过库存做提示
        -->
        <ul>
            <li v-for="(item, index) in car" >
            {{item.pname}} --- 商品价格:{{item.price}} --- 库存:{{item.stock}}
            数量:<input type="number" v-model="item.num" style="width: 30px;" />
            </li>
            <li><strong>总价:</strong>{{calcSum}}</li>
            <li v-html="message"></li>
            <li v-html="warn()"></li>
        </ul>

    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>

    <script>
        new Vue({
            el:"#app",
            data:{
                car:[
                    {pname:'Iphone 12',price:7999,stock:10,num:1},
                    {pname:'小米11',price:3599,stock:3,num:4},
                ],
                message:"",
            },
            // methods : 当方法中使用的数据发生改变,方法会自动调用
            methods: {
                // calcSum(){
                //     let sum=0;
                //     this.car.forEach(item => {
                //         sum+=item.price*item.num;
                //     });
                //     return sum;
                // }
                warn(){
                    let message="";
                    this.car.forEach(item => {
                        if(item.num>item.stock){
                            message+=`${item.pname}的库存超出限制<br/>`
                        }
                    });
                    return message;
                }
            },
            // 计算属性: 当方法中使用的数据发生改变,方法会自动调用
            computed:{
                 calcSum(){
                    let sum=0;
                    this.car.forEach(item => {
                        sum+=item.price*item.num;
                    });
                    return sum;
                }
            }
        });


        /*
        方法和计算属性的区别:
            声明发生不一样,调用不一样方法要用(), 计算属性调用不要加()
        */


    </script>

</body>

</html>

可以拷贝代码自己动手试试,就明白了。

总结一下:

计算属性 VS 方法

  • 如果不使用计算属性,在 methods 里定义了一个方法,也可以实现相同的效果,甚至该方法还可以接受参数,使用起来更灵活。
  • 既然 methods 同样可以解决模板中复杂逻辑计算的问题,那么为什么还需要使用计算属性呢?
    原因就是:计算属性是基于它的依赖缓存的。前面我们介绍过,计算属性的改变取决于其所依赖数据的变化;
  • 所以只要依赖数据不发生改变,计算属性就不会更新。当我们重复获取计算属性时它也不会重复计算,只会获取缓存的值。
    而我们每次调用 methods 都会重新计算一遍,这样将会消耗一部分性能。当然,如何你不希望对数据进行缓存,那么可以用方法来代替。

02 - 监听器Watch

侦听器

通过侦听器来监听数据的变化,进行相应的逻辑处理。

如何监听对象类型数据的某个属性进行侦听。

先看一下基础用法,如下:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Vue </title>
    <script src="./node_modules/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <p style="font-size:25px;">计数器: {{ counter }}</p>
        <button @click="counter++" style="font-size:25px;">点我</button>
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el: '#app',
            data: {
                counter: 1
            },
            watch: {
                // 写法1: 基础类型的侦听, 将侦听数据作为函数就可以了  
                counter(newvalue, oldvalue) {
                    console.info('计数器值的变化 :' + oldvalue + ' 变为 ' + newvalue + '!')
                }
            }
        })
 // 写法2:       
// 外面调用  $watch 是一个实例方法
 vm.$watch('counter', function(nval, oval) {
    alert('计数器值的变化 :' + oval + ' 变为 ' + nval + '!');
 });

    </script>
</body>

</html>

常规用法:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>计算属性和侦听器</title>
</head>

<body>
    <div id="app">
        <!-- 实现一个购物车功能
        1. 数据初始化处理
        2.计算商品总价
        3.选择商品数量:当商品数量超过库存做提示
        -->
        <ul>
            <li v-for="(item, index) in car" >
            {{item.pname}} --- 商品价格:{{item.price}} --- 库存:{{item.stock}}
            数量:<input type="number" v-model="item.num" style="width: 30px;" />
            </li>
            <!-- <li><strong>总价:</strong>{{calcSum}}</li> -->
            <li v-html="message"></li>
            <li v-html="warn()"></li>
        </ul>

    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>

    <script>
        new Vue({
            el:"#app",
            data:{
                car:[
                    {pname:'Iphone 12',price:7999,stock:10,num:1},
                    {pname:'小米11',price:3599,stock:3,num:4},
                ],
                message:"",
            },
            // methods : 当方法中使用的数据发生改变,方法会自动调用
            // methods : 页面初始化时,会调用warn()方法。
            methods: {
                warn(){
                    let message="";
                    this.car.forEach(item => {
                        if(item.num>item.stock){
                            message+=`${item.pname}的库存超出限制<br/>`
                        }
                    });
                    return message;
                }
            },

            // 侦听器 专门用于侦听数据的变化,当数据发生变化会自动调用方法
            watch:{
                // 要侦听的数据: 数组
                car:{
                    handler(newvalue,oldvalue){ 
                        this.message="";
                        this.car.forEach(item => {
                            if(item.num>item.stock){
                                this.message+=`${item.pname}的库存超出限制<br/>`
                            }
                        });
                    },
                    deep:true   //深度侦听器
                },
                // 基础类型的侦听, 将侦听数据作为函数就可以了  
                // message(newvalue,oldvalue){
                //     console.info(newvalue,oldvalue)
                // }
            }
        });

    </script>

</body>

</html>

这里需要注意,方法和侦听器的区别:

方法: 

  • 方法中任意数据发生了改变就会自动调用方法
  • 可以调用,进行返回值
  • 页面初始化的时候就调用一次了

侦听器:

  • 需要指定具体的侦听数据,只有被具体指定的侦听数据发生了改变才会触发
  • 不能像方法那样去调用, 而是靠vue自动触发

03 - 过滤器Watch

最后一个常用的器:过滤器,这个在第三章模板语言里已经讲过了,这里就过一下。

Vue.js 允许你自定义过滤器,被用作一些常见的文本格式化。由"管道符"指示, 格式如下:

<!-- 在两个大括号中 -->
{{ message | capitalize }}

<!-- 在 v-bind 指令中 -->
<div v-bind:id="rawId | formatId"></div>
示例如下:
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>过滤器</title>
</head>

<body> 
    <div id="app">
        <ul>
            <div v-bind:id="idtag | filterGender">这里v-bind写法:{{ idtag | changeid  }}</div>
        </ul>
    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>

    <script> 
        let vm = new Vue({
            el: "#app",
            data: {
                idtag:'id001',
            },
            // 专门针对数据过滤
            filters:{
                changeid(idtag){
                    var numReg = /^[0-9]*$/
                    var numRe = new RegExp(numReg)
                    if(!numRe.test(idtag)){
                        return '错误的id'
                    }else{
                        return idtag
                    }

                }
            }
        })
    </script>
</body>

</html>
这是使用v-bind属性指令来演示filters,下面看个常规的,如下代码:
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>过滤器</title>
</head>

<body> 
    <div id="app">
        <ul>
            <li v-for="user in userList">
                姓名:{{user.name}};性别:{{formateGender(user.gender)}}
                {{user.gender | filterGender}}
            </li>
        </ul>
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>

    <script> 
        let vm = new Vue({
            el: "#app",
            data: {
                userList: [
                    { id: 1, name: 'xushu', gender: 1 },
                    { id: 2, name: 'zhuge', gender: 0 }
                ]
            },
            methods: {
                formateGender(gender){
                    if(gender==1){
                        return "~男"
                    }else{
                        return "~女"
                    }
                }
            },
            // 专门针对数据过滤
            filters:{
                filterGender(gender){
                    if(gender==1){
                        return "!男"
                    }else{
                        return "!女"
                    }
                }
            }
        })
    </script>
</body>

</html>
动手试试,一目了然。

04 - 常用指令缩写

Vue最为常用指令缩写有两个,如下:

v-bind 缩写

<!--完整语法-->
<a v-bind:href="url">测试</a>
<!--缩写-->
<a :href="url">测试</a>

v-on 缩写

<!--完整语法-->
<a v-on:click="doSomething">修改</a>
<!--缩写-->
<a @click="doSomething">修改</a>
其中属性绑定指令的应用需要注意:
  • 插值表达式只能用在元素的内容节点中,不能用在元素的属性节点中!
  • 在 vue 中,可以使用 v-bind: 指令,为元素的属性动态绑定值;
  • 简写是英文的:
  • 在使用 v-bind 属性绑定期间,如果绑定内容需要进行动态拼接,则字符串的外面应该包裹单引号,
    例如:
<div :title="'box'+ index">这是一个 div</div>

本节主要介绍Vue常用三大法器:计算器、监听器和过滤器,感兴趣可以研究一下更多内置法器。

回复

我来回复
  • 暂无回复内容