动态class
目标
用v-bind给标签class设置动态的值
语法
● 格式1:<标签 :class="变量" />
● 格式2:<标签 :class="{类名1: 布尔值, 类名2: 布尔值}" />
○ 如果布尔值为true,就添加对应的类名
说明:可以和静态class共存
<style>
#app{width:500px;margin:50px auto;border:3px solid red;}
.box{
border:3px solid black;
margin:5px;
}
.bg-blue{
background-color: blue;
}
.bg-green{
background-color: green;
}
.fs20{font-size:20px;}
.tr{text-align: right;}
</style>
</head>
<body>
<div id="app">
<h3 class="title">v-bind-绑定class</h3>
<!-- 元素自有class和v-bind绑定的class会协同工作,一起生效 -->
<div class="box" v-bind:class="cla ? 'bg-blue': 'bg-green'">
1. 三元表达式
</div>
<!-- 如果对象中的属性值是true,
则把对象中的属性名添加到类名中 -->
<div class="box" :class="claObj">
2. 绑定对象
</div>
<!-- 数组中元素是字符串,
它会把所有的元素全添加到class中 -->
<div class="box" :class="claArr">
3. 绑定数组
</div>
<button @click="hAddClass">补充一个class</button>
</div>
<script>
// v-bind 是用来动态绑定元素的属性,而class也是元素的属性
// 目标: 可以通过动绑定class来控制样式 。
// 方式:
// 1. 三元表达式
// 2. 绑定对象
// 3. 绑定数组
const vm = new Vue({
el: "#app",
// el: document.getElementById("app"),
data: {
cla: false,
claObj: {
fs20: true,
tr: true
},
claArr:['fs20','tr', 'abc']
},
methods: {
hAddClass () {
// 向数组中添加一个类 'c-red'
this.claArr.push('c-red')
}
}
})
</script>
小结
就是把类名保存在vue变量中赋予给标签
动态style
目标
给标签动态设置style的值
语法
<标签 :style="{css属性名: 值}" />
1. 可以和静态style共存
2. 样式中带-属性写成小驼峰
<div id="app">
<h3 class="title">v-bind-绑定style</h3>
<!-- 把对象的属性名和属性值直接设置到style中 -->
<div class="box" :style="styleObj">
1. 绑定对象
</div>
<!-- 把数组中的每一个元素(对象),取出来,组成style -->
<div class="box" :style="styleArr">
2. 绑定数组
</div>
<button @click="hBlack">改成黑色的字</button>
</div>
<script>
// v-bind 是用来动态绑定元素的属性,而style也是元素的属性
// 目标: 可以通过动绑定style来控制样式 。
// 方式:
// 1. 绑定对象
// 2. 绑定数组
const vm = new Vue({
el: "#app",
// el: document.getElementById("app"),
data: {
styleObj: {
color:'red',
// 如果属性名有-,则要加''
'background-color':'blue'
},
// 数组中的每一项都是一个对象,其中以键值对的格式设置了style
styleArr:[ {color:'red','font-weight':'bold'}, {'font-size':'50px'} ]
},
methods: {
hBlack () {
// 直接把styleObj中的color设置成black
this.styleObj.color = "black"
}
}
})
</script>
<h1 :class="[active , 'active2' , active === 'activeName' ? 'active3' : '' , {'active4' : true}]">class+style === arr</h1>
<h1 :class="{'active4' : true , 'active5' : active === 'activeName' }">class+style === obj</h1>
<h1 :style="{'color' : 'red' , background : bg }">class+style === obj</h1>
计算属性
使用场景
从已有的数据A中计算等到的新的数据B,使用计算属性。
如果一个结果需要依赖data中的数据,但是需要经过一些逻辑处理,才能得到你想要的数据。此时就可以使用计算属性。
例如:要对给定的字符串做翻转处理之后再来显示
<div id="app">
<!-- 此处逻辑复杂 -->
<h3>{{msg.split('').reverse().join('')}}</h3>
</div>
<script src="./vue.js"></script>
<script>
export default {
data(){
return {
msg: 'javascript'
}
}
}
</script>
computed 是vue的配置选项,它的值是一个对象,其中可定义多个计算属性,每个计算属性就是一个函数。
● 属性名称: 计算属性的名称
● 属性的值:计算属性的素材函数
○ 对需要依赖的数据,进行逻辑上的处理
○ 处理完毕后,需要return出去,返回的值就是计算属性的值
使用格式
使用格式
在两个地方使用:
● 模板
○ 用插值表达式 {{计算属性名}}
○ 用其它指令
● 在实例内
○ this.计算属性名
示例:颠倒字符串
<div id="app">
<!-- 逻辑复杂 -->
<h3>{{msg.split('').reverse().join('')}}</h3>
<!-- 计算属性 和data类似-->
<h3>{{reverseMsg}}</h3>
</div>
<script src="./vue.js"></script>
<script>
{
data () {
return { msg: 'hi vue' }
},
// 声明计算属性
computed: {
//属性名字(计算属性名称)
//属性的值(计算属性处理函数)
reverseMsg () {
// 对依赖的数据进行处理,且进行return
return this.msg.split('').reverse().join('')
}
}
})
</script>
在模板中使用计算属性,和使用data的方式是一样的。
○ 虽然在计算属性中声明的是函数,但是在模板中使用,当中数据来使用,不需要加括号。
小结
● 什么时间用:需要对数据进行复杂的逻辑加工,产生新的数据时。
● 定义: 就是一个特殊的配置项computed。其中有多个函数。
● 使用:计算属性的使用方式与data中的数据项一致;
○ 计算属性-计算:这个值是对原数据进行计算之后得到的新的数据
○ 计算属性-属性:它的使用方法与原数据一样。this.计算属性名,{{计算属性名}}
● 执行的时机: 如果计算属性中依赖的数据项变化时,它会自动调用。
computed有缓存
问:
当我们在模板中来显示一份经过对数据项进行复杂计算之后的结果时,我们有两种解决方案:
● 计算属性
● 函数
应该如何选择?
答:
● methods定义函数,如果在模板中使用,每使用一次,就相当于调用了一次,处理逻辑会重新执行。
● computed定义计算属性,如果在模板中使用,使用多次,但是如果依赖的数据不发生改变,计算属性对应的函数不会重新执行。
○ 计算属性会做缓存,提高渲染的性能。
<div id="app">
<h3>学习计算属性</h3>
<p>计算属性:{{ reversedMsg }}</p>
<p>计算属性:{{ reversedMsg }}</p>
<p>计算属性:{{ reversedMsg }}</p>
<hr>
<p>函数:{{fReversedMsg()}}</p>
<p>函数:{{fReversedMsg()}}</p>
<p>函数:{{fReversedMsg()}}</p>
</div>
<script>
// 计算属性的特点:缓存
// - 如果计算属性所依赖的数据项并没有发生变化,则就算使用多个计算函数,其函数也只执行一次
// 因为它把结果缓存起来了。
{
data() {
return { msg: 'javascript' }
},
methods: {
updateMsg () {
this.msg = "abc"
// 由于计算属性有缓存,虽然在页面上用到三次,但它的函数体只执行一次。
// 对于普通的函数,在页面上用到了三次,它就会执行三次
},
fReversedMsg () {
console.log( '函数 fReversedMsg' )
//把msg的翻转一下
let newMsg = this.msg.split('').reverse().join('')
return newMsg
}
},
computed: {
reversedMsg () {
console.log( 'reversedMsg' )
//把msg的翻转一下
let newMsg = this.msg.split('').reverse().join('')
return newMsg
}
}
})
</script>
小结
● 计算属性有缓存,提高渲染性能。
● 如果在页面上需要用到 对现有的数据进行加工得到新数据,则时要使用计算属性
计算属性-完整写法
目标
计算属性也是变量, 如果想要直接赋值, 需要使用完整写法=>开启读写模式
语法
computed: {
"属性名": {
set(值){
},
get() {
return "值"
}
}
}
需求
计算属性给v-model使用
页面准备输入框
<template>
<div>
<div>
<span>名字:</span>
<input type="text" v-model="full">
</div>
</div>
</template>
<script>
export default {
data () {
return {
msg: 'full'
}
},
computed: {
full: {
get(){ // 获取full的值
console.log("get方法触发");
return this.msg
},
set(val){ // 要给full赋值
console.log(val)
this.msg = val
}
}
}
}
</script>
小结
想要给计算属性赋值, 需要使用set方法
过滤器
作用
过滤器的作用:转换格式, 把数据在显示之前做格式转换
格式
定义的格式
{
data(){},
computed:{},
methods:{},
// 定义过滤器
filters: {
// 属性名称(过滤器名称):属性的值(过滤器处理函数)
myFilter:function(value,其它参数){
return 过滤后的结果
}
}
}
使用的格式
// 不带参数
{{ msg | 过滤器}}
// 带参数
{{ msg | 过滤器(参数)}}
示例:带参数的过滤器
把时间戳转成年-月-日格式
filters: {
// 过滤器的定义
// 属性名称(过滤器名称):属性的值(过滤器处理函数)
// myFilter: function(value,其它参数) {
// }
fFormatDate: function (val) {
console.log('val', val)
// val 就是需要被过滤器处理的值
// return '你被过滤了' + val
const dt = new Date(val)
return dt.getFullYear() + '-' + (dt.getMonth()+1) + '-' + dt.getDate()
}
}
调用:
日期:{{ timeStamp | fFormatDate}},
注意:
● 它的工作过程就是函数的调用执行过程。
● 过滤器本质是一个函数:它的接收的参数是格式化之前的数据及格式化的参数,它的返回值是格式化之间的值
小结
过滤器使用场景: 对于拿到的数据在显示到页面的过程中,如果发现格式不是我们想要的,可以通过过滤器去转下格式。它一定需要入参,入参表示要转格式的数据。
计算属性:对于拿到的数据进行加工,以得到新的数据项。它不需要入参,因为它需要的数据在函数内部都可以通过this.XXX来获取到。
在vue3中已经不再支持过滤器了!
vue监听器-基本使用
作用
侦听器/监听器
可以监听数据(data/computed等)的值的改变。 数据的值有类型:基本数据类型,引用数据类型
语法
data(){},
computed:{},
methods:{},
filters:{},
watch: {
"被监听的属性名" (newVal, oldVal){
}
}
<template>
<div>
<input type="text" v-model="name">
</div>
</template>
<script>
export default {
data(){
return {
name: ""
}
},
watch: {
name (newVal, oldVal){ // 当msg变量的值改变触发此函数
console.log(newVal, oldVal);
}
}
}
</script>
<style>
</style>
小结
想要监听一个属性变化, 可使用监听属性watch
监听属性-深度监听和立即执行
目标
监听复杂类型, 或者立即执行监听函数
语法
watch: {
"要监听的属性名": {
immediate: true, // 立即执行
deep: true, // 深度监听复杂类型内变化
handler (newVal, oldVal) {
}
}
}
<template>
<div>
<input type="text" v-model="user.name">
<input type="text" v-model="user.age">
</div>
</template>
<script>
export default {
data(){
return {
user: {
name: "小白",
age: 18
}
}
},
watch: { // 固定属性(设置监听哪些属性)
user: { // 具体属性名(被监听)
handler(newVal, oldVal){ // 固定触发此函数
console.log(newVal);
},
immediate: true, // 马上监听触发
deep: true // 深度监听(监听name和age值的改变)
}
}
}
</script>
小结
immediate立即监听, deep深度监听, handler固定方法触发
案例-品牌管理(数据缓存)
目标
监听list变化, 同步到浏览器本地
需求
- 品牌数据缓存到本地=> 新增和修改价格都支持保存到本地
- 刷新后可以从本地读取渲染,上次缓存数据
<script>
export default {
data() {
return {
name: "", // 名称
price: 0, // 价格
+ list: JSON.parse(localStorage.getItem('data')) || []
};
},
methods: {
hDel(index) {
// 删除数组中指定位置的元素
this.list.splice(index, 1);
},
hAdd() {
// 收集用户的输入信息
// 简单判空
if (this.name.length == 0 || this.price.length == 0 || this.price < 0) {
alert("请写入正确的名字和价格");
return; // 阻止代码继续向下执行-返回出去这个函数
}
let id = this.list.length > 0 ? this.list[this.list.length - 1].id + 1 : 100
this.list.push({
id,
name: this.name,
price: this.price,
time: new Date()
});
},
},
+ watch: {
+ list: {
handler(newArr){
+ localStorage.setItem('data', JSON.stringify(newArr))
},
deep: true
}
+ }
};
</script>
总结
- v-for能监测到哪些数组方法变化, 更新页面(响应式)=》
- 调用数组方法(push、splice可以修改原数组,就可以触发刷新)
- 数组下标修改列表的值(不会触发响应式)=>解=》this.$set(数组, 数组的索引, 数组修改的值)
- key的作用是什么 =》给v-for遍历的元素标记唯一值
- 虚拟dom和diff算法作用 =》修改了变量=》会生成一份最新的虚拟DOM=》通过diff算法和上一次虚拟DOM=》找不同=》只更新变化部分
- 动态设置class或style=》通过data变量动态控制样式
- vue过滤器作用和分类 =》作用:格式化data中定义的变量数据=》不影响原变量的值
- vue计算属性作用=》新的变量的定义方式=》用法和data中定义的变量一样 =>{{计算属性函数名}}
- vue监听器的作用