vue语法(二)

事件监听

在前端开发中,我们需要经常和用户交互

​ 这个时候,我们就必须监听用户发生的时间,比如点击、拖拽,键盘事件等等

​ 在Vue中如何监听事件?使用v-on指令

v-on介绍

​ 作用:绑定事件监听器

​ 缩写:@

​ 预期:Function | Inline Statement | Object

​ 参数:event

当通过methods中定义方法,以供@click调用时,需要注意参数问题:

1.如果该方法不需要额外参数,那么方法后的()可以不添加。

但是注意:如果方法本身中有一个参数,那么会默认将原生事件event参数传递进去

2.如果需要同时传入某个参数,同时需要event时,可以通过$event传入事件。

<body>
    <div id="app">
        <!-- 调用没有参数的方法  -->
        <button v-on:click="btnclick">按钮一</button>
        <button @click="btnclick">按钮二</button>
        <!-- 调用有参数的方法 -->
        <button @click="onClick(123)">按钮三</button>
        <!-- 在事件定义时,写方法时省略了小括号,但是方法本身是需要一个参数的,这个时候,Vue会默认将浏览器生产的event事件对象作为参数传入到方法 -->
        <button @click="btnonClick">按钮四</button>
        <!-- 方法定义时,我们需要event对象,同时又需要其他参数 -->
        <!-- 在调用方式,如何手动的获取到浏览器参数的event对象:$event -->
        <button @click="btnsClick(123,$event)">按钮五</button>
    </div>
</body>
<script src="../js/vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {},
        methods: {
            btnclick() {
                console.log('btn触发了');
            },
            onClick(a) {
                console.log(a);
            },
            btnonClick(event) {
                console.log(event);
            },
            btnsClick(a, event) {
                console.log(a);
                console.log(event);
            }
        }
    })
</script>

v-on修饰符使用

.stop 阻止事件冒泡 调用了event.stopPropagation()

.prevent 阻止默认事件 调用了event.preventDefault()

.{keyCode | keyAlias}- 只当事件是从特定键触发时才触发回调。

.native - 监听组件根元素的原生事件。

.once - 只触发一次回调。

<body>
    <div id="app">
        <!-- .stop修饰符的使用 -->
        <div @click="divClick">
            <button @click.stop="onClick">点击</button>
        </div>
        <!-- .prevent修饰符的使用 -->
        <form action="baidu">
            <input type="submit" value="提交" @click.prevent='submitClick'>
        </form>
        <!-- 监听某个键 -->
        <input type="text" @keyup.enter="keyup">
        <!-- .once修饰符的使用 -->
        <button @click.once="once">点击一次</button>
    </div>
</body>
<script src="../js/vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {},
        methods: {
            divClick() {
                console.log('divClick触发');
            },
            onClick() {
                console.log("onClick触发");
            },
            submitClick() {
                console.log("submitClick触发");
            },
            keyup() {
                console.log("keyup触发");
            },
            once() {
                console.log("once触发");
            }
        }
    })
</script>

v-if、v-else-if、v-else的使用

这三个指令与Javascript的条件语句if、else、else if类似

Vue的条件指令可以根据表达式的值在DOM中渲染成销毁元素或组件

案例演示:

<body>
    <div id="app">
        <h1 v-if="score>=90">优秀</h1>
        <h1 v-else-if="score>=80">良好</h1>
        <h1 v-else-if="score>=60">及格</h1>
        <h1 v-else>不及格</h1>
        <h1>{{result}}</h1>
    </div>
</body>
<script src="../js/vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            score: 99,
        },
        computed: {
            result() {
                let showData = "";
                if (this.score >= 90) {
                    showData = '优秀'
                } else if (this.score >= 80) {
                    showData = '良好'
                } else if (this.score >= 60) {
                    showData = '及格'
                } else {
                    showData = '不及格'
                }
                return showData
            }
        }
    })
</script>
如果逻辑比较复杂不建议使用第一种,建议使用computed计算属性。

v-if的原理:

v-if后面的条件为false时,对应的元素以及其子元素不会渲染。

也就是根本没有不会有对应的标签出现在DOM中。

登录切换小案例
<body>
    <div id="app">
        <span v-if="isUser">
            <label for="username">用户账号</label>
            <input type="text" id="username" placeholder="请输入用户账户" key="username">
        </span>
        <span v-else>
            <label for="email">用户邮箱</label>
            <input type="text" id="email" placeholder="请输入用户邮箱" key="email">
        </span>
        <button @click="isUser = !isUser">切换类型</button>
    </div>
</body>
<script src="../js/vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            isUser: true
        }
    })
</script>

小案例问题

问题:

如果我们在有输入内容的情况下,切换了类型,我们会发现文字依然显示之前的输入的内容。

