Vue对象提供的属性功能
一.过滤器
过滤器,就是vue允许开发者自定义的文本格式化函数,可以使用在两个地方:输出内容和操作数据中。定义过滤器的方式有两种。
1.使用Vue.filter()进行全局定义
Vue.filter("RMB", function(data){
//就是来格式化(处理)data这个数据的
if(data==0){
return data
}
return "¥"+data
})
2.在vue对象中通过filters属性来定义
var vm = new Vue({
el: "#app",
data: {
price: 1.1+8.7
},
//2.局部定义过滤器,这种方式用的更多
filters: {
// p_format(data){
// return data.toFixed(2);
p_format(data, num, num2) {
console.log(num2);
return data.toFixed(num);
}
}
})
例子:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/vue.js"></script> </head> <body> <div id="app"> <p>{{price}}</p> <p>{{price|RMB}}</p> <!-- <p>{{price|p_format}}</p>--> <!-- 注意: 这是django模板提供的过滤器传参的方式,vue不可行--> <!-- <p>{{price|p_format:2}}</p>--> <p>{{price|p_format(2,3)}}</p> <!-- <p>{{price|RMB|p_format(2,3)}}</p>--> <!-- 把¥放前面的话,返回值为字符串,所有需要放后面。--> <p>{{price|p_format(2,3)|RMB}}</p> </div> <script> //1.全局定义一个过滤器 Vue.filter("RMB", function (data) { return "¥" + data; }); var vm = new Vue({ el: "#app", data: { price: 1.1+8.7 }, //2.局部定义过滤器,这种方式用的更多 filters: { // p_format(data){ // return data.toFixed(2); p_format(data, num, num2) { console.log(num2); return data.toFixed(num); } } }) </script> </body> </html>
效果图如下:
总结:
1. 一个数据可以调用多个过滤器,每个过滤器之间使用 "|"竖杠隔开,但是过滤器之间的执行顺序是从左往右执行,所以有可能产生冲突问题.这时候可以尝试调整调用过滤器之间的顺序
2. 过滤器本质上就是一个函数,所有我们必须有返回值,否则数据调用了过滤器以后,无法得到处理后的数据结果
3. vue1.x版本时,有内置过滤器的,但是官方认为,过多的封装工具给开发者使用,会容易造成框架本身的臃肿,所以在vue2.x版本以后又废除了.
4. 过滤器本质上来说就是函数,所以函数不仅只有一个参数的.我们过滤器也支持多个参数的写法.
二.计算和侦听属性
1. 计算属性
JS学习中有过字符串反转,如果直接把反转的代码写在元素中,则会使得其他同事在开发时时不易发现数据被调整了,所以vue提供了一个计算属性(computed),可以让我们把调整data数据的代码存在在该属性中。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/vue.js"></script> </head> <body> <div id="app"> <p>{{ str1 }}</p> <p>{{ strRevs }}</p> </div> <script> var vm = new Vue({ el:"#app", data:{ str1: "abcdefgh" }, computed:{ //计算属性:里面的函数都必须有返回值 strRevs: function(){ var ret = this.str1.split("").reverse().join(""); return ret } }, }) </script> </body> </html>
效果图:
2.监听属性
侦听属性,可以帮助我们侦听data某个数据的变化,从而做相应的自定义操作。
侦听属性是一个对象,它的键是要监听的对象或者变量,值一般是函数,当侦听的data数据发生变化时,会自定执行的对应函数,这个函数在被调用时,vue会传入两个形参,第一个是变化前的数据值,第二个是变化后的数据值。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/vue.js"></script> </head> <body> <div id="app"> <p>{{num}}</p> <button @click="num++">投票</button> </div> <script> var vm = new Vue({ el:"#app", data:{ num:0, }, watch: { num(new_data,old_data){ console.log(new_data,old_data); if (new_data > 3){ this.num = 3; } } } }) </script> </body> </html>
最后测试:点击投票,票数到3就再也增加不了了。
案例(实现省市区的三级联动):
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/vue.js"></script> </head> <body> <div id="app"> 地址: <select name="" v-model="province_id"> <option value="0">请选择省份</option> <option v-for="province in province_list" :value="province.id">{{province.name}}</option> </select> <select name="" v-model="city_id"> <option value="0">请选择城市</option> <option v-if="province_id==city.parent_id" v-for="city in city_list" :value="city.id">{{city.name}}</option> </select> <select name="" v-model="area_id"> <option value="0">请选择地区</option> <option v-if="city_id == area.parent_id" v-for="area in area_list" :value="area.id">{{area.name}}</option> </select> </div> <script> var vm = new Vue({ el: "#app", data: { // 默认的起始位置为0 province_id: 0, province_list: [ {"id": 1, "name": "北京市"}, {"id": 2, "name": "广东省"}, ], city_list: [], city_id: 0, area_id: 0, area_list: [], }, watch: { province_id() { this.city_list = [ {"parent_id": 1, "id": 1, "name": "海淀区"}, {"parent_id": 1, "id": 2, "name": "昌平区"}, {"parent_id": 2, "id": 3, "name": "广州市"}, {"parent_id": 2, "id": 4, "name": "深圳市"}, ]; // 初始城市id,不初始化的话,第二次选择会有bug this.city_id = 0; this.area_id = 0; }, city_id() { this.area_list = [ {"parent_id": 1, "id": 1, "name": "中关村"}, {"parent_id": 1, "id": 2, "name": "清华园"}, {"parent_id": 2, "id": 3, "name": "沙河"}, {"parent_id": 2, "id": 4, "name": "回龙观"}, {"parent_id": 3, "id": 5, "name": "天河区"}, {"parent_id": 3, "id": 6, "name": "番禺区"}, {"parent_id": 4, "id": 7, "name": "南山区"}, {"parent_id": 4, "id": 8, "name": "宝安区"}, ]; // 初始化地区id this.area_id = 0; }, } }) </script> </body> </html>
三.vue对象的生命周期
每个Vue对象在创建时都要经过一系列的初始化过程。在这个过程中Vue.js会自动运行一些叫做生命周期的的钩子函数,我们可以使用这些函数,在对象创建的不同阶段加上我们需要的代码,实现特定的功能。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue的生命周期</title> <script src="js/vue.js"></script> </head> <body> <div id="app"> <p>{{num}}</p> <button @click="num++">投票</button> </div> <script> var vm = new Vue({ el: "#app", data: { num: 0 , }, // 8个钩子函数,常用的有6个下面列举出来的。还有2个不常用分别是:destroy和bdforeDestroy // bdforeCreate会在vm对象创建实例化以后,初始化vm内部数据之前调用 beforeCreate(){ // 类似与Python面向对象的__new__ console.log("----------beforeCreate start---------"); console.log(this); // Vue console.log(this.$el); // 还没有对视图模板进行初始化 undefined console.log(this.num); // 还没有对数据进行初始化 undefined console.log("##########beforeCreate end#########"); }, // created 在vm对象实例化并初始化数据以后,视图模板加载之前调用 // 一般情况下,会在这里编写ajax代码,从服务器端获取数据并赋值给data里面的数据(***) created(){ console.log("----------created start---------"); console.log(this); //Vue console.log(this.$el); // 还没有对视图模板进行初始化 console.log(this.num); // 此时已经可以拿到数据了 0 console.log("##########created end#########"); }, // beforeMount 在加载视图以后,给数据赋值之前调用 beforeMount(){ console.log("----------beforeMount start---------"); console.log(this); // Vue console.log(this.$el);// 已经拿到试图模板,但是数据还没别渲染 // 处于:<p>{{num}}</p> <button @click="num++">投票</button> 的状态 console.log(this.num); // 此时已经可以拿到数据了 0 console.log("##########beforeMount end#########"); }, // 加载视图并进行数据赋值以后调用 // 一般情况下,会在这里编写操作界面的代码,调整样式,制作初始化的js特效(***) mounted(){ console.log("----------mounted start---------"); console.log(this); // Vue console.log(this.$el); // 已经拿到试图模板,但是数据已经渲染 // <div id="app"><p>0</p> <button>投票</button></div> console.log(this.num); // 此时已经可以拿到数据了 console.log("##########mounted end#########"); }, // // 更新数据时,修改data数据以后,对模板的数据赋值之前调用 beforeUpdate(){ console.log("----------beforeUpdate start---------"); console.log(this); // Vue console.log(this.$el.innerHTML); //点击投票后得到数据: // <p>0</p> <button>投票</button> console.log(this.num); // 此时已经可以拿到数据了 1 console.log("##########beforeUpdate end#########"); }, // // 更新数据完成以后调用,只有页面点击了投票在运行 updated(){ console.log("----------updated start---------"); console.log(this); // Vue console.log(this.$el.innerHTML); //点击投票后 得到下列数据 // <p>1</p> <button>投票</button> console.log(this.num); // 此时已经可以拿到数据了 1 console.log("##########updated end#########"); } }) </script> </body> </html>
生命周期编写的代码位置与代码编写顺序无关。
即使将updated放在第一位也是最后执行的。
四.阻止事件冒泡和刷新页面
事件绑定时,如果同时给父子元素绑定同名事件,则在子元素触发事件以后,父元素的同名事件也会触发到,这种现象就是事件冒泡.
好处:一个触发,多次执行
利用事件冒泡的好处,可以实现事件委托.
坏处:形成事件的联动反应.
使用.stop和.prevent
1.阻止事件冒泡
例:js原生阻止的事件冒泡
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .father{ width:300px; height: 300px; background: green; } .son{ width: 100px; height: 100px; background: red; } </style> </head> <body> <div class="father"> <div class="son"></div> </div> <ul id="content_list"> <li>子元素1</li> <li>子元素2</li> <li>子元素3</li> <li>子元素4</li> <li>子元素5</li> <li>子元素6</li> <li>子元素7</li> <li>子元素8</li> </ul> <script> var fa_div = document.getElementsByClassName("father")[0]; var son_div = document.getElementsByClassName("son")[0]; fa_div.onclick=function () { alert("父元素!"); }; son_div.onclick=function (event) { alert("子元素!"); event.stopPropagation(); // 原生的js代码阻止事件冒泡 }; // 批量绑定事件, 影响都性能 // let li_list = document.getElementsByTagName("li"); // for (let i = 0;i < li_list.length; i++) { // // console.log(li_list[i]); // li_list[i].onclick = function () { // console.log(this.innerHTML); // } // } var fa_ul = document.getElementById("content_list"); fa_ul.onclick = function (e) { console.log(this); console.log(e); console.log(e.target); let _this = e.target; // 打印出此时的标签代码 console.log(_this.innerHTML); } </script> </body> </html>
在子元素中使用:event.stopPropagation();
例2:vue的事件冒泡和阻止事件冒泡
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/vue.js"></script> <style> .father{ width:300px; height: 300px; color: white; background: green; } .son{ width: 100px; height: 100px; background: red; } </style> </head> <body> <div class="father" @click="add"> <h3>{{num}}</h3> <p>点击母盒子</p> <div class="son" @click.stop="add"> 点击子盒子 </div> </div> <script> var vm = new Vue({ el:".father", data:{ num:0, }, methods:{ add() { this.num++; } } }) </script> </body> </html>
效果是点击子盒子加1,点击母盒子加1,不会出现点击子盒子而加2的冒泡情况。
2.阻止刷新页面(阻止元素默认行为)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/vue.js"></script> </head> <body> <div class="father"> <a href="" @click="add">{{text1}}</a> <a href="" @click.prevent="add">{{text2}}</a> </div> <script> var vm = new Vue({ el: ".father", data: { text1: "a标签有刷新效果", text2: "a标签阻止默认行为", }, methods:{ add(){ alert("出来了.") } } }) </script> </body> </html>
正常情况下是,点击了弹出警告框点击确定后会刷新页面,但是很多开发的时候不允许这样的刷新,于是要阻止这样的刷新使用了:@click.prevent。从下面动态测试,第一个为没有加prevent的可以看到确定后自动会产生刷新,而第二个不会。
五. 综合案例-Vuedolist
首先是未加功能代码为:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>VueDoList 案例</title> <head> <meta charset="UTF-8"> <title>VueDoList案例</title> <style> .list_con { width: 600px; margin: 50px auto 0; } .inputtxt { width: 550px; height: 30px; border: 1px solid #ccc; padding: 0; text-indent: 10px; } .inputbtn { width: 40px; height: 32px; padding: 0; border: 1px solid #ccc; } .list { 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> </head> <body> <div id="VueDoList" class="list_con"> <h2>To do list</h2> <input type="text" name="" id="txt1" class="inputtxt"> <input type="button" name="" value="增加" id="btn1" class="inputbtn"> <ul id="list" class="list"> <!-- javascript:void(0); # 阻止a标签跳转 --> <li> <span>学习html</span> <a href="javascript:void(0);" class="up"> ↑ </a> <a href="javascript:void(0);" class="down"> ↓ </a> <a href="javascript:void(0);" class="del">删除</a> </li> <li> <span>学习css</span> <a href="javascript:void(0);" class="up"> ↑ </a> <a href="javascript:void(0);" class="down"> ↓ </a> <a href="javascript:void(0);" class="del">删除</a> </li> <li> <span>学习javascript</span> <a href="javascript:void(0);" class="up"> ↑ </a> <a href="javascript:void(0);" class="down"> ↓ </a> <a href="javascript:void(0);" class="del">删除</a> </li> </ul> </div> </body> </html>
效果图为:
下面我们通过vue来实现页面的列表计划管理。
首先进行需求分析:
1. 把计划数据展示到页面中
2. 当用户填写计划以后,点击"增加"按钮时,把数据添加到计划列表中,展示出来
3. 当用户点击"删除"按钮,把当前一行的计划数据移除掉
4. 当用户点击"↑",则需要把当前一行和上一行数据之间的位置,进行互换
5. 当用户点击"↓",则需要把当前一行和下一行数据之间的位置,进行互换
然后,开始一项一项的完成需求:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>VueDoList 案例</title> <head> <meta charset="UTF-8"> <title>VueDoList案例</title> <style> .list_con { width: 600px; margin: 50px auto 0; } .inputtxt { width: 550px; height: 30px; border: 1px solid #ccc; padding: 0; text-indent: 10px; } .inputbtn { width: 40px; height: 32px; padding: 0; border: 1px solid #ccc; } .list { 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="js/vue.js"></script> </head> <body> <div id="VueDoList" class="list_con"> <h2>Vue do list</h2> <input type="text" name="" v-model="plan" id="txt1" class="inputtxt"> <input type="button" name="" @click="add_data" value="增加" id="btn1" class="inputbtn"> <ul id="list" class="list"> <li v-for="item,index in data_list"> <span>{{item.title}}</span> <a href="javascript:void(0);" @click="move_up(index)" class="up"> ↑ </a> <a href="javascript:void(0);" @click="move_down(index)" class="down"> ↓ </a> <a href="javascript:void(0);" @click="del_data" class="del">删除</a> </li> </ul> </div> <script> var vm = new Vue({ el: "#VueDoList", data: { plan: "", data_list: [ {"title": "学习html"}, {"title": "学习css"}, {"title": "学习javascript"}, ] }, methods: { //新增数据 add_data() { // this.data_list.unshift({"title":this.plan}); this.data_list.splice(0, 0, {"title": this.plan}) // console.log(this) }, // 删除数据,根据索引删除 del_data(index) { // console.log(index) // console.log( this.data_list[index] ); // 可以使用js原生的数组方法来完成删除指定下表的成员 // 数组.splice(开始截取的下表,截取的成员数量,替换的成员) this.data_list.splice(index, 1) }, // 向上移动数据(current表示当前位置) move_up(index){ if(index > 0) { // 1. 先把当前要移动的元素提取出来 let current = this.data_list.splice(index, 1)[0]; // 2. 再把提取出来的元素放到index - 1的位置 this.data_list.splice(index - 1, 0, current); } }, // 向下移动数据 move_down(index){ // 1. 先把当前要移动的元素提取出来 let current = this.data_list.splice(index, 1)[0]; // 2.把取出来的元素放到index+1 的位置 this.data_list.splice(index + 1, 0, current); } } }) </script> </body> </html>
效果图为:
可以进行增删和上移下移。