监视属性
监视属性就是监视某一属性的变化
使用watch
<!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>
<!-- 引入Vue -->
<script src="./js/vue.js">
</script>
</head>
<body>
<div class='root'>
<!-- 点击按钮,显示的数字在1和0之间切换 -->
现在是{{ans}}
<button @click='change'>点击切换</button>
</div>
<script>
Vue.config.productionTip=false
new Vue({
el:'.root',
data:{
is1:true,
ans:1
},
methods: {
change(){
this.is1=!this.is1
}
},
// 使用监视属性
watch:{
// is1是被监视的属性
is1:{
// 初始化时调用Handler
//immediate:true,
//当is1发生改变了,就会调用Handel
// 参数有两个,一个是新的is1的值,一个是旧的is1的值
handler(newvalue,oldvalue) {
if(this.ans==1){
this.ans=0;
}else{
this.ans=1;
}
}
}
}
})
</script>
</body>
</html>
深度监视
监视多级结构中某个属性的变化,例如要监视number对象中a的变化,可以使用'number.a':{Handler函数}
当要监视一个多级结构中的所有属性是否发生了变化,可以使用深度监视,即在handle函数前加上deep:true
简写
当配置项中只有Handler函数时,可以使用简写
和计算属性相似
watch:{
is1(newvalue,oldvalue) {
if(this.ans==1){
this.ans=0;
}else{
this.ans=1;
}
}
}
面临异步操作时,往往选择watch
computed和watch之间的区别
computed能完成的功能,watch都可以完成。
watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。
注意:
所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象。
所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,这样this的指向才是vm 或 组件实例对象。
绑定class样式
可以使用:class='属性名'来动态绑定类名,绑定的类名可以以字符串形式(样式的类名不确定,需要动态指定时),也可以以数组的形式(要绑定的样式、动态、名字都不确定时),还可以使用对象的形式(要绑定的样式、动态、名字都确定,但要动态决定用不用时时),在这种形式中,通过设置类名的值为false或true来设置该类是否被添加
//以数组的形式
classary:['classname1','classname2']
//以类的形式
classobj:{
classname1:false,
classname1:true,
}
绑定style
可以使用:style绑定样式,具体使用方法为模版中:style='样式对象名',对象在Vue中定义
条件渲染
在模版中使用v-show可以进行条件渲染,设置是否显示,v-show='false'表示隐藏,也可以写一个判断表达式,还可以写一个变量名(data中的变量)
还可以使用v-if进行条件渲染,设置是否显示。v-if='false'表示隐藏,也可以写一个判断表达式,还可以写一个变量名(data中的变量)。与if、if else、else的逻辑相同,还有v-else-if、v-else,其中if-else后不跟判断条件。注意,使用v-if、v-else-if、v-else时,不允许打断,即中间不能有别的语句。
当使用v-if时,多个标签判断条件一样时,可以使用<template></template>标签将其进行包裹,然后对这个标签进行判断。这个标签不会对样式结构有影响,并且不能使用在v-show。
如果变化频率很高,最好使用v-show。
使用v-show时,不显示的DOM元素没有被移除,仅仅是使用样式隐藏掉。
使用v-if时,不显示的DOM元素被移除
使用v-if时,元素可能无法获取到,而使用v-show时一定可以获取到
列表渲染
基本使用
遍历数组:
<body>
<div class="root">
<ul>
<!-- 使用v-for进行列表渲染 -->
<!-- 遍历数组 -->
<!-- v-for里面的语句中的for也可以使用of -->
<!-- stu是stus数组中的对象,index是stu的索引 -->
<li v-for='(stu,index) in stus' :key='stu.id'>
{{stu.name}} {{stu.age}}
</li>
</ul>
</div>
<script>
Vue.config.productionTip=false
new Vue({
el:'.root',
data:{
// stus以数组中存对象的形式展现
stus:[
{id:'000',name:'lili',age:16},
{id:'001',name:'Anna',age:17},
{id:'002',name:'Tom',age:24},
]
}
})
</script>
</body>
v-for指令用于展示列表数据
语法:v-for="(item, index) in xxx" :key="yyy"
可以遍历:数组(item, index)、对象(value, key)、字符串((char, index)用的很少)、指定次数((number, index)用的很少)
key的作用与原理
key的作用就是给节点的标识
虚拟DOM中key的作用
key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】, 随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较
对比规则
(1) 旧虚拟DOM中找到了与新虚拟DOM相同的key:
①若虚拟DOM中内容没变, 直接使用之前的真实DOM
②若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM
(2) 旧虚拟DOM中未找到与新虚拟DOM相同的key创建新的真实DOM,随后渲染到到页面。
用index作为key可能会引发的问题
(1) 若对数据进行:逆序添加、逆序删除等破坏顺序操作: 会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低
(2) 如果结构中还包含输入类的DOM: 会产生错误DOM更新 ==>界面有问题
开发中如何选择key
(1)最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
(2)如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的
列表过滤
根据条件过滤列表,筛选出符合条件的列表
使用filter函数
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>列表过滤</title>
<script type="text/javascript" src="./js/vue.js"></script>
</head>
<body>
<div id="root">
<h2>人员列表</h2>
<input type="text" placeholder="请输入名字" v-model="keyWord">
<ul>
<li v-for="(p,index) of filPerons" :key="index">
{{p.name}}-{{p.age}}-{{p.sex}}
</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
//用watch实现
/* new Vue({
el:'#root',
data:{
keyWord:'',
persons:[
{id:'001',name:'马冬梅',age:19,sex:'女'},
{id:'002',name:'周冬雨',age:20,sex:'女'},
{id:'003',name:'周杰伦',age:21,sex:'男'},
{id:'004',name:'温兆伦',age:22,sex:'男'}
],
filPerons:[]
},
watch:{
keyWord:{
immediate:true,
handler(val){
this.filPerons = this.persons.filter((p)=>{
return p.name.indexOf(val) !== -1
})
}
}
}
}) */
//用computed实现
new Vue({
el:'#root',
data:{
keyWord:'',
persons:[
{id:'001',name:'马冬梅',age:19,sex:'女'},
{id:'002',name:'周冬雨',age:20,sex:'女'},
{id:'003',name:'周杰伦',age:21,sex:'男'},
{id:'004',name:'温兆伦',age:22,sex:'男'}
]
},
computed:{
filPerons(){
return this.persons.filter((p)=>{
return p.name.indexOf(this.keyWord) !== -1
})
}
}
})
</script>
</html>
列表排序
也是使用计算属性,使用sort方法
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>列表过滤</title>
<script type="text/javascript" src="./js/vue.js"></script>
</head>
<body>
<div id="test">
<input type="text" v-model="searchName">
<ul>
<li v-for="(p, index) in filterPersons" :key="index">
{{index}}---{{p.name}}---{{p.age}}
</li>
</ul>
<button @click="orderType = 1">年龄升序</button>
<button @click="orderType = 2">年龄降序</button>
<button @click="orderType = 0">还原顺序</button>
</div>
<script>
new Vue({
el: '#test',
data: {
searchName: '',
orderType: 0, //0代表原本, 1代表升序, 2代表降序
persons: [
{name: 'Tom', age: 10},
{name: 'Jack', age: 16},
{name: 'Rose', age: 12},
{name: 'Aka', age: 18}
]
},
computed: {
filterPersons(){
// 2. 对persons进行过滤
let fPersons = this.persons.filter(p => p.name.indexOf(this.searchName) !== -1);
// 3. 排序
if(this.orderType){
// 使用sort排序
fPersons.sort((p1, p2)=>{
// 返回负数p1在前,返回正数p2在前
return this.orderType==1 ? p1.age - p2.age : p2.age - p1.age
})
}
return fPersons;
}
},
methods: {
setOrderType(orderType){
this.orderType = orderType;
}
}
})
</script>
</body>
</html>