Vue的监测
- vue会监测data中所有层次的数据。
- vue检测对象中的数据的原理:通过setter实现监测,且要在new Vue时就传入要检测的数据。
- 对象中后追加的属性,vue默认不作响应式处理
- 如果要给后添加的属性做响应式,要使用一下API来添加属性:Vue.set(target, propertyName/index, value)或者vm.$set(target, propertyName/index, value)
- vue检测数组中的数据的原理:通过包裹数组更新元素的方法实现,本质是,调用原生的对应的方法对数组进行更新,然后重新解析模板,进而更新页面
- 在vue修改数组中的某个元素时一定要使用如下方法:
- 使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
- Vue.set()或者vm.$set()
- Vue.set()或者vm.$set()不能给 vm 或者 vm的根数据对象 添加属性
监测测试案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
<script type="text/javascript" src="../vue.js"></script>
</head>
<body>
<div id="root">
<h3>你好,{{name}} </h3><br/>
<h3>学生姓名是:{{student.name}}</h3>
<h3>学生年龄是:{{student.age}}</h3>
<h3>学生性别是:{{student.sex}}</h3>
<ul>
<li v-for="(person,index) in persons" :key="person.id">
姓名:{{person.name}} --年龄:{{person.age}}
</li>
</ul>
<button @click="student.age++">年龄加一</button>
<button @click="addSex">添加性别</button>
<button @click="addFriend">添加人员</button>
<button @click="updateFirstFriendName">更新第一人名字</button>
</div>
</body>
<script type="text/javascript">
let vm = new Vue({
el:'#root',
data:{
name:'李二狗',
student:{
age:19,
name:"曼波"
},
persons:[
{id:'001',name:'张三',age:18},
{id:'002',name:'李四',age:19},
{id:'003',name:'王五',age:20}
]
},
methods:{
addSex(){
Vue.set(this.student,"sex","男")
//this.$set(this.student,"sex","男")
},
addFriend(){
this.persons.unshift({id:"004",name:"jack",age:19})
},
updateFirstFriendName(){
this.persons[0].name = "哈基米"
}
}
})
</script>
</html>
收集表单数据
- 若是文本框这种输入类型,v-model收集的是value属性的值,用户输入的内容就是value
- 若是单选框,v-model收集的是选项的value,要给选项配好value属性
- 若是多选框,没有配置value属性,那么收集的就是checked属性(勾选就是true,不勾选就是false)。配置了value值后,绑定的data中的数据要是一个数组,各个多选的值会成为数组中的元素。
- v-model的三个修饰符:
- lazy:失去了焦点再收集数据,默认是边输入边收集
- number:输入的字符串转化为数字
- trim:输入首尾空格过滤
收集表单数据案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
<script type="text/javascript" src="../vue.js"></script>
</head>
<body>
<div id="root">
<form>
<label for="demo">账号:</label>
<input type="text" id="demo" v-model="account"><br><br>
<label for="demo2">密码:</label>
<input type="password" id="demo2" v-model="password"><br><br>
性别:<br>
<label for="man">男</label><input type="radio" id="man" name="sex" value="man" v-model="sex">
<label for="woman">女</label><input type="radio" id="woman" name="sex" value="woman" v-model="sex"><br><br>
爱好:<br>
<label for="sing">唱</label><input type="checkbox" id="sing" name="hobby" v-model="hobby" value="sing">
<label for="dance">跳</label><input type="checkbox" id="dance" name="hobby" v-model="hobby" value="dance">
<label for="rap">rap</label><input type="checkbox" id="rap" name="hobby" v-model="hobby" value="rap">
<label for="basketball">篮球</label><input type="checkbox" id="basketball" name="hobby" v-model="hobby" value="basketball"><br><br>
所属校区:<select name="schoolArea" id="schoolArea" v-model="schoolArea">
<option value=""></option>
<option value="jiangxi"> 江西 </option>
<option value="henan"> 河南 </option>
<option value="zhejiang"> 浙江 </option>
</select><br><br/>
其他信息:<textarea v-model="other"></textarea><br><br>
<input type="checkbox" v-model="agree"><a href="<http://www.atguigu.com>">《用户协议》</a><br><br>
<button>提交</button>
</form>
</div>
</body>
<script type="text/javascript">
let vm = new Vue({
el:'#root',
data:{
account:"",
password:"",
sex:"",
hobby:[],
schoolArea:"",
other:"",
agree:""
}
})
</script>
</html>
过滤器
过滤器用于对要使用的数据进行特定操作后再使用(适用于一些简单的逻辑),产生的是一个经过处理的新数据。
注册过滤器
局部过滤器
使用Vue实例的filters属性进行注册过滤器,例:
new Vue({
el:"#root",
data:{
hello:"哈哈哈",
time:1621561377603 //时间戳
},
computed:{
fmtTime(){
return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
}
},
//局部过滤器
filters:{
filterTest(value){
return dayjs(value).format('YYYY-MM-DD HH:mm:ss')
},
filterTest2(value,str="YYYY-MM-DD HH:mm:ss"){
return dayjs(value).format(str)
},
mySlice(value){
return value.slice(0,4)
}
}
})
在filters属性中,其中的方法的方法名就是过滤器的名称,return返回的是过滤后的结果,value和其他参数的说明在以下过滤器的使用中阐述。
全局过滤器
使用Vue.filter(name,callbackFunction)注册全局过滤器,要在Vue实例的初始化之前就注册,例:
//全局过滤器
Vue.filter("mySlice2",function(value){
return value.slice(0,2)
})
过滤器的使用
在表达式中,比如{{}}中的表达式或者一些属性(v-bind等)的属性值表达式中,使用管道符来表示使用过滤器,最终的结果就是过滤器产生的结果,例:
<h3>(过滤器)现在是:{{time | filterTest}}</h3>
此时time便会变成以上过滤器中的方法(见局部过滤器中的案例)的那个value参数,即管道符左边的表达式的结果会变成管道符右边的过滤器的value参数。
如果要加入别的参数,在管道符右边的过滤器中加上括号,在括号中加入其他参数即可,但是此时的管道符右边的参数在filters属性的方法中是从第二个参数算起的,因为第一个参数永远是管道符左边表达式的结果产生的value值(即管道符右边的第一个参数是filters中的方法的第二个参数,第二个参数是filters中的第三个参数,以此类推)。例:
<h3>(过滤器)现在是:{{time | filterTest2("YYYY-MM-DD")}}</h3>
同时,过滤器还可以嵌套使用,计算顺序是从左到右,即第二个过滤器产生的结果就是第三个过滤器的value参数值,例:
<h3>(过滤器)现在是:{{time | filterTest2("YYYY-MM-DD") | mySlice}}</h3>
过滤器的整体案例如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="<https://cdn.bootcdn.net/ajax/libs/dayjs/1.11.12/dayjs.min.js>"></script>
<script type="text/javascript" src="../vue.js"></script>
</head>
<body>
<div id="root">
<h2>显示格式化之后的时间</h2>
<h3>现在是:{{fmtTime}}</h3>
<h3>(过滤器)现在是:{{time | filterTest}}</h3>
<h3>(过滤器)现在是:{{time | filterTest2("YYYY-MM-DD")}}</h3>
<h3>(过滤器)现在是:{{time | filterTest2("YYYY-MM-DD") | mySlice}}</h3>
<h3>{{hello | mySlice2}}</h3>
</div>
<div id="root2">
<h2>{{msg | mySlice2}}</h2>
</div>
</body>
<script>
//全局过滤器
Vue.filter("mySlice2",function(value){
return value.slice(0,2)
})
new Vue({
el:"#root",
data:{
hello:"哈哈哈",
time:1621561377603 //时间戳
},
computed:{
fmtTime(){
return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
}
},
//局部过滤器
filters:{
filterTest(value){
return dayjs(value).format('YYYY-MM-DD HH:mm:ss')
},
filterTest2(value,str="YYYY-MM-DD HH:mm:ss"){
return dayjs(value).format(str)
},
mySlice(value){
return value.slice(0,4)
}
}
})
new Vue({
el:"#root2",
data:{
msg:"你好呀"
}
})
</script>
</html>
其他内置指令
内置指令复习
v-bind:单向绑定解析表达式
v-model:双向数据绑定
v-for:遍历数组、对象、字符串
v-on:绑定事件监听,可以简写为@
v-if:条件渲染(动态控制节点是否存在)
v-else:条件渲染(动态控制节点是否存在)
v-show:条件渲染(动态控制节点是否展示)
v-text
作用是解析表达式中的内容,渲染文本内容。
与插值语法的区别:v-text解析后会替换掉整个节点的文本内容,而插值表达式可以动态渲染部分文本内容
v-html
作用是向指定节点中渲染包含html结构的内容。
也是会替换整个节点的所有内容,与v-text的区别是v-html可以识别并解析html结构。
在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
一定要在可信的内容上使用v-html,不要使用在用户提交的内容上
v-cloak
没有属性值,Vue实例创建完成后并接管容器后,会删掉v-cloak属性。
使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题
v-once
没有属性值,v-once所在节点在初次动态渲染后,就视为静态内容了。
以后数据的改变不会引起v-once所在的结构的更新。
v-pre
没有属性值,跳过其所在的节点的编译过程。
可以利用其跳过没有使用指令语法、没有使用插值语法的节点,会加快编译。
自定义指令
自定义指令在directives属性中进行定义,定义方式有两种
函数式
在directives属性中,新建方法,方法名为自定义自定义指令的指令名。方法有两个参数:
- element:代表该自定义指令绑定的那个节点的DOM(为真实DOM)
- binging:其中有一些指令相关的信息,比如指令的属性值对应的表达式,指令属性值对应的值(也就是表达式的结果),指令对应的值用binging.value表示
然后在方法内进行定义指令的逻辑,例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
<script type="text/javascript" src="../vue.js"></script>
</head>
<body>
<div id="root">
<h2>当前的n值是:<span v-text="n"></span></h2>
<h2>放大十倍后的n值是:<span v-big="n"></span></h2>
<button @click="n++">点我n+1</button>
</div>
</body>
<script type="text/javascript">
let vm = new Vue({
el:'#root',
data:{
name:'李二狗',
n:12
},
directives:{
big(element,binding){
element.innerText = binding.value * 10
}
}
})
</script>
</html>
对象式
在directives属性中,使用对象的形式表示自定义指令的创建,该对象的属性名为自定义指令的指令名。对象中有三个常用方法:
- bind方法:当指令与元素成功绑定时调用
- inserted方法:指令所在元素被插入页面时
- update方法:指令所在的模板被重新解析时
函数式的逻辑其实就是bind方法和update方法用同一个方法体,结合在一起,不过没有inserted,也不能将bind和update方法的逻辑分离。
案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
<script type="text/javascript" src="../vue.js"></script>
</head>
<body>
<div id="root">
<h2>当前的n值是:<span v-text="n"></span></h2>
<h2>放大十倍后的n值是:<span v-big="n"></span></h2>
<button @click="n++">点我n+1</button>
<hr><hr>
<input type="text" v-fbind:value="n">
</div>
</body>
<script type="text/javascript">
let vm = new Vue({
el:'#root',
data:{
name:'李二狗',
n:12
},
directives:{
big(element,binding){
element.innerText = binding.value * 10
},
fbind:{
//当指令与元素成功绑定时调用此函数
bind(element,binding){
element.value = binding.value
},
//指令所在元素被插入页面时调用
inserted(element,binding){
element.focus()
},
//指令所在的模板重新被解析时调用
update(element,binding){
element.value = binding.value
element.focus()
}
}
}
})
</script>
</html>
注:
- 如果自定义指令的指令名是xxxx-xxxx这种格式的,那么在directives属性中的写法就要写为原始的形式,即属性名为字符串形式,方法也不能使用简写形式,要使用原来的”key”:function(){ }形式
- 如果定义全局的自定义指令,要使用Vue.directives(”指令名”, 函数式/对象式 写法)