bjday2——vue过滤器、计算和监听属性、阻止事件冒泡
一、Vue对象提供的属性功能
-
过滤器
过滤器,就是Vue允许开发者自定义文本格式化函数, 可以使用在两个地方:
输出内容和操作数据。
自定义过滤器的两种方法:
1.1 使用Vue.filter()
进行全局定义
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue.js"></script>
<style>
#goods table {
width: 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;
width: 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.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>
小数可以相加:
小数部分忽略:
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>
3. vue对象的生命周期
3.1 钩子函数
每个Vue对象载创建是都要经过一系列的初始化过程。在这个过程中Vue.js会自动运行生命周期提供的钩子函数,我们可以使用这些函数,在对象创建的不同阶段加上我们需要的代码,实现特定的功能。
- 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 {
width: 400px;
height: 300px;
background-color: orange;
padding-top: 100px;
}
.box2 {
width: 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 {
width: 600px;
margin: 50px auto 0;
}
.inputtxt {
width: 550px;
height: 30px;
border: 1px solid #ccc;
padding: 0px;
text-indent: 10px;
}
.inputbtn {
width: 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>
<!--javascript:阻止a标签跳转-->
<a href="javascript:;" class="up">↑</a>
<a href="javascript:;" class="down">↓</a>
<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>
<!--javascript:阻止a标签跳转-->
<a href="javascript:;" class="up" @click="up(index)">↑</a>
<a href="javascript:;" class="down" @click="down(index)">↓</a>
<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>
效果:
展示计划:
添加计划:
删除计划:
上移计划:
下移计划:
补充:事件的函数名千万不要和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">
效果:
二、使用vue.js完成表格的管理功能[添加数据,取消添加、展示商品列表,编辑商品信息,取消编辑,删除商品]
商品id默认使用下标作为值
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue.js"></script>
<style>
#goods table {
width: 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;
width: 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:
2:
3: