第三章 Vue进阶

1.Vue方法、计算属性及监听器

在vue中处理复杂的逻辑的时候,我们经常使用计算属性、方法及监听器。

methods:方法:它们是挂载在Vue对象上的函数,通常用于做事件处理函数,或自己封装的自定义函数。
computed:计算属性:在Vue中,我们可以定义一个计算属性,这个计算属性的值,可以依赖于某个data中的数据。或者说:计算属性是对数据的再加工处理。
watch:监听器:如果我们想要在数据发生改变时做一些业务处理,或者响应某个特定的变化,我们就可以通过监听器,监听数据的变化,从而做出相应的反应。

1.1.computed 计算属性

计算属性是根据依赖关系进行缓存的计算,并且只在需要的时候进行更新。

<div id="app">
    <p>原数据:</p>
    <p>新数据:</p>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    let vm = new Vue({
        el: '#app',
        data: {
            msg:'hello world!'
        },
        computed:{
            reversedMsg(){
                return this.msg.split('').reverse().join('');
            }
        }
    });
</script>

一个案例:根据商品数量修改总价

<div id="app">
    <table width="100%" style="text-align: center;">
        <tr>
            <th>商品编号</th>
            <th>商品名称</th>
            <th>商品单价</th>
            <th>商品数量</th>
            <th>合计</th>
        </tr>
        <tr>
            <td>1</td>
            <td>小米10</td>
            <td></td>
            <td>
                <button @click="subtract">-</button>

                <button @click="add">+</button>
            </td>
            <td></td>
        </tr>
    </table>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    let vm = new Vue({
        el: '#app',
        data: {
            price:2999,
            quantity:1
        },
        computed:{
            totalPrice(){
                return this.price*this.quantity;
            }
        },
        methods:{
            add(){
                this.quantity++;
            },
            subtract(){
                this.quantity--;
            }
        }
    });
</script>

1.2.methods 方法

在使用vue的时候,可能会用到很多的方法,它们可以将功能连接到事件的指令,甚至只是创建一个小的逻辑就像其他函数一样被重用。接下来我们用方法实现上面的字符串反转。

<div id="app" >
    <p>原数据: { { msg } } </p>
    <p>新数据: { { reversedMsg() } } </p>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    let vm = new Vue({
        el: '#app',
        data: {
            msg:'hello world!'
        },
        methods:{
            reversedMsg(){
                return this.msg.split('').reverse().join('');
            }
        }
    });
</script>

虽然使用computed和methods方法来实现反转,两种方法得到的结果是相同的,但本质是不一样的。

计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变的时候才会重新求值,这就意味着只要message还没有发生改变,多次访问reversedMessage计算属性立即返回的是之前计算的结果,而不会再次执行计算函数。

而对于methods方法,只要发生重新渲染,methods调用总会执行该函数。

如果某个computed需要的遍历一个极大的数组和做大量的计算,可以减小性能开销,如果不希望有缓存,则用methods。

1.3.watch 监听器

watch能够监听数据的改变。监听之后会调用一个回调函数。 此回调函数的参数有两个:

更新后的值(新值)
更新前的值(旧值)

1.3.1.监听基本数据类型

下面使用watch来监听商品数量的变化。如果商品数量小于1,就重置成上一个值。

<div id="app">
    <table width="100%" style="text-align: center;">
        <tr>
            <th>商品编号</th>
            <th>商品名称</th>
            <th>商品单价</th>
            <th>商品数量</th>
            <th>合计</th>
        </tr>
        <tr>
            <td>1</td>
            <td>小米10</td>
            <td></td>
            <td>
                <button @click="subtract">-</button>

                <button @click="add">+</button>
            </td>
            <td></td>
        </tr>
    </table>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    let vm = new Vue({
        el: '#app',
        data: {
            price: 2999,
            quantity: 1
        },
        computed: {
            totalPrice() {
                return this.price * this.quantity;
            }
        },
        methods: {
            add() {
                this.quantity++;
            },
            subtract() {
                this.quantity--;
            }
        },
        watch:{
            quantity(newVal,oldVal){
                console.log(newVal,oldVal);
                this.quantity = newVal<=0?oldVal:newVal
            }
        }
    });
</script>

1.3.2.深度监听

