链接地址:
Vue 全套教程(一)
watch
关键字,并定义一个回调函数 handler
(函数可以获取到属性修改前后的值),当被监视属性的值发生变化时,回调函数自动被调用。代码示例:
<body>
<div id="root">
<!-- 获取计算属性的值 -->
<h2>今天天气很{{info}}</h2>
<!-- 点击事件 -->
<button @click="changeWeather">切换天气</button>
</div>
</body>
<script type="text/javascript">
const vm = new Vue({
el:'#root',
data:{
isHot:true,
},
computed:{
info(){
return this.isHot ? '炎热' : '凉爽'
}
},
// 监视data中的isHot属性
watch:{
isHot:{
// 初始化时就执行回调函数一次
immediate:true,
// 回调函数
// 参数1表示监视属性的新值,参数2表示旧值,参数名称可以自定义
// 如果只有一个参数,则表示新值
handler(newValue, oldValue){
console.log('isHot被修改了', newValue, oldValue)
}
}
},
methods: {
changeWeather(){
// 修改被监视的属性值
this.isHot = !this.isHot
}
},
})
// 另一种写法
// isHot必须加引号,其他方式的key也应该加引号,不加引号采用的都是对象的简写方式,此处不是对象
// 参数1表示监视哪个属性,参数2表示监视配置
vm.$watch('isHot',{
immediate:true,
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
})
</script>
运行结果:
总结:
vm.$watch
监视。deep:true
代码示例:
<script type="text/javascript">
const vm = new Vue({
el:'#root',
data:{
// numbers属性是一个对象,值有多层
numbers:{
a:1,
b:1,
c:{
d:{
e:100
}
}
}
},
watch:{
// 监视numbers属性
numbers:{
// 开启深度监视,numbers中的任意(深层)属性发生变化,都会调用回调函数
deep:true,
handler(){
console.log('numbers改变了')
}
},
// 不开启深度监视,但监视某一深层属性
'numbers.c.d': {
handler(){
console.log('numbers改变了')
}
}
}
})
</script>
注意:
Vue 中的 watch
默认不监视对象内部值的改变,默认监视的是对象地址值,也就是对象内部值发生改变但地址值仍然不会变,会认为这个对象没有发生改变,不会执行回调函数。如果想要监视内部值的变化,必须使用上述的深度监视。
当不需要使用 immediate
属性以及深度监视时可以采用简写形式,具体写法如下:
第一种方式:
<script type="text/javascript">
const vm = new Vue({
el:'#root',
watch:{
//正常写法
isHot:{
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
},
//简写1,就是写成函数形式
//直接当成handler来使用
isHot(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue,this)
},
}
//简写2,可直接调用已定义的函数
watch: {
//监视data属性,调用Vue中定义的function函数
data: 'function',
}
})
</script>
第二种方式:
<script type="text/javascript">
const vm = new Vue({
el:'#root'
})
//正常写法
vm.$watch('isHot',{
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
})
//简写
//参数2写一个函数,作用与handler一致
vm.$watch('isHot', function(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue,this)
})
</script>
总结:
watch 与 computed 对比:
watch 可以进行异步操作,computed 不可以进行异步操作,如下所示:
watch:{
firstName(val){
<!-- 当firstName属性值发生变化的时候,等待1秒再执行打印操作 -->
setTimeout(()=>{
console.log(val)
},1000);
}
}
函数写法的两个重要原则:
使用 class = "样式名"
可以给标签绑定样式,这个样式是固定的,绑定之后无法修改。
如果想要绑定的样式并不确定,想要随时修改,那么就需要使用 :class = "变量名"
了,在变量中定义要使用的 class
样式。
代码示例:
<head>
<meta charset="UTF-8" />
<title>绑定class样式</title>
<!-- 定义多个css样式 -->
<style>
.basic{
width: 400px;
height: 100px;
border: 1px solid black;
}
.happy{
border: 4px solid red;;
background-color: rgba(255, 255, 0, 0.644);
background: linear-gradient(30deg,yellow,pink,orange,yellow);
}
.sad{
border: 4px dashed rgb(2, 197, 2);
background-color: gray;
}
.normal{
background-color: skyblue;
}
</style>
<!-- 通过本地文件引入vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<div id="root">
<!-- 不使用任何样式 -->
<div>{{name}}</div> <br/><br/>
<!-- 使用基础的样式,绑定的是样式名 -->
<div class="basic">{{name}}</div> <br/><br/>
<!-- 使用可变化的样式以及基础的样式,点击后调用方法修改样式 -->
<!-- 绑定的是变量名而不是样式名,后期修改变量值,就可以修改样式 -->
<div class="basic" :class="mood" @click="changeMood">{{name}}</div>
</div>
</body>
<script type="text/javascript">
const vm = new Vue({
el:'#root',
data:{
name:'Jay',
// mood变量绑定的是样式名
mood:'normal'
},
methods: {
changeMood(){
// 随机的选择三种样式之一
const arr = ['happy','sad','normal']
const index = Math.floor(Math.random()*3)
//修改绑定样式的变量值
this.mood = arr[index]
}
},
})
</script>
上述代码完成的效果:
一定会使用基础的 basic
样式,但是另一个样式不确定,通过点击事件随机修改样式,如下图:
如果要绑定的是多个不确定(名字、个数都不确定)的样式,则可以使用数组写法。
代码示例:
<body>
<div id="root">
<!-- :class绑定一个数组 -->
<div class="basic" :class="classArr">{{name}}</div>
</div>
</body>
<script type="text/javascript">
const vm = new Vue({
el: '#root',
data: {
name: 'Jay',
// 数组中定义所有要使用的样式,前端展示所有样式的叠加效果
classArr:['happy','sad','normal']
}
})
</script>
后续只要修改数组中的元素值或个数就可以绑定多个不同的样式了。
如果要绑定的样式名称及个数确定,但是不确定哪个使用,则可以使用对象写法。
代码示例:
<body>
<div id="root">
<!-- :class绑定一个对象 -->
<div class="basic" :class="classObj">{{name}}</div>
</div>
</body>
<script type="text/javascript">
const vm = new Vue({
el: '#root',
data: {
name: 'Jay',
// 对象中定义要使用的所有样式
// 取值为true或false
classObj:{
happy:false,
sad:false
}
}
})
</script>
后续只要修改对象中的布尔值就可以决定采用哪个样式。
注意:
绑定 style
样式与上述方式类似,只不过是绑定 :style
属性。
3.1.1 用法:
v-if = "表达式"
v-else-if = "表达式"
v-else = "表达式"
当表达式为真时,元素显示。
代码示例:
<body>
<div id="root">
<!-- 写data中的变量 -->
<div v-if="temp">Angular1</div>
<!-- 写表达式 -->
<div v-if="1 == 1">Angular2</div>
<div v-if="1 == 2">Angular3</div>
<!-- 写布尔值 -->
<div v-if="true">Angular4</div>
</div>
</body>
<script type="text/javascript">
const vm = new Vue({
el:'#root',
data:{
temp:"true"
}
})
</script>
运行结果:
3.1.2 配合template使用
如果想要同时显示或隐藏多个元素,可以考虑使用 v-if
和 template
结合使用的方式。
<body>
<div id="root">
<!-- v-if与template的配合使用 -->
<!-- 想要同时显示或隐藏多个元素 -->
<template v-if="1 === 1">
<h4>你好</h4>
<h4>故宫</h4>
<h4>北京</h4>
</template>
</div>
</body>
运行结果:
用法:v-show = "表达式"
,表达式可写的内容与 v-if
一致,表达式为真时,元素显示。
代码示例:
<body>
<div id="root">
<div v-show="false">周杰伦</div>
</div>
</body>
运行结果:
注意:
v-if
时,不满足条件的元素会直接被删去v-show
时,不满足条件的元素没有被删,只是被隐藏v- if
隐藏元素后,元素可能无法再被获取到,而使用 v-show
将元素隐藏后,元素仍然可以被获取到v-if
适用于切换频率较低的场景,v-show
适用于切换频率较高的场景v-if
可以配合 template
使用,而 v-show
不可以作用:v-for
指令用来遍历数据,需要结合 key
属性一起使用
基本语法:v-for="(item,index) of 被遍历的内容"
或者 v-for="(item,index) in 被遍历的内容"
,其中 item
表示每次遍历的结果,index
表示遍历的索引值(从0开始,自动生成)
代码示例:
<div id="root">
<!-- 遍历数组 -->
<h2>人员列表(遍历数组)</h2>
<ul>
<!-- 要保证每一个被遍历的标签的 key 属性值不同 -->
<li v-for="(item,index) of persons" :key="index">
<!-- 另一种方式 :key="item.id",只要保证key属性值不同即可 -->
{{item.name}}-{{item.age}}
</li>
</ul>
<!-- 遍历对象 -->
<h2>汽车信息(遍历对象)</h2>
<ul>
<!-- 遍历对象时,key 和 value 的位置是反的 -->
<li v-for="(value,key) of car" :key="key">
{{key}}-{{value}}
</li>
</ul>
<!-- 遍历字符串 -->
<h2>测试遍历字符串</h2>
<ul>
<li v-for="(char,index) of str" :key="index">
{{char}}-{{index}}
</li>
</ul>
<!-- 遍历指定次数 -->
<!-- 遍历数字时,自动从 1 开始遍历 -->
<h2>测试遍历指定次数</h2>
<ul>
<li v-for="(number,index) of 5" :key="index">
{{index}}-{{number}}
</li>
</ul>
</div>
<script type="text/javascript">
new Vue({
el:'#root',
data:{
persons:[
{id:'001',name:'张三',age:18},
{id:'002',name:'李四',age:19},
{id:'003',name:'王五',age:20}
],
car:{
name:'奥迪A8',
price:'70万',
color:'黑色'
},
str:'hello'
}
})
</script>
运行结果1:
运行结果2:
注意:
v-for
key
属性值不同key
和 value
的位置是反的首先观察一种情况:
<div id="root">
<!-- 点击事件调用add方法 -->
<button @click.once="add">添加一个老刘</button>
<ul>
<!-- 使用索引作为属性key的值 -->
<li v-for="(p,index) of persons" :key="index">
<!-- 遍历的结果要增加一个输入框 -->
{{p.name}}-{{p.age}} <input type="text">
</li>
</ul>
</div>
<script type="text/javascript">
new Vue({
el:'#root',
data:{
persons:[
{id:'001',name:'张三',age:18},
{id:'002',name:'李四',age:19},
{id:'003',name:'王五',age:20}
]
},
methods: {
add(){
const p = {id:'004',name:'老刘',age:40}
// 添加到数组的最前方
this.persons.unshift(p)
}
},
})
</script>
运行结果:
key的原理:(配合下列图示理解)
key的原理图示如下:
1. 以索引作为key属性值:
2. 以自定义id作为key属性值:
注意:
介绍:
filter()
方法用来对数组进行过滤,这个方法会创建一个新的数组,新的数组元素是原数组中通过筛选后的元素。
示例:
//返回数组nums中所有大于5的元素
let nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
//res用来接收一个新数组
//num表示遍历原数组得到的每一个元素
let res = nums.filter((num) => {
//如果返回值为true,则该元素被保留
return num > 5;
});
console.log(res); // [6, 7, 8, 9, 10]
console.log(nums); //[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],原数组并未改变
总结:
filter()
方法中还需要定义一个函数,数组中的每个元素都会执行这个函数,函数的参数表示原数组的每一个元素,如果这个函数的返回值为 true,则该元素被保留。
首先需要明确任何字符串都包含空串,如下图:
列表过滤概念:
代码实现:
<div id="root">
<!-- 双向绑定keyWord属性 -->
<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">
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:[]
},
// 监视双向绑定的属性keyWord
watch:{
keyWord:{
// 保证开始时可以显示全部数据
immediate:true,
// val表示keyWord新值
handler(val){
this.filPerons = this.persons.filter((p)=>{
// 判断数组中的某项是否包含输入的新值
return p.name.indexOf(val) !== -1
})
}
}
}
})
</script>
注意:
如果监视属性中没有编写 immediate:true
,则一开始列表是空的,因为页面遍历的是经过过滤的数组,一开始这个数组是空的,所以列表为空。
加上 immediate:true
属性之后,初始化时就直接调用 handler
函数,参数 val 的值为空字符,由于任何字符串都包含空串,所以原数组的所有元素都会被保留。
<div id="root">
<input type="text" placeholder="请输入名字" v-model="keyWord">
<ul>
<li v-for="(p,index) of filPersons" :key="index">
{{p.name}}-{{p.age}}-{{p.sex}}
</li>
</ul>
</div>
<script type="text/javascript">
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:{
filPersons(){
// 第一个return表示filPerons此时的值
return this.persons.filter((p)=>{
// 第二个return表示filter函数内定义函数的返回值
return p.name.indexOf(this.keyWord) !== -1
})
}
}
})
</script>
filPerons
依赖 keyWord
,当 keyWord
发生变化,就会执行函数获取新值。
sort() 函数:
用于对数组排序,默认是按照编码顺序排序(修改的是原数组):
var arr=[102,103,506,403,89]
//默认按照编码顺序排序
//负数中,越小的数编码值越大
//根据数字第一个数字大小进行排序
//根据字符的字典顺序排序
console.log(arr.sort()); //102 103 403 506 89
//从小到大排序
//a或b表示数组中的某一项
arr.sort((a,b) => {
return a-b;
});
//从大到小排序
arr.sort((a,b) => {
return b-a;
});
列表排序概念:
代码实现:
<div id="root">
<h2>人员列表</h2>
<input type="text" placeholder="请输入名字" v-model="keyWord">
<button @click="sortType = 2">年龄升序</button>
<button @click="sortType = 1">年龄降序</button>
<button @click="sortType = 0">原顺序</button>
<li v-for="(p,index) of filPerons" :key="p.id">
{{p.name}}-{{p.age}}-{{p.sex}}
</li>
</div>
<script type="text/javascript">
new Vue({
el:'#root',
data:{
keyWord:'',
sortType:0, //0原顺序 1降序 2升序
persons:[
{id:'001',name:'马冬梅',age:30,sex:'女'},
{id:'002',name:'周冬雨',age:31,sex:'女'},
{id:'003',name:'周杰伦',age:18,sex:'男'},
{id:'004',name:'温兆伦',age:19,sex:'男'}
]
},
computed:{
filPerons(){
// 先过滤
const arr = this.persons.filter((p)=>{
return p.name.indexOf(this.keyWord) !== -1
})
// 后排序,排序在过滤的基础上
if(this.sortType){
arr.sort((p1,p2)=>{
return this.sortType === 1 ? p2.age-p1.age : p1.age-p2.age
})
}
// 过滤并排序后的结果作为filPerons此时的值
return arr
}
}
})
</script>