bjday2——vue过滤器、计算和监听属性、阻止事件冒泡

一、Vue对象提供的属性功能

  1. 过滤器

过滤器,就是Vue允许开发者自定义文本格式化函数, 可以使用在两个地方:

输出内容和操作数据。

自定义过滤器的两种方法:

1.1 使用Vue.filter()进行全局定义

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
    <style>
        #goods table {
             600px;
            border: 1px solid #000;
            border-collapse: collapse;
        }

        #goods td, #goods th {
            border: 1px solid #000;
        }

        #goods .box {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            margin: auto;
            background-color: #eee;
             280px;
            height: 160px;
            padding: 40px 80px;
        }
    </style>
</head>
<body>
<div id="goods">
    <button @click="change">添加商品</button>
    <div class="box" v-show="show">
        商品标题: <input type="text" v-model="goods_info.name"><br><br>
        商品数量: <input type="text" v-model="goods_info.num"><br><br>
        商品价格: <input type="text" v-model="goods_info.price"><br><br>
        <button @click="add_goods">保存</button>
        <button @click="change">取消</button>
    </div>
    <table>
        <tr>
            <th>商品id</th>
            <th>商品标题</th>
            <th>商品数量</th>
            <th>商品价格</th>
        </tr>
        <tr :bgcolor="index%2==0?color.even:color.odd" v-for="(book,index) in goods_list">
            <td>{{index}}</td>
            <td>{{book.name}}</td>
            <td>{{book.num}}</td>
            <td>{{book.price}}</td>
        </tr>
    </table>
</div>
<script>
    let vm = new Vue({
        el: '#goods',
        data: {
            color: {
                odd: '#ffaaaa',
                even: '#aaaaff',
            },
            show: false,
            goods_info: {'name': '', 'num': 0, 'price': 0},
            goods_list: [
                {'name': 'python入门', 'num': 11, 'price': 11.11},
                {'name': 'python进阶', 'num': 22, 'price': 22.22},
                {'name': 'python高级', 'num': 33, 'price': 33.33},
                {'name': 'python放弃', 'num': 44, 'price': 44.44},
            ]
        },
        methods: {
            change() {
                // 点击之后切换show的布尔值,默认为false隐藏添加窗口,点击保存或取消时,切换为false从而将商品隐藏
                this.show = this.show != true
            },
            add_goods() {
                // &&与关系同真才为真,输入框都输入数据的时候才能进行保存
                if (this.goods_info.name && this.goods_info.num && this.goods_info.price) {
                    // 将用户输入数据组成的对象插入到商品列表中
                    this.goods_list.push(this.goods_info);
                    // 将添加商品窗口隐藏
                    this.show = this.show != true
                } else {
                    // 将添加商品窗口隐藏
                    this.show = this.show != true
                    return false;
                }
            },
        }
    })
</script>

image-20200617155022354

1.2 . 在vue对象中通过filters属性来定义

<div id="app">
    <div>{{money}}</div>
    <div>{{money|format}}</div>
</div>
<script>
    let vm = new Vue({
        el:'#app',
        data:{
            money:6.666
        },
        filters:{
            format(money){
                return money.toFixed(2)
    }
        }
    })
</script>

局部过滤器只能在当前vm对象中使用

2. 计算和监听属性

2.1 计算属性

我们之前学习过字符串反转,如果直接把反转的代码写在元素中,则会使得其他同事在开发时时不易发现数据被调整了,所以vue提供了一个计算属性(computed),可以让我们把调整data数据的代码存在在该属性中。

<div id="app">
    <p>{{str1}}</p>
    <p>{{str1Rvs}}</p>
</div>
<script>
    let vm = new Vue({
        el:'#app',
        data:{
            str1:'ABCDEF'
        },
        computed:{  //计算属性:里面的函数都必须有返回值
            str1Rvs:function(){
                return this.str1.split("").reverse().join("")
            }
        }
    })
</script>

再举个小例子,页面有两个input框和一个span标签,可以用计算属性实现将两个框子动态输入的值求和后展示到span标签内。

<div id="app">
    <input type="text" v-model="num1">+
    <input type="text" v-model="num2">=
    <span>{{sum}}</span>
</div>
<script>
    let vm = new Vue({
        el: '#app',
        data: {
            num1: 0,
            num2: 0,
        },
        computed: {
            sum() {
                // 前端页面输入的内容全都是字符,需要转成数据类型
                // ( parseFloat/parseInt/number:浮点/整型)
                let num3 = parseFloat(this.num1) + parseFloat(this.num2)
                // let num3 = parseInt(this.num1) + parseInt(this.num2)
                return num3
            }
        }
    })
