目录
【前文回顾】👉 vue双向数据绑定的原理解析及代码实现_04
⬛ 绑定样式
1. 绑定内联样式
(1). 不好的做法: 将style属性看做一个普通的字符串属性进行绑定。
a. <元素 :style="变量">
data:{
变量: "css属性:值; css属性:值;..."
}
b. 问题: 极其不便于只操作其中某一个css属性
(2). 好的办法: 将style看做一个对象来绑定。每个css属性都是对象中的一个属性。
结果: "css属性1:属性值1; css属性2:属性值2;..."
↑ ↑ ↑ ↑
a. <元素 :style="{ css属性1: 变量1, css属性2: 变量2, ... }"
data:{
变量1:"属性值1",
变量2:"属性值2",
... ...
}
b. 优点: 轻易只修改其中某一个css属性值,而不影响其他属性值
c. 问题: 如果多个css属性的变量零散的保存在data中,如果多个元素都需要控制内联样式,就极容易发生冲突。
d. 示例: 控制一个飞机的飞行
1_style.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
<style>
img{
position:fixed;
left:50%;
}
</style>
</head>
<body>
<div id="app">
<!-- 属性名 变量-->
<!-- 不能自定义 可自定义-->
<!-- <img :style="{marginLeft:marginLeft,bottom:bottom}" src="img/p3.png"> -->
<img :style="{marginLeft,bottom}" src="img/p3.png">
</div>
<script>
var vm=new Vue({
el:"#app",
data:{
marginLeft:"-100px", //必须带单位
bottom:"50px"
}
})
</script>
</body>
</html>
运行结果:
(3). 更好的解决办法: 将每个元素所需的所有内联样式变量,集中保存在data中的一个对象里。
a. <元素1 :style="变量名1">
<元素2 :style="变量名2">
data:{
变量名1:{
css属性:值,
... : ...
},
变量名2:{
css属性:值,
... : ...
}
b. 优点: 避免不同元素间相同css属性的冲突
c. 示例: 控制两个飞机的飞行
1_style2.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
<style>
img{
position:fixed;
}
</style>
</head>
<body>
<div id="app">
<img style="left:50%" :style="img1Style" src="img/p3.png">
<img style="left:50%" :style="img2Style" src="img/p5.png">
</div>
<script>
var vm=new Vue({
el:"#app",
data:{
img1Style:{
marginLeft:"-200px",
bottom:"25px",
},
img2Style:{
marginLeft:"100px",
bottom:"100px"
}
}
})
</script>
</body>
</html>
运行结果:
(4). 问题: 如果元素上有些内联css属性是固定不变的,而有些css属性是可能发生变化的?
(5). 解决: 其实在一个元素上写死的固定不变的style和动态变化的:style是可以并存的。最后运行的结果是,:style动态生成的css属性会和style中固定不变的属性合并为最终应用到元素上的style属性。
结果: style="固定不变的css属性:值; 变化的css属性: 值; ..."
↑ ↑
<元素 style="固定不变的css属性:值" :style="变量"
data:{
变量:{
变化的css属性: 值
}
}
比如: <img style="left:50%" :style="img1Style" src="img/p3.png">
data:{
img1Style:{
marginLeft:"-200px",
bottom:"25px",
}
}
(6). 问题: DOM中经常批量修改一个元素的多个css属性,如果单个修改每个css属性值,代码会很繁琐
(7). 解决: 用class来代替单独修改每个css属性。
2. 绑定class
(1). 不好的方法: 将整个class字符串,看做一个普通的字符串属性绑定.
<元素 :class="变量">
data:{
变量: "class1 class2 ..."
}
缺点: 极其不便于修改其中某一个class
(2). 好的方法: 将class看做一个对象来绑定。
a. <元素 :class="{ class1: 变量1, class2: 变量2, ... }"
data:{
变量1: true或false,
变量2: true或false,
... : ...
}
说明: 当一个class对应的变量值是true,则这个class会出现在编译后的元素上,起作用;当一个class对应的变量值为false,则这个class不会出现在编译后的元素上,不起作用!
b. 优点: 极其便于修改其中某一个class
c. 示例: 验证手机号
2_class.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
<style>
.span-cls{
padding:5px 10px;
}
.success{
background-color:lightGreen;
border:green;
color:green;
}
.fail{
background-color:pink;
border:red;
color:red;
}
</style>
</head>
<body>
<!--1. 做界面
1.1 找界面中可能发生变化的位置
本例中:
文本框会被用户主动修改,新值要自动更新到程序中,所以文本框用v-model绑定
span的样式可能发生变化,在success和fail两种class之间来回切换
span的内容可能发生变化
1.2 找界面中触发事件的元素
本例中: 文本框失去焦点时自动触发验证-->
<div id="app">
手机号:<input v-model="phone" @blur="vali">
<!-- 属性名和属性值相同,可以简写 -->
<!-- <span class="span-cls" :class="{ success:success, fail:fail }">{{msg}}</span> -->
<span class="span-cls" :class="{ success, fail }">{{msg}}</span>
</div>
<script>
//2. 创建new Vue()对象
var vm=new Vue({
el:"#app",
//3. 创建模型对象
//因为界面中共需要4个变量,所以:
data:{
phone:"",
success:false,
fail:false,
msg:""
},
//因为界面中需要一个事件处理函数
methods:{
vali(){
//定义验证手机号的正则表达式:
var reg=/^1[3-9]\d{9}$/;
//用正则验证手机号正确
if(reg.test(this.phone)==true){
//就修改span为验证通过的样子
this.success=true;
this.fail=false;
this.msg=" √ 手机号格式正确";
}else{//否则如果验证失败
//就修改span为验证失败的样式
this.success=false;
this.fail=true;
this.msg=" × 手机号格式不正确"
}
}
}
})
</script>
</body>
</html>
运行结果:
d. 问题: 如果多个元素都需要用同一个class,但是启用和禁用的状态各不相同,如果将变量直接保存在data中,极容易发生冲突
(3). 更好的方法: 将一个元素的多个class包裹在一个对象变量中:
a. <元素1 :class=变量1">
<元素2 :class=变量2">
data:{
变量1:{
class名: true或false,
... : ...
},
变量2:{
class名: true或false,
... : ...
}
}
b. 优点: 即使多个元素,共用同一个class,也不会发生冲突!
c. 示例: 验证手机号和身份证号
2_class3.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="js/vue.js"></script>
<style>
.span-cls {
padding: 5px 10px;
}
.success {
background-color: lightGreen;
border: green;
color: green;
}
.fail {
background-color: pink;
border: red;
color: red;
}
</style>
</head>
<body>
<!--1. 做界面
1.1 找界面中可能发生变化的位置
本例中:
文本框会被用户主动修改,新值要自动更新到程序中,所以文本框用v-model绑定
span的样式可能发生变化,在success和fail两种class之间来回切换
span的内容可能发生变化
1.2 找界面中触发事件的元素
本例中: 文本框失去焦点时自动触发验证-->
<div id="app">
手机号:<input v-model="phone" @blur="valiPhone" />
<span class="span-cls" :class="phoneSpan">{{phoneMsg}}</span><br />
身份证号:<input v-model="pid" @blur="valiPid" />
<span class="span-cls" :class="pidSpan">{{pidMsg}}</span>
</div>
<script>
//2. 创建new Vue()对象
var vm = new Vue({
el: "#app",
//3. 创建模型对象
//因为界面中共需要4个变量,所以:
data: {
phone: "", //接文本框中的值
pid: "", //接文本框中的值
phoneSpan: {
//控制手机号验证结果的样式
success: false,
fail: false,
},
pidSpan: {
//控制身份证号验证结果的样式
success: false,
fail: false,
},
phoneMsg: "", //保存手机号的错误提示
pidMsg: "", //保存身份证号的错误提示
},
//因为界面中需要一个事件处理函数
methods: {
valiPhone() {
//定义验证手机号的正则表达式:
var reg = /^1[3-9]\d{9}$/;
//用正则验证手机号正确
// 复习小程序中js高级第2天
if (reg.test(this.phone) == true) {
//就修改span为验证通过的样子
this.phoneSpan = {
success: true,
fail: false,
};
this.phoneMsg = " √ 手机号格式正确";
} else {
//否则如果验证失败
//就修改span为验证失败的样式
this.phoneSpan = {
success: false,
fail: true,
};
this.phoneMsg = " × 手机号格式不正确";
}
},
valiPid() {
//定义验证身份证号的正则表达式:
var reg = /^\d{15}(\d\d[0-9x])$/i;
//用正则验证身份证号正确
// 复习小程序中js高级第2天
if (reg.test(this.pid) == true) {
//就修改span为验证通过的样子
this.pidSpan = {
success: true,
fail: false,
};
this.pidMsg = " √ 身份证号格式正确";
} else {
//否则如果验证失败
//就修改span为验证失败的样式
this.pidSpan = {
success: false,
fail: true,
};
this.pidMsg = " × 身份证号格式不正确";
}
},
},
});
</script>
</body>
</html>
运行结果:
(4). 问题: 如果元素上有些class是固定不变的,而有些class是可能发生变化的?
(5). 解决: 其实在一个元素上写死的固定不变的class和动态变化的:class是可以并存的。最后运行的结果是,:class动态生成的class字符串会和class中固定不变的class字符串合并为最终应用到元素上的class属性。
❣️ 巩固总结:样式绑定——动态绑定元素的class
我们可以通过数组和对象的两种形式绑定元素的 Class。
💦 对象语法形式 💦
在巩固总结上面的文章篇幅里,讲解的便是绑定元素的class的对象语法,在这里我们重新再回顾一下。
1️⃣ 对象语法
通过传给 v-bind:class
一个对象,以动态地切换 class:
<div v-bind:class="{ show: isShow }"></div>
代码解释: 上面的语法表示 show
这个 class 存在与否将取决于数据属性 isShow
是否为真值。
实例演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<style>
.hide {
display: none;
}
</style>
<body>
<div id="app">
<div v-bind:class="{hide: isHide}">Hello !</div>
</div>
</body>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
isHide: true
},
})
//vm.isHide = true
</script>
</html>
代码解释: HTML 代码第 2 行,我们给 div 绑定样式,当 isHide 为真值时, 其渲染结果为 <div class="hide"></div>
,否则 <div></div>
。 打开控制台,修改 vm.isHide 的值可以动态改变页面效果。
2️⃣ 与普通的 class 属性共存
此外,v-bind:class
指令也可以与普通的 class 属性共存。 语法:<div class ="defaultClass" v-bind:class="{ classA: isA,classB:isB }">
当有如下模板:
<div
class="defaultClass" v-bind:class="{ show: isShow, 'text-danger': hasError }">
</div>
和如下 data:
data: {
isShow: true,
hasError: false
}
页面结果渲染为:
<div class="defaultClass active"></div>
代码解释: 当 isShow
或者 hasError
变化时,class 列表将相应地更新。
例如,如果 hasError
的值为 true
,isShow
的值为 true
,class 列表将变为 "defaultClass show text-danger"
。
例如,如果 hasError
的值为 true
,isShow
的值为 false
,class 列表将变为 "defaultClass text-danger"
。
在之前介绍的案例中,我们将绑定的数据对象内联定义在模板里, 这样显得比较繁琐。其实,我们可以统一定义在一个 classObject 中:
实例演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<div class="defaultClass" v-bind:class="classObject">Hello !</div>
</div>
</body>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
classObject: {
show: true,
'text-danger': false
}
},
})
</script>
</html>
页面结果渲染为:
<div class="defaultClass show"></div>
代码解释: HTML 代码中,我们首先给 div 一个固定样式 defaultClass, 然后通过 classObject 给 div 绑定样式。 JS 代码 第 6-9 行,我们定义了数据 classObject,它有两个属性:1. 属性 show,值为 true,2. 属性 text-danger,值为 false。所以,最后页面渲染的效果是:<div class="defaultClass show"></div>
3️⃣ 利用计算属性绑定样式
<div v-bind:class="classObject"></div>
我们也可以在这里绑定一个返回对象的计算属性。这是一个常用且强大的模式:
实例演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<div v-bind:class="classObject"></div>
</div>
</body>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
computed: {
//对象语法————classObject: function(){...}等价于classObject(){...}
classObject: function () {
return {
show: true,
//对象的属性名引号可加可不加,若属性名里有特殊字符,属性名必须加引号)
'text-danger': false
}
}
}
})
</script>
</html>
页面结果渲染为:
<div class="defaultClass show"></div>
代码解释: HTML 代码中,我们通过 classObject 给 div 绑定样式。 JS 代码 第 6-11 行,我们定义了计算属性 classObject,它返回一个对象,该对象有两个属性:1. 属性 show,值为 true,2. 属性 text-danger,值为 false。所以,最后页面渲染的效果是:<div class="show"></div>
💦 数组语法形式 💦
我们可以把一个数组传给 v-bind:class
,以应用一个 class 列表:
实例演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<div v-bind:class="[classA, classB]">Hello !</div>
</div>
</body>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
classA: 'classA',
classB: 'classB1 classB2'
},
})
</script>
</html>
页面结果渲染为:
<div class="classA classB1 classB2"></div>
代码解释: 在 HTML 代码中,我们通过数组给 div 绑定样式,数组中有 classA 和 classB 两个值。 在 JS 代码第 6-7 行定义了 classA 和 classB 两个字符串,它的格式和元素 class 的格式相同,不同的样式类之间以空格相隔。
如果你也想根据条件切换列表中的 class,可以用三元表达式:
<div v-bind:class="[isShow ? showClass : '', classB]"></div>
这样写将始终添加 classB
的样式,但是只有在 isShow
为真时才添加 showClass
。
不过,当有多个条件 class 时这样写有些繁琐。所以在数组语法中也可以使用对象的形式来表达数组中的某一项:
<div v-bind:class="[{ showClass: isShow }, classB]"></div>
代码解释: 在 HTML 中,div 绑定一个样式数组,数组第一项是一个对象表达式 { showClass: isShow }。当 isShow 为 true 时样式最终绑定为:<div v-bind:class="[showClass, classB]"></div>
;当 isShow 为 false 时样式最终绑定为:<div v-bind:class="[classB]"></div>
;
❣️ 巩固总结:样式绑定——动态绑定内联样式
和 Class 的绑定一样,Style 的绑定同样可以通过数组和对象的两种形式。
💦 对象语法 💦
在文章开头时,讲解的便是绑定内联样式的对象语法,在这里我们重新再回顾一下。
v-bind:style
的对象语法十分直观——看着非常像 CSS,但其实是一个 JavaScript 对象。CSS 属性名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来,因为对象的书写格式中规定,属性名引号可加可不加,但若属性名里有特殊字符,属性名必须加引号,关于队对象的知识点介绍,请之后关注我的JS专栏) 来命名:
实例演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<div v-bind:style="{ backgroundColor: backgroundColor, width: width + 'px' }"></div>
</div>
</body>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
backgroundColor: 'red',
width: 300
}
})
</script>
</html>
页面结果渲染为:
<div style =" background-color:red;width: 300px"></div>
代码解释: 在 HTML 代码中,我们给 div 绑定 background-color 和 width 两个内联样式,它们的值在 data 中定义。
在模板中写较为复杂的表达式语法显得比较繁琐,通常直接绑定到一个样式对象更好,这会让模板显得更加清晰:
实例演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<div v-bind:style="styleObject"></div>
</div>
</body>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
styleObject: {
"background-color": 'red',
width: '300px'
}
},
})
</script>
</html>
页面结果渲染为:
<div style ="background-color:red;width: 300px"></div>
代码解释: 在 HTML 代码中,我们给 div 绑定数据 styleObject,它们的值在 data 中定义(data里保存界面里所有需要的变量)。
💦 数组语法 💦
v-bind:style
的数组语法可以将多个样式对象应用到同一个元素上:
实例演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<div v-bind:style="[stylesA, stylesB]"></div>
</div>
</body>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
stylesA: {
"background-color": 'red',
width: '300px'
},
stylesB: {
color: '#fff',
height: '300px'
}
}
})
</script>
</html>
页面结果渲染为:
<div style ="background-color:red;width: 300px;color:#fff;height:300px"></div>
❣️ 小结
本小节我们学习了如何通过v-bind
来动态绑定样式。主要有以下知识点:
- 通过 v-bind:class 动态绑定元素的 Class;
- v-bind:style 动态绑定元素的内联样式;
- 如何通过数组和对象的形式给 v-bind:class 和 v-bind:style 赋值。
💥 扩展:this判断—8种指向
this 8种指向: 判断this,一定不要看定义在哪儿!只看调用时!
➡️ 1. obj.fun() this->obj
➡️ 2. fun() 或 (function(){ ... })() 或 多数回调函数 或 定时器函数 this->window
➡️ 3. new Fun() this->new正在创建的新对象
➡️ 4. 类型名.prototype.共有方法=function(){ ... } this->将来谁调用指谁,同第一种情况
➡️ 5. DOM或jq中事件处理函数中的this->当前正在触发事件的DOM元素对象
如果需要使用简化版函数,必须$(this)
➡️ 6. 箭头函数中的this->箭头函数外部作用域中的this
➡️ 7. jQuery.fn.自定义函数=function(){ ... } this->将来调用这个自定义函数的.前的jQuery子对象,不用再$(this)
➡️ 8. new Vue()中methods中的函数中的this->当前new Vue()对象
⬛ 总结:知识点提炼
1. MVVM: 界面View+模型Model+视图模型ViewModel
2. Vue绑定原理: 访问器属性+虚拟DOM树
变量被修改时: 访问器属性发出通知,虚拟DOM树扫描并仅更新受影响的元素
3. 虚拟DOM树优点:
(1). 小: 只包含可能变化的元素。
(2). 遍历查找快
(3). 修改效率高: 只修改受影响的元素。
(4). 避免重复编码: 已封装DOM增删改查代码
4. Vue功能3步:
(1). 先创建增强版的界面:
a. 整个界面必须包含在一个唯一的父元素下:
通常是<div id="app">
b. 可能变化的元素内容用{{自定义变量名}}标记
c. 触发事件的元素用@click="自定义处理函数名"标记
(2). 再创建new Vue()对象,其中el:指向new Vue()要监控的页面区域
(3). 在new Vue()对象内定义模型对象data和methods
a.界面所需的所有变量都放在data中
b.界面所需的所有事件处理函数都放在methods中
5. 总结: 绑定语法+13种指令
(1). 如果元素的内容需要随变量自动变化: {{}}
(2). 如果元素的属性值需要随变量自动变化: :
(3). 控制一个元素显示隐藏: v-show //使用display:none隐藏元素
(4). 控制两个元素二选一显示: v-if v-else //使用删除元素方式隐藏元素
(5). 多个元素多选一显示: v-if v-else-if v-else
(6). 只要反复生成多个相同结构的元素组成列表时: v-for :key="唯一标识"
强调: 为什么必须加:key="i"?给每个元素副本添加唯一标识。修改数组中某个元素值时,避免重建整个列表,只需要修改一个DOM元素副本即可!提高修改效率。
(7). 只要绑定事件: @ $event
(8). 防止用户短暂看到{{}}: v-cloak和v-text
(9). 只要绑定原始HTML代码片段内容: v-html
(10). 如果元素的内容只在首次加载时绑定一次,之后都不会改变: v-once
优化: 减少虚拟DOM树中元素个数。
(11). 保护内容中的{{}}不被编译: v-pre
(12). 今后只要想获得表单元素的值或状态: v-model
6. 绑定样式:
(1). 需要精确修改某一个css属性,就绑定style:
a. <元素 style="固定样式" :style="{css属性:变量名, ...}"
data:{
变量名:css属性值
... : ...
}
b. <元素 style="固定样式" :style="变量名"
data:{
变量名:{
css属性名: 属性值,
... : ...
}
}
(2). 只要批量修改一个元素的多个css属性就绑定class
a. <元素 class="固定class" :class="{class名:变量名, ...}"
data:{
变量名:true或false,
... : ...
}
b. <元素 class="固定class" :class="变量名"
data:{
变量名:{
class名:true或false,
... : ...
}
}
【后文传送门】👉 vue自定义指令、计算属性、过滤器_06
如果这篇【文章】有帮助到你,希望可以给【青春木鱼】点个赞👍,创作不易,相比官方的陈述,我更喜欢用【通俗易懂】的文笔去讲解每一个知识点,如果有对【前端技术】感兴趣的小可爱,也欢迎关注❤️❤️❤️【青春木鱼】❤️❤️❤️,我将会给你带来巨大的【收获与惊喜】💕💕!