Day_03 Vue学习
1.计算属性
1.1 定义:
要用的属性不存在,要通过已有属性计算得来。
1.2.原理:
底层借助了Objcet.defineproperty方法提供的getter和setter。
<body>
<div id="root"> 姓:
<input type="text" v-model="firstName"><br/> 名:
<input type="text" v-model="lastName"><br/> 全名:
<!--这里的fullname是计算属性中的fullName函数中get返回值名称-->
<span>{{fullName}}</span><br/> 全名:
<span>{{fullName}}</span><br/> 全名:
<span>{{fullName}}</span><br/> 全名:
<span>{{fullName}}</span><br/> 全名:
<span>{{fullName}}</span>
</div>
<script>
const vm = new Vue({
el: '#root',
data: {
firstName: '张',
lastName: '三'
},
//计算属性中,vm会自己去找到这个函数的get属性,
//然后把返回值给到fullName,不用我们自己去调用get
computed: {
fullName: {
//get作用?
//当有人读取fullname时,get就会被调用,
//返回值就是fullName的值
get() {
//此处的this是vm,函数一定不写箭头函数
console.log('get被调用了');
return this.firstName + '-' + this.lastName;
},
//这个set不是必须的,什么时候调动,当fullName被修改的时候
set(value) {
console.log('set被调用了', value);
this.firstName = value.split('-')[0];
this.lastName = value.split('-')[1];
}
}
}
})
</script>
</body>
1.3.get函数什么时候执行?
- 初次读取时会执行一次。
- 当依赖的数据发生改变时会被再次调用。
1.4.优势:
与methods实现相比,内部有缓存机制,效率更高,调试方便。
<body>
<div id="root"> 姓:
<input type="text" v-model="firstName"><br/> 名:
<input type="text" v-model="lastName"><br/> 全名:
<!-- 当函数用作指令去调用的时候括号就是可写可不写的
但是要是用作模板方法去取值的话,那就必须写括号了,这样才能得到返回值
-->
<span>{{fullName()}}</span><br/> 全名:
<span>{{fullName()}}</span><br/> 全名:
<span>{{fullName()}}</span><br/> 全名:
<span>{{fullName()}}</span><br/> 全名:
<span>{{fullName()}}</span>
<!-- 只要data中的值发生变化那么vue一定会去重新解析模板 -->
</div>
<script>
new Vue({
el: '#root',
data: {
firstName: '张',
lastName: '三'
},
methods: {
// 这个里面没有任何缓存而言调用几次方法,这个方法就执行几次
fullName() {
console.log('函数被调用了')
return this.firstName + '-' + this.lastName;
}
}
})
</script>
</body>
注意事项
- 计算属性最终会出现在vm上,直接读取使用即可。
- 如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生变化
1.5计算属性的简写形式
<body>
<div id="root"> 姓:
<input type="text" v-model="firstName"><br/> 名:
<input type="text" v-model="lastName"><br/> 全名:
<span>{{fullName}}</span><br/> 全名:
<span>{{fullName}}</span><br/> 全名:
<span>{{fullName}}</span><br/> 全名:
<span>{{fullName}}</span><br/> 全名:
<span>{{fullName}}</span>
</div>
<script>
const vm = new Vue({
el: '#root',
data: {
firstName: '张',
lastName: '三'
},
computed: {
//完整写法
// fullName: {
// get() {
// console.log('get被调用了');
// return this.firstName + '-' + this.lastName;
// },
// set(value) {
// console.log('set被调用了', value);
// this.firstName = value.split('-')[0];
// this.lastName = value.split('-')[1];
// }
// }
//简写形式,只有考虑读取,不考虑修改的前提下才能简写
fullName() {
console.log('get被调用了');
return this.firstName + '-' + this.lastName;
}
}
})
</script>
</body>
注意事项
- 在用插值语法的时候一定要看清楚所取得的数据在哪里
- data中的直接拿
- 指令中的函数,可以加括号或不加括号,那就代表调用函数的时候传不传参数
- 计算属性中的函数,一定不带括号,因为vue实例会自动去调用函数生成返回值,我们直接写函数名就可以取到值
2.监视属性:
2.1 监视属性watch
-
当被监视的属性变化时,回调函数自动调用,进行相关操作
-
监视的属性必须存在,才能进行监视!!
记算属性不存在也不报错,只是新旧值都是undefined
-
监视的两种写法:
(1).new Vue时传入watch配置
(2).通过vm.$watch监视
<body>
<div id="root">
<h2>今天天气很{{info}}</h2>
<button @click='changeWeather'>切换天气</button>
</div>
</body>
<script>
const vm = new Vue({
el: '#root',
data: {
isHot: true
},
//计算属性
computed: {
info() {
return this.isHot ? '炎热' : '凉爽';
}
},
methods: {
changeWeather() {
this.isHot = !this.isHot;
}
},
//配置监视第一种方式
// watch: {
// isHot: {
// //什么时候调用呢,当ishot发生改变时
// handler(newValue, oldValue) {
// console.log('ishot修改了', newValue, oldValue)
// },
// //默认是false,初始化时handler调用一下
// immediate: true
// },
//监视info和isHot都是一样的
// info: {
// handler(newValue, oldValue) {
// console.log('info修改了', newValue, oldValue)
// },
// }
// }
})
//配置监视第二种方式
vm.$watch('isHot', {
handler(newValue, oldValue) {
console.log('ishot修改了', newValue, oldValue)
}
})
</script>
2.2深度监视:
- Vue中的watch默认不监测对象内部值的改变(一层)。
- 配置deep:true可以监测对象内部值改变(多层)。
<body>
<div id="root">
<h2>今天天气很{{info}}</h2>
<button @click='changeWeather'>切换天气</button>
<hr>
<h3>a的值是:{{numbers.a}}</h3>
<button @click="numbers.a++">点我a+1</button>
<h3>b的值是:{{numbers.b}}</h3>
<button @click="numbers.b++">点我b+1</button>
</div>
</body>
<script>
const vm = new Vue({
el: '#root',
data: {
isHot: true,
numbers: {
a: 1,
b: 1
}
},
computed: {
info() {
return this.isHot ? '炎热' : '凉爽';
}
},
methods: {
changeWeather() {
this.isHot = !this.isHot;
}
},
//配置监视
watch: {
isHot: {
handler(newValue, oldValue) {
console.log('ishot修改了', newValue, oldValue)
}
},
//监视多级结构中某个属性的变化
// 'numbers.a': {
// handler() {
// console.log('a被改变了')
// }
// }
//监视多级结构中所有的属性的变化
numbers: {
deep: true,//深度监测
handler() {
console.log('numbers被改变了')
}
}
}
})
</script>
注意事项:
(1).Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以!
(2).使用watchI时根据数据的具体结构,决定是否采用深度监视。
2.3监视属性的简写
<body>
<div id="root">
<h2>今天天气很{{info}}</h2>
<button @click='changeWeather'>切换天气</button>
</div>
</body>
<script>
const vm = new Vue({
el: '#root',
data: {
isHot: true
},
computed: {
info() {
return this.isHot ? '炎热' : '凉爽';
}
},
methods: {
changeWeather() {
this.isHot = !this.isHot;
}
},
watch: {
// 完整写法
// isHot: {
// // immediate: true, //初始化时让hander调用一下
// // deep: true, //深度监视
// handler(newValue, oldValue) {
// console.log('ishot修改了', newValue, oldValue)
// },
// },
//简写,只有当配置项只有handler的时候才能用
isHot(newValue, oldValue) {
console.log('ishot修改了', newValue, oldValue);
}
}
})
// //完整写法
// vm.$watch('isHot', {
// immediate: true, //初始化时让hander调用一下
// deep: true, //深度监视
// handler(newValue, oldValue) {
// console.log('ishot修改了', newValue, oldValue)
// },
// })
//简写
// vm.$watch('isHot', function(newValue, oldValue) {
// console.log('ishot修改了', newValue, oldValue)
// })
</script>
注意事项:
所有vue管理的函数都要写成普通函数,否则vue中的this就是window了
2.4计算属性和监听属性比较
<!--姓名案例_computed实现:-->
<body>
<div id="root"> 姓:
<input type="text" v-model="firstName"><br/> 名:
<input type="text" v-model="lastName"><br/> 全名:
<span>{{fullName}}</span>
<script>
const vm = new Vue({
el: '#root',
data: {
firstName: '张',
lastName: '三'
},
computed: {
fullName() {
console.log('get被调用了');
return this.firstName + '-' + this.lastName;
}
}
})
</script>
</body>
<!--姓名案例_watch实现:-->
<body>
<div id="root"> 姓:
<input type="text" v-model="firstName"><br/> 名:
<input type="text" v-model="lastName"><br/> 全名:
<span>{{fullName}}</span>
</div>
<script>
const vm = new Vue({
el: '#root',
data: {
firstName: '张',
lastName: '三',
fullName: '张-三'
},
//可以开启一个异步任务
watch: {
firstName(val) {
setTimeout(() => {
this.fullName = val + '-' + this.lastName
}, 1000)
},
lastName(val) {
this.fullName = this.firstName + '-' + val
}
}
})
</script>
</body>
注意事项:
这个时候很明显计算属性比监测属性好用的多
需求:如果想当姓改变之后,全名1秒之后才改变
//计算属性只能这样写,那问题是:
//1.这样的话计算属性就没有返回值了,所以fullName就没有值啦
//2.这里的return相当于是箭头函数的返回值了
fullName() {
console.log('get被调用了');
setTimeout(() => {
return this.firstName + '-' + this.lastName;
}, 1000)
}
//可以开启一个异步任务
watch: {
firstName(val) {
//vue里面的只要是vue不监管的函数一定要写成箭头函数
//定时器的回调是js引擎帮我们调用的所以这里的this就是window
setTimeout(() => {
this.fullName = val + '-' + this.lastName
}, 1000)
},
lastName(val) {
this.fullName = this.firstName + '-' + val
}
}
那这样的话监视属性就比计算属性好用
computed和watch之间的区别:
computed能完成的功能,watch都可以完成。
watch能完成的功能,computed不一定能完成,
例如:watch可以进行异步操作。
两个重要的小原则:
- 所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象。
- 所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等),最好写成箭头函数。
- 这样this的指向才是vm 或 组件实例对象。
3 绑定样式
<body>
<!-- 绑定class样式,--字符串写法,
适用于:样式的类名不确定需要动态指定
-->
<div id="root">
<div class="basic" :class='mood' @click='changeMood'>
{{name}}</div>
<hr>
<!-- 绑定class样式,--数组写法,
适用于:要绑定的样式个数不确定,样式不确定
-->
<div class="basic" :class='arr'>{{name}}</div>
<hr>
<!-- 绑定class样式,--对象写法,
适用于:要绑定的样式个数确定,名字确定 ,要动态决定用不用
-->
<div class="basic" :class='classObj'>{{name}}</div>
<hr>
<!-- 内联绑定样式 -->
<div class="basic" :style="styleObj">{{name}}</div>
<hr>
<!-- 内联绑定数组对象 -->
<div class="basic" :style="[styleObj,styleObj2]">{{name}}
</div>
<hr>
<!-- 内联绑定数组对象2 -->
<div class="basic" :style="styleArr">{{name}}</div>
</div>
</body>
<script>
const vm = new Vue({
el: '#root',
data: {
name: '尚硅谷',
mood: 'normal',
arr: ['atguigu1', 'atguigu2', 'atguigu3'],
classObj: {
atguigu1: false,
atguigu2: false
},
styleObj: {
// 这里的key不能瞎写,就是css属性的小驼峰
fontSize: '40px'
},
styleObj2: {
color: 'red'
},
styleArr: [{
// 这里的key不能瞎写,就是css属性的小驼峰
fontSize: '40px'
}, {
// 没必要这样写,虽然也可以实现
// methods: {
// changeMood() {
// const arr = ['happy', 'sad', 'normal'];
// const index = Math.floor(Math.random() * 3);
// this.mood = arr[index];
// }
// }, this.mood = arr[index];
}
},
})
</script>
绑定样式:
1.class样式
写法:class=“xxx” xxx可以是字符串、对象、数组。
字符串写法适用于:类名不确定,要动态获取。
对象写法适用于:要绑定多个样式,个数不确定,名字也不确定。
数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。
2.style样式
:style="{fontSize:xxx}“其中xxx是动态值。
:style=”[a,b]"其中a、b是样式对象。
3.条件渲染
3.1v-if 写法:
(1).v-if=“表达式”
(2).v-else-if=“表达式”
(3).v-else=“表达式” 适用于:切换频率较低的场景。
<body>
<div id='root'>
<h2>当前的n值是{{n}}</h2>
<button @click='n++'>点我n+1</button>
<!-- 使用v-show做条件渲染,如果东西变化的频率高,那就用-->
<h2 v-show="false"> 欢迎来到{{name}}</h2>
<h2 v-show="1===3"> 欢迎来到{{name}}</h2>
<!--使用v-if做条件渲染,元素直接会不见了,频率低的用 -->
<h2 v-if="false"> 欢迎来到{{name}}</h2>
<h2 v-if="1==1"> 欢迎来到{{name}}</h2>
<div v-if="n===1">Angular</div>
<div v-else-if="n===1">你管我</div>
<div v-if="n===2">React</div>
<div v-if="n===3">Vue</div>
<div v-else>哈哈哈</div>
<!-- template只能配合v-if,不能配合v-show -->
<template v-if='n===1'>
<h2>你好</h2>
<h2>尚硅谷</h2>
<h2>北京</h2>
</template>
</div>
</body>
<script>
const vm = new Vue({
el: '#root',
data: {
name: '尚硅谷',
// a: false,
n: 1
}
})
</script>
特点:不展示的DOM元素直接被移除。
注意:v-if可以和:v-else-if、v-else一起使用,但要求结构不能断掉
3.2.v-show 写法:
(1)v-show=“表达式” 适用于:切换频率较高的场景。
特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉
备注:使用v-if的时,元素可能无法获取到,而使用v-show一定可以获取到。
<body>
<div id='root'>
<h2>当前的n值是{{n}}</h2>
<button @click='n++'>点我n+1</button>
<!-- 使用v-show做条件渲染,如果东西变化的频率高,那就用-->
<h2 v-show="false"> 欢迎来到{{name}}</h2>
<h2 v-show="1===3"> 欢迎来到{{name}}</h2>
</div>
</body>
<script>
const vm = new Vue({
el: '#root',
data: {
name: '尚硅谷',
// a: false,
n: 1
}
})
</script>
</html>