</script>

小数可以相加:

image-20200617163719174

小数部分忽略:

image-20200617163339381

2.2 监听属性

监听属性可以帮助我们监听vm对象data内的某个数据的变化,从而做出相应的自定义操作。

监听属性是一个对象,他的键是data内要监听的对象或者是变量,值一般是函数,当监听的数据发生变换是,会触发对应自定义函数的执行。这个函数被调用时,vue会传入两个形参,第一个是变化后的数据值,第二个是变化前的数据值

<div id="app">
    <button @click="num++">赞{{num}}</button>

</div>
<script>
    let vm = new Vue({
        el: '#app',
        data: {
            num: 0
        },
        watch: {
            num(new_v, old_v) {
                if (this.num >= 5) {
                    this.num = 5
                }
                console.log('修改之后的值:' + new_v, '修改之前的值:' + old_v)
            }
        }
    })
</script>

image-20200617165509947

3. vue对象的生命周期

3.1 钩子函数

每个Vue对象载创建是都要经过一系列的初始化过程。在这个过程中Vue.js会自动运行生命周期提供的钩子函数,我们可以使用这些函数,在对象创建的不同阶段加上我们需要的代码,实现特定的功能。

vue对象的生命周期流程图

  • beforeCreate:vm对象尚未创建
  • created:created:vm对象创建完成,设置好了要控制的元素范围
  • beforeMount:vm对象尚未把data数据显示到页面中
  • mounted:vm对象已经把data数据显示到页面中
  • beforeUpdate:vm对象尚未把更新后的data数据显示到页面中
  • updated:vm对象已经把更新后的data数据显示到页面中
  • beforeDestroy:vm对象销毁回收前
  • destoryed:vm对象销毁回收之后
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="js/vue.min.js"></script>
    <script>
    window.onload = function(){
        var vm = new Vue({
            el:"#app",
            data:{
                num:0
            },
            beforeCreate:function(){
                console.log("beforeCreate,vm对象尚未创建,num="+ this.num);  //undefined
                this.name=10; // 此时没有this对象呢,所以设置的name无效,被在创建对象的时候被覆盖为0
            },
            created:function(){
                console.log("created,vm对象创建完成,设置好了要控制的元素范围,num="+this.num );  // 0
                this.num = 20;
            },
            beforeMount:function(){
                console.log( this.$el.innerHTML ); // <p>{{num}}</p>
                console.log("beforeMount,vm对象尚未把data数据显示到页面中,num="+this.num ); // 20
                this.num = 30;
            },
            mounted:function(){
                console.log( this.$el.innerHTML ); // <p>30</p>
                console.log("mounted,vm对象已经把data数据显示到页面中,num="+this.num); // 30
            },
            beforeUpdate:function(){
                // this.$el 就是我们上面的el属性了,$el表示当前vue.js所控制的元素#app
                console.log( this.$el.innerHTML );  // <p>30</p>
                console.log("beforeUpdate,vm对象尚未把更新后的data数据显示到页面中,num="+this.num); // beforeUpdate----31
                
            },
            updated:function(){
                console.log( this.$el.innerHTML ); // <p>31</p>
                console.log("updated,vm对象已经把过呢更新后的data数据显示到页面中,num=" + this.num ); // updated----31
            },
        });
    }
    </script>
</head>
<body>
    <div id="app">
        <p>{{num}}</p>
        <button @click="num++">按钮</button>
    </div>
</body>
</html>

最常用的是created和mounded,vue对象创建以后,把ajax请求后端数据的代码放进 created,在vue使用的过程中,如果要初始化操作,把初始化操作的代码放在 mounted 中执行。

4. 阻止时间冒泡阻止页面刷新

事件冒泡:指代js中内层的子元素的事件触发以后,如果外层的父级元素具有该类事件,会导致父级元素的该类事件一并被触发到。

好处:如果能正确利用这种现象,可以实现事件委托,提升特效的性能

坏处:如果没有正确使用,则会导致不必要的bug出现。

4.1 js中阻止事件冒泡:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件冒泡</title>
    <style>
        .box1 {
             400px;
            height: 300px;
            background-color: orange;
            padding-top: 100px;
        }

        .box2 {
             200px;
            height: 200px;
            background-color: #000;
            margin: auto;
        }
    </style>