在上面的例子中,监听的简单的数据类型,数据改变很容易观察,但是当需要监听的数据变为对象类型的时候,上面的监听方法就失效了,因为上面的简单数据类型属于浅度监听,对应的对象类型就需要用到深度监听,只需要在上面的基础上加上deep: true就可以了。

<div id="app">
    <table width="100%" style="text-align: center;">
        <tr>
            <th>商品编号</th>
            <th>商品名称</th>
            <th>商品单价</th>
            <th>商品数量</th>
            <th>合计</th>
        </tr>
        <tr>
            <td>1</td>
            <td>小米10</td>
            <td></td>
            <td>
                <button @click="subtract">-</button>

                <button @click="add">+</button>
            </td>
            <td></td>
        </tr>
    </table>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    let vm = new Vue({
        el: '#app',
        data: {
            goods:{
                price: 2999,
                quantity: 1
            }
        },
        computed: {
            totalPrice() {
                return this.goods.price * this.goods.quantity;
            }
        },
        methods: {
            add() {
                this.goods.quantity++;
            },
            subtract() {
                this.goods.quantity--;
            }
        },
        watch:{
            goods:{
                handler(newVal,oldVal){
                    /**
                     * 注意:虽然使用深度监听,可以监听到对象的改变。
                     *      但是,由于是对象类型,所以newVal与oldVal都指向同一个对象。
                     *      所以,newVal与oldVal中的quantity都是改变后的新值。
                     */
                    console.log(newVal,oldVal);
                    this.goods.quantity = newVal.quantity<=0?oldVal.quantity:newVal.quantity;
                },
                deep:true
            }
        }
    });
</script>

2.Vue操作数组时的注意事项

由于 JavaScript 语言本身的限制,当我们对数组进行某些操作时,Vue 可能不会检测到数组元素的变化,那么进而视图也不会响应。比如:

<div id="app">
    <p v-for="(item,index) in userArr">
        ,,
    </p>
    <button @click="clear">清空</button>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    let vm = new Vue({
        el: '#app',
        data: {
            userArr: [{
                userId: 1,
                userName: '张三',
                userSex: '男'
            }, {
                userId: 2,
                userName: '李四',
                userSex: '女'
            }, {
                userId: 3,
                userName: '王五',
                userSex: '男'
            }]
        },
        methods: {
            clear() {
                this.userArr.length = 0;
                console.log(this.userArr.length);    //0
            }
        }
    });
</script>

上面实例中,将数组的长度设置为0后,数组确实被清空了。但是Vue却不能检测到数组的变化,所以页面视图也不会响应。

为了解决这个问题,Vue给我们提供了如下解决方案: Vue 提供一组观察数组的变异方法(就是这些方法会改变原始数组,所以才会被Vue检测到),使用它们就可以触发视图更新。 这些方法有7个:push()、pop()、shift()、unshift()、splice()、sort()、reverse()

<div id="app">
    <p v-for="(item,index) in userArr">
        ,,
    </p>
    <button @click="clear">清空</button>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    let vm = new Vue({
        el: '#app',
        data: {
            userArr: [{
                userId: 1,
                userName: '张三',
                userSex: '男'
            }, {
                userId: 2,
                userName: '李四',
                userSex: '女'
            }, {
                userId: 3,
                userName: '王五',
                userSex: '男'
            }]
        },
        methods: {
            clear() {
                //使用Vue中提供的变异方法
                this.userArr.splice(0,this.userArr.length);
            }
        }
    });
</script>

3.Vue的表单绑定

v-bind实现了数据的单向绑定,将vue实例中的数据同元素属性值进行绑定,接下来看一下vue中的数据双向绑定v-model。

3.1.v-mode实现表单绑定

