事件监听
在前端开发中,我们需要经常和用户交互
这个时候,我们就必须监听用户发生的时间,比如点击、拖拽,键盘事件等等
在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
}
}
})