</head>
<body onclick="alert('点击了body')">
<div class="box1">
    <div class="box2"></div>
    <script>
        let box1 = document.getElementsByClassName("box1")[0];
        let box2 = document.getElementsByClassName("box2")[0];
        box1.onclick = function (event) {
            alert('点了box1')
            // event.stopPropagation();
        }
        box2.onclick = function (event) {
            alert('点了box2');
            event.stopPropagation();
        }
    </script>
</div>
</body>
</html>

给需要阻止冒泡的事件内加上event.stopPropagation()

4.2 vue阻止事件冒泡

事件后加.top,如:

@click=""——>@click.stop=""

<div id="app" class="box1" @click="show('点击了box1')">
    <div class="box2" @click.stop="show('点击了box2')"></div>
</div>
<script>
    let vm = new Vue({
        el:'#app',
        data:{},
        methods:{
            show(message){
                alert(message)
            }
        }
    })
</script>

4.3 阻止页面刷新

可用于表单submit按钮,点击后提交数据阻止页面的刷新。

事件后加.prevent,如:

@click=""——>@click.stop.prevent=""

<div id="app">
    <a href="https://www.baidu.com" @click.prevent="show">百度</a>  <!--点击后不在跳转到百度-->
</div>
<script>
    let vm = new Vue({
        el:'#app',
        data:{},
        methods:{
            show(){}
        }
    })
</script>

4.4 事件委托

事件委托就是利用事件冒泡的原理,将多个子元素的事件交给父元素去绑定执行,提升事件的 效率,并且通过event.target,还能找到目标子元素。

<body>
    <ul id="app">
        <li>1111111111111111</li>
        <li>2222222222222222</li>
        <li>3333333333333333</li>
        <li>4444444444444444</li>
        <li>5555555555555555</li>
    </ul>
<script>
    var ul = document.getElementById('app')
    ul.onclick = function (event) {
        let self = event.target
        console.log(self.innerHTML)
    }
</script>

5. 综合案例-todolist

学习计划表

5.1 展示也有计划

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>todolist</title>
    <style type="text/css">
        .list_con {
             600px;
            margin: 50px auto 0;
        }

        .inputtxt {
             550px;
            height: 30px;
            border: 1px solid #ccc;
            padding: 0px;
            text-indent: 10px;
        }

        .inputbtn {
             40px;
            height: 32px;
            padding: 0px;
            border: 1px solid #ccc;
        }

        .list {
            margin: 0;
            padding: 0;
            list-style: none;
            margin-top: 20px;
        }

        .list li {
            height: 40px;
            line-height: 40px;
            border-bottom: 1px solid #ccc;
        }

        .list li span {
            float: left;
        }

        .list li a {
            float: right;
            text-decoration: none;
            margin: 0 10px;
        }
    </style>
    <script src="vue.js"></script>
</head>
<body>
<div id="app">
    <input type="text" class="inputtxt">
    <input type="button" class="inputbtn" value="增加">
    <ul class="list">
        <li v-for="items in todolist" id="list">
            <span>{{items}}</span>&nbsp;&nbsp;
            <!--javascript:阻止a标签跳转-->
            <a href="javascript:;" class="up">↑</a>&nbsp;&nbsp;
            <a href="javascript:;" class="down">↓</a>&nbsp;&nbsp;
            <a href="javascript:;" class="del">删除</a>
        </li>
    </ul>

</div>
<script>
    let vm = new Vue({
        el: '#app',
        data: {
            todolist: ["学习html", "学习css", "学习javascript", "学习语文"]
        },
    })
</script>
</body>
</html>

5.2 添加新的学习计划及修改计划顺序

<body>
<div id="app" class="list_con">
    <input type="text" class="inputtxt" v-model="message">
    <input type="button" class="inputbtn" value="增加" @click="add">
    <ul class="list">
        <li v-for="items,index in todolist" id="list">
            <span>{{items}}</span>&nbsp;&nbsp;
            <!--javascript:阻止a标签跳转-->
            <a href="javascript:;" class="up" @click="up(index)">↑</a>&nbsp;&nbsp;
            <a href="javascript:;" class="down" @click="down(index)">↓</a>&nbsp;&nbsp;
            <a href="javascript:;" class="del" @click="delItem(index)">删除</a>
        </li>
    </ul>