但是按道理讲,我们应该切换到另一个input元素中了。

在另一个input元素中,我们并没有输入内容。

问题解答:

这是因为Vue在进行DOM渲染时,出于性能考虑,会尽可能的复用已经存在的元素,而不是重新创建新的元素。

在上面的案例中,Vue内部会发现原来的input元素不再使用,直接作为else中的input来使用了。

解决方案:

如果我们不希望Vue出现类似重复利用的问题,可以给对应的input添加key属性。并且我们需要保证key不同。

v-show

v-show的用法和v-if非常相似,也用于决定一个元素是否渲染

v-if和v-show对比

v-if当条件为false时,压根不会有对应的元素在DOM中。

v-show当条件为false时,仅仅是将元素的display属性设置为none而已。

开发中如何选择:

当需要在显示与隐藏之间切换很频繁时,使用 v-show

当只有一次切换时,使用v-if。

v-for

遍历数组

<body>
    <div id="app">
        <!-- 1.在遍历的过程中,没有使用索引值(下标值) -->
        <ul>
            <li v-for="item in names">{{item}}</li>
        </ul>
        <!-- 2.在遍历的过程中,获取索引值 -->
        <ul>
            <li v-for="(item,index) in names">{{index+1}}---{{item}}</li>
        </ul>
    </div>
</body>
<script src="../js/vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            names: ['123', '456', '789', '10jq']
        }
    })
</script>

遍历对象

<body>
    <div id="app">
        <!-- 1.在遍历对象的过程中,如果只是获取一个值,那么获取到的是value -->
        <ul>
            <li v-for="item in info">{{item}}</li>
        </ul>
        <!-- 2.获取key和value 格式:(value,key) -->
        <ul>
            <li v-for="(value,key) in info">{{key}}---{{value}}</li>
        </ul>
        <!-- 3.获取key和value和index 格式:(value,key,index) -->
        <ul>
            <li v-for="(value,key,index) in info">{{key}}---{{value}}----{{index}}</li>
        </ul>
    </div>
</body>
<script src="../js/vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            info: {
                name: 'why',
                age: 18,
                height: 1.88
            }
        }
    })
</script>
列表点击案例
<!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>
    <style>
        .active {
            color: red;
        }
    </style>
</head>

<body>
    <div id="app">
        <ul>
            <li v-for="(item,index) in movies" :class="{active : currentIndex === index}" @click="lionClick(index)">
                {{item}}
            </li>
        </ul>
    </div>
</body>
<script src="../js/vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            movies: ['海王', '蜘蛛侠', '钢铁侠', '蝙蝠侠'],
            currentIndex: 0
        },
        methods: {
            lionClick(index) {
                this.currentIndex = index
            }
        }
    })
</script>

</html>

组件的key属性

官方推荐我们在使用v-for时,给对应的元素或组件添加上一个:key属性。

为什么需要这个key属性呢?

这个其实和Vue的虚拟DOM的Diff算法有关系。

在循环遍历时,key要使用唯一对应值,不要使用index下标,在某些场合下会出现问题。

总结:key的作用主要是为了高效的更新虚拟DOM。

vue过滤器

过滤器可以用在这两个地方:双花括号(mustache语法)和v-bind表达式 。 过滤器应该被添加在JavaScript表达式的尾部,由“管道”符号指示:

<!-- 在双花括号中 -->
{{message | capitalize}}

<!-- 在`v-bind`中 -->
<div v-bind:id="rawId | formatId"></div>

vue中的过滤器分为两种:局部过滤器和全局过滤器

1、定义无参全局过滤器

<div id="app">
            <p>{{ msg | mat}}</p>
        </div>

        <script>
            // 定义一个 Vue 全局的过滤器,名字叫做  msgFormat
            Vue.filter('mat', function(msg) {
                // 字符串的  replace 方法,第一个参数,除了可写一个 字符串之外,还可以定义一个正则
                return msg.replace(/aa/g, 'xx')
            })
        </script>

2、定义有参全局过滤器

   <div id="app">
            <p>{{ msg | mat('我是','--')}}</p>
        </div>

        <script>
            // 定义一个 Vue 全局的过滤器,名字叫做 mat
            Vue.filter('mat', function(msg, arg, arg2) {
                // 字符串的  replace 方法,第一个参数,除了可写一个 字符串之外,还可以定义一个正则
                return msg.replace(/aa/g, arg+arg2)
            })
      </script>

3、局部过滤器