<div id="app">
    <h3>注册</h3>
    <form>
        用户名:<input type="text" v-model="myForm.username"/><br>
        密码:<input type="password" v-model="myForm.password" /><br>
        确认密码:<input type="password" v-model="myForm.beginpassword" /><br>
        性别:<input type="radio" v-model="myForm.sex" value="0" /><input type="radio" v-model="myForm.sex" value="1" /><br>
        爱好:<input type="checkbox" v-model="myForm.like" value="0" />读书
             <input type="checkbox" v-model="myForm.like" value="1" />体育
             <input type="checkbox" v-model="myForm.like" value="2" />旅游<br>
        国籍:<select v-model="myForm.nationality">
                <option value="0">中国</option>
                <option value="1">美国</option>
                <option value="2">英国</option>
             </select><br>
        个人简介:<textarea v-model="myForm.brief" rows="5" cols="30"></textarea><br>
             <input type="button" value="提交" @click="handler" />
    </form>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    let vm = new Vue({
        el: '#app',
        data: {
            myForm: {
                username: '',
                password: '',
                beginpassword: '',
                sex: 0,
                like: [0, 1, 2],
                nationality: 0,
                brief: '',
                level: 0
            }
        },
        methods: {
            handler: function() {
                console.log(this.myForm.username);
                console.log(this.myForm.password);
                console.log(this.myForm.beginpassword);
                console.log(this.myForm.sex);
                console.log(this.myForm.like);
                console.log(this.myForm.nationality);
                console.log(this.myForm.brief);
            }
        }
    });
</script>

3.2.v-model修饰符

v-model中还可以使用一些修饰符来实现某些功能:

  • v-model.lazy 只有在input输入框发生一个blur时才触发,也就是延迟同步到失去焦点时。
  • v-model.trim 将用户输入的前后的空格去掉。
  • v-model.number 将用户输入的字符串转换成number。
<div id="app">
    <!-- 输入数据会延迟到失去焦点时才绑定 -->
    <input type="text" v-model.lazy="lazyStr" /><br>
    <!-- 输入数据会自动转换为number,所以可以直接进行运算 -->
    NaN<input type="text" v-model.number="numberStr" /><br>
    <!-- 输入数据会自动去除前后空格 -->
    <input type="text" v-model.trim="trimStr" /><br>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    let vm = new Vue({
        el: '#app',
        data: {
            lazyStr: '',
            numberStr:'',
            trimStr:''
        }
    });
</script>

4.过滤器

过滤器是对即将显示的数据做进一步的筛选处理,然后进行显示,值得注意的是过滤器并没有改变原来的数据,只是在原数据的基础上产生新的数据。

过滤器分全局过滤器和本地过滤器(局部过滤器)。

4.1.全局过滤器

下面定义一个全局过滤器,用于在数据前加上大写的VUE。需要注意的是,全局过滤器定义必须始终位于Vue实例之上,否则会报错。

<div id="app">
    { { message | toAdd  } }
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    Vue.filter("toAdd", function(value) {
        return 'VUE' + value
    })
    var demo = new Vue({
        el: '#app',
        data: {
            message: '过滤器',
        }
    })
</script>
注意:
    Vue.filter() 后有两个参数:过滤器名,过滤器处理函数。
    过滤器处理函数也有一个参数:要过滤的数据。

4.2.本地过滤器

本地过滤器存储在vue组件中,作为filters属性中的函数,我们可以注册多个过滤器存储在其中。

<div id="app">
    <p> { { message | Reverse } } </p>
    <p> { { message | Length } } </p>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    var demo = new Vue({
        el: '#app',
        data: {
            message: '过滤器',
        },
        filters: {
            Reverse: function(value) {
                if (!value){
                    return '';
                } 
                return value.toString().split('').reverse().join('');
            },
            Length: function(value) {
                return value.length;
            },
        },
    })
</script>

4.3.过滤器传参

过滤器也是可以传递参数的。

<div id="app">
    { { msg1 | toDou (1,2) } }
    { { msg2 | toDou (10,20) } }
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    Vue.filter('toDou', function(value, param1, param2) {
        if (param2 < 10) {
            return value + param1;
        } else {
            return value + param2;
        }
    });
    new Vue({
        el: '#app',
        data: {
            msg1: 9,
            msg2: 12,
        }
    });
</script>

注意:过滤器处理函数的第一个参数,仍然是要过滤的数据。从第二个参数开始,才是过滤器本身要传递的参数。

4.4.串联过滤器

多个过滤器可以串联使用

<div id="app">
    { { money | prefix | suffix } }
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    Vue.filter("prefix", function(value) {
        return '¥' + value
    })
    Vue.filter("suffix", function(value) {
        return  value + '元'
    })
    var demo = new Vue({
        el: '#app',
        data: {
            money:10
        }
    })
</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值