</div>
<script>
    let vm = new Vue({
        el: '#app',
        data: {
            message: '',
            todolist: ["学习html", "学习css", "学习javascript", "学习语文"]
        },
        methods: {
            // 添加计划
            add() {
                if (this.message == "") {
                    return false
                } else {
                    let item = this.message;
                    this.todolist.push(item)
                    this.message="";
                }
            },
            // 上移计划
            up(index) {
                // splice() 从数组中添加/删除项目,然后返回被删除的项目,
                // 参数1/参数2/参数3:删除的起始索引/删除的个数,0则不删/删除后替补的值,不删时为添加。
                let current = this.todolist.splice(index, 1)[0];  // 获取当前删除的索引对应的值
                console.log(current)
                this.todolist.splice(index - 1, 0, current)
            },
            // 下移计划
            down(index) {
                let current = this.todolist.splice(index, 1)[0];
                console.log(current)
                this.todolist.splice(index + 1, 0, current)
            },
            // 删除计划
            del(index) {
                this.todolist.splice(index, 1)
            }
        }
    })
</script>
</body>

效果:

展示计划:

image-20200617210641570

添加计划:

image-20200617210819123

删除计划:

image-20200617210949734

上移计划:

image-20200617211233347

下移计划:

image-20200617211934357

补充:事件的函数名千万不要和data里面的数据变量名相同,会冲突。

作业

一、完成todolist的案例,在todolist中实现隔行换色效果奇数行的计划, 背景色为"blue"偶数行的计划,背景色为"orange"

 # 修改背景颜色
# ccs样式
<style>
        .odd{
            background-color: blue;
        }
        .even{
            background-color: orange;
        }
</style> 
# 其他代码和上面综合例子相同,不同的就是下面一行用于修改背景颜色。
<li :class="index%2==0?'even':'odd'" v-for="(items,index) in todolist" id="list">

效果:

image-20200617234012076

二、使用vue.js完成表格的管理功能[添加数据,取消添加、展示商品列表,编辑商品信息,取消编辑,删除商品]
商品id默认使用下标作为值

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
    <style>
        #goods table {
             600px;
            border: 1px solid #000;
            border-collapse: collapse;
        }

        #goods td, #goods th {
            border: 1px solid #000;
        }

        #goods .box {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            margin: auto;
            background-color: #eee;
             280px;
            height: 160px;
            padding: 40px 80px;
        }
    </style>
</head>
<body>
<div id="goods">
    <button @click="change">添加商品</button>
    <div class="box" v-show="show">
        商品标题: <input type="text" v-model="goods_info.name"><br><br>
        商品数量: <input type="text" v-model="goods_info.num"><br><br>
        商品价格: <input type="text" v-model="goods_info.price"><br><br>
        <button @click="add_goods">保存</button>
        <button @click="change">取消</button>
    </div>
    <table>
        <tr>
            <th>商品id</th>
            <th>商品标题</th>
            <th>商品数量</th>
            <th>商品价格</th>
        </tr>
        <tr :bgcolor="index%2==0?color.even:color.odd" v-for="(book,index) in goods_list">
            <td>{{index}}</td>
            <td>{{book.name}}</td>
            <td>{{book.num}}</td>
            <td>{{book.price}}</td>
        </tr>
    </table>
</div>
<script>
    let vm = new Vue({
        el: '#goods',
        data: {
            color: {
                odd: '#ffaaaa',
                even: '#aaaaff',
            },
            show: false,
            goods_info: {'name': '', 'num': 0, 'price': 0},
            goods_list: [
                {'name': 'python入门', 'num': 11, 'price': 11.11},
                {'name': 'python进阶', 'num': 22, 'price': 22.22},
                {'name': 'python高级', 'num': 33, 'price': 33.33},
                {'name': 'python放弃', 'num': 44, 'price': 44.44},
            ]
        },
        methods: {
            change() {
                // 点击之后切换show的布尔值,默认为false隐藏添加窗口,点击保存或取消时,切换为false从而将商品隐藏
                this.show = this.show != true
            },
            add_goods() {
                // &&与关系同真才为真,输入框都输入数据的时候才能进行保存
                if (this.goods_info.name && this.goods_info.num && this.goods_info.price) {
                    // 将用户输入数据组成的对象插入到商品列表中
                    this.goods_list.push(this.goods_info);
                    // 将添加商品窗口隐藏
                    this.show = this.show != true
                } else {
                    // 将添加商品窗口隐藏
                    this.show = this.show != true
                    return false;
                }
            },
        }
    })
</script>

效果:

1:

image-20200617234300765

2:

image-20200617234410622

3:

image-20200617234439668

原文地址:https://www.cnblogs.com/zhangtieshan/p/13155385.html