局部过滤器的有参和无参的定义和使用方法与全局的过滤器一样。唯一的区别在于局部过滤器是定义在vue的实例中。其作用的区域也是vue实例#app控制的区域

    // 创建 Vue 实例,得到 ViewModel
            var vm = new Vue({
                el: '#app',
                data: {
                    msg: '曾经,我也是一个单纯的少年'
                },
                methods: {},
                //定义私用局部过滤器。只能在当前 vue 对象中使用
                filters: {
                    dataFormat(msg) {
                        return msg+'xxxxx';
                    }
                }
            });

注意:

1、 当有局部和全局两个名称相同的过滤器时候,会以就近原则进行调用,即:局部过滤器优先于全局过滤器被调用!

2、 一个表达式可以使用多个过滤器。过滤器之间需要用管道符“|”隔开。其执行顺序从左往右

数组中有哪些方法是响应式的

push - 将数据添加到数组末尾处

pop - 删除数组末尾的元素

shift - 删除数组第一个元素

unshift - 在数组最前面添加元素

splice - 删除元素/插入元素/替换元素

第一个参数:开始的位置。

删除元素:第二个参数传入你要删除几个元素(如果没有传,就删除后面所有的元素)

替换元素:第二个参数,表示我们要替换几个元素,后面是用于替换前面的元素

插入元素:第二个参数,传入0,并且后面跟上要插入的元素

sort - 排序

reverse - 反转

注意:通过索引值修改数组中的元素,不是响应式的

this.letters[0] = 'bbbb';

拓展:

vue内部实现函数

set(要修改的值,索引值,修改后的值)

Vue.set(this.letter,0,“bbb”)

js高阶函数

filter/map/reduce

const nums = [10,20,30,40,111,555,777]

1.filter函数的使用

filter中的回调函数有一个要求:必须返回一个Boolean值

当返回的true时,函数内部会自动将这次回调的n加入到新的数组中

当返回false时,函数内部会过滤掉这次的n

let newNums = nums.filter(function(){

	return n < 100

})
//10 20 30 40 

2.map函数的使用

let new2Nums = newNums.map(function(n){
	return n * 2
})
//20 40 60 80

3.reduce函数的使用

reduce的作用对数组中所有的内容进行汇总

let total = new2Nums.reduce(function(preValue,n){
	return preValue + n 
},0)
//240

结合三种一起使用:

let total = nums.filter(n => n<100).map(n => n * 2).reduce((pre,n)=> pre +n);

购物车案例

页面:

<!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">
        <div v-if="books.length">
            <table border="1" cellspacing='0'>
                <caption>
                    <h2>购物车</h2>
                </caption>
                <colgroup>
                    <col width='40' />
                    <col width='150' />
                    <col width='150' />
                    <col width='40' />
                    <col width='120' />
                    <col width='100' />
                </colgroup>
                <tbody>
                    <tr>
                        <th></th>
                        <th>书籍名称</th>
                        <th>出版日期</th>
                        <th>价格</th>
                        <th>购买数量</th>
                        <th>操作</th>
                    </tr>
                    <tr v-for="(item,index) in books">
                        <td>{{item.id}}</td>
                        <td>{{item.name}}</td>
                        <td>{{item.date}}</td>
                        <td>{{item.price | showPrice}}</td>
                        <td align="center"><button @click="add(index)">+</button>
                            {{item.count}} <button @click="ras(index)" v-bind:disabled="item.count <= 1">-</button>
                        </td>
                        <td align="center"><button @click="remove(index)">删除</button></td>
                    </tr>
                    <tr>
                        <td align="right" colspan="6">总价:{{totalPrice | showPrice}}</td>

                    </tr>
                </tbody>
            </table>
        </div>
        <h2 v-else>购物车为空</h2>
    </div>
</body>
<script src="../js/vue.js"></script>
<script src="./gouwu.js"></script>
</html>

vue代码:

const app = new Vue({
    el:'#app',
    data:{
        books:[
            {
                id:1,
                name:'《算法导论》',
                date:'2006-9',
                price:85.00,
                count:1
            },
            {
                id:2,
                name:'《java基础教程》',
                date:'2016-9',
                price:185.00,
                count:1
            },
            {
                id:3,
                name:'《JavaScript基础》',
                date:'2004-9',
                price:85.00,
                count:1
            },
            {
                id:4,
                name:'《HTML和CSS》',
                date:'2020-9',
                price:75.00,
                count:1
            },
        ]
    },
    methods:{
        add(index){
            this.books[index].count++
        },
        ras(index){
            this.books[index].count--
        },
        remove(index){
            this.books.splice(index,1);
        }
    },
    filters:{
        // 过滤器
        showPrice(price){
            return '¥'+price.toFixed(2)
        }
    },
    computed:{
        totalPrice(){
            let total = 0
            for(let i of this.books){
                total += i.count * i.price
            }
            return total
        }
    }
})
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值