一:初识 Vue
1.1 绑定样式
1.1.1 绑定 class 样式
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>绑定样式</title>
<style>
......
</style>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
<!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
<div class="basic" :class="mood" >{{name}}</div> <br/><br/>
<!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 -->
<div class="basic" :class="classArr">{{name}}</div> <br/><br/>
<!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 -->
<div class="basic" :class="classObj">{{name}}</div> <br/><br/
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
el:'#root',
data:{
name:'尚硅谷',
mood:'normal',
classArr:['atguigu1','atguigu2','atguigu3'],//三个类名都会被应用到元素上
classObj:{
atguigu1:false,//Vue 根据对象中属性的初始布尔值,决定是否应用相应的类名。
atguigu2:false,//Vue 根据对象中属性的初始布尔值,决定是否应用相应的类名。
},
},
},
})
</script>
</html>
这段代码演示了在 Vue 中绑定 class 的三种方式:字符串写法、数组写法、对象写法。
-
字符串写法:
<div class="basic" :class="mood" >{{name}}</div> //mood:'normal',
这里使用了:class
指令来动态绑定类名字符串。在 Vue 实例中,mood
是一个字符串变量,它的值会根据用户行为而变化。
-
数组写法:
<div class="basic" :class="classArr">{{name}}</div> //classArr:['atguigu1','atguigu2','atguigu3'],//三个类名都会被应用到元素上
这里使用了:class
指令来动态绑定类名数组classArr
,在这个例子中,atguigu1
、atguigu2
、atguigu3
三个类名都会被应用到元素上。
-
对象写法:
<div class="basic" :class="classObj">{{name}}</div> /* classObj:{ atguigu1:false,//Vue 根据对象中属性的初始布尔值,决定是否应用相应的类名。 atguigu2:false,//Vue 根据对象中属性的初始布尔值,决定是否应用相应的类名。 }, */
这里使用了:class
指令来动态绑定类名对象classObj
,在这个例子中,atguigu1
和 atguigu2
的初始值为 false
,因此对应的类名不会被应用。当需要时,可以通过改变对象中属性的值来动态控制类名的应用或移除。
1.1.2 绑定 style 样式
**<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>绑定样式</title>
<style>
......
</style>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
<!-- 绑定style样式--对象写法 -->
<div class="basic" :style="styleObj">{{name}}</div> <br/><br/>
<!-- 绑定style样式--数组写法 -->
<div class="basic" :style="styleArr">{{name}}</div>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
el:'#root',
data:{
name:'尚硅谷',
styleObj:{
fontSize: '40px',
color:'red',
},
styleObj2:{
backgroundColor:'orange'
},
styleArr:[
{
fontSize: '40px',
color:'blue',
},
{
backgroundColor:'gray'
}
]
},
},
})
</script>
</html>**
这段代码演示了在 Vue 中绑定样式的两种方式:对象写法和数组写法。
-
对象写法:
<div class="basic" :style="styleObj">{{name}}</div>
这里使用了:style
指令来动态绑定样式对象styleObj
,代码中的styleObj
被应用到这个<div>
元素上,fontSize: '40px'
定义了字体大小为40像素,color: 'red'
定义了文本颜色为红色。
-
数组写法:
<div class="basic" :style="styleArr">{{name}}</div>
这里使用了:style
指令来动态绑定样式数组styleArr
,数组中的样式对象被依次应用到这个<div>
元素上,第一个对象定义了字体大小为40像素,文本颜色为蓝色,第二个对象定义了背景颜色为灰色。
1.2 条件渲染
在 Vue 中,条件渲染是一种根据数据的值来动态显示或隐藏 DOM 元素的技术。Vue 提供了多种方式来实现条件渲染,包括-if
、v-else-if
、v-else
、v-show
等指令。
1.2.1. v-if 和 v-else-if`和 v-else
v-if
指令用于根据表达式的值来决定是否渲染一个元素,如果表达式返回 true
,则元素被渲染,表达式返回false
则不被渲染。v-else-if
和 v-else
则用于在v-if
之后添加额外的条件逻辑。
<p v-if="seen">现在你看到我了</p>
<p v-else-if="type === 'A'">Type A</p>
<p v-else-if="type === 'B'">Type B</p>
<p v-else>Type C</p>
</div>
<script>
new Vue({
el: '#app',
data: {
seen: true,
type: 'B'
}
})
</script>
在这个示例中,<p>
标签根据 seen
的值来决定是否渲染。当 seen
为 true
时,第一个 <p>
标签被渲染;如果 seen
为 false
,则该元素不会被渲染。另外,根据 type
的值,也可以决定渲染不同的 <p>
元素。
1.2.2. v-show
v-show
指令也用于根据表达式的值来控制元素的显示与隐藏,但是与 v-if
不同的是,无论条件是否为真,被绑定的元素始终会被渲染到 DOM 中,只是通过 CSS 的 display
属性来控制显示与隐藏而已。
<div id="app">
<p v-show="seen">现在你看到我了</p>
</div>
<script>
new Vue({
el: '#app',
data: {
seen: true
}
})
</script>
在这个示例中,<p>
元素始终存在于 DOM 中,但是根据 seen
的值,它可能是可见的(display: block
)或不可见的(display: none
)。
条件渲染的选择:
- v-if 适用于:切换频率较低的场景。
- v-show 适用于:切换频率较高的场景。
1.2.3 v-if与template的配合使用
在 Vue 中,v-if
指令通常用于条件性地渲染一块内容。有时候,我们可能需要在多个元素之间进行条件渲染,但又不想向 DOM 中添加额外的标签,我们该怎么办呢?
在 Vue 中,<template>
元素在渲染时不会出现在最终的 DOM 中,它只是作为一个逻辑容器来帮助进行条件渲染,这时,就可以使用 <template>
元素与 v-if
指令结合起来,以实现条件渲染而不引入额外的 DOM 元素。
以下是使用 v-if
与 <template>
的配合示例:
<template v-if="isTrue">
<h1>Title</h1>
<p>Content</p>
</template>
<template v-else>
<h1>Another Title</h1>
<p>Another Content</p>
</template>
在这个示例中,<template>
元素内部包含了要条件渲染的内容,根据 v-if
指令的值来决定是否渲染这段内容。当 isTrue
为 true
时,第一个 <template>
素内部的内容会被渲染,否则渲染第二个 <template>
内部的内容。
1.3 列表渲染
1.3.1 v-for
在 Vue 中,v-for
指令用于迭代数组或对象,并为每项数据渲染出对应的元素。
v-for
的语法格式为 v-for="item in items"
,其中 item
是形参,可以任意指定,代表数组中的每一项,items
是要遍历的数组。
下面我将详细介绍 v-for
的用法。
作用一:迭代数组:
在 Vue 中,使用 v-for
迭代数组非常常见。下面是一个简单的示例:
<div id="app">
<ul>
<li v-for="item in items">{{ item }}</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data: {
items: ['Apple', 'Banana', 'Orange']
}
})
</script>
运行结果如图所示:
这段代码的执行流程:
- 当页面加载时,Vue 实例被创建并挂载到
id
为app
的<div>
元素上。 - Vue 实例开始解析模板,遇到
v-for
指令时,它会遍历items
数组中的每一项,并为每一项生成一个<li>
元素,并将当前项的值插入到<li>
元素的内容中。 - Vue 实例将解析后的 DOM 结构渲染到页面上,用户就可以看到每个水果名字显示在无序列表中的各个列表项中。
- 如果后续有任何对
items
数组的修改(例如添加、删除或更新数组中的项),Vue 实例会检测到这些变化并相应地更新 DOM,以保持页面与数据的同步。
作用二:获取索引值
有时候我们需要获取每一项数据的索引值,可以使用第二个参数来获取索引:
<div id="app">
<ul>
<li v-for="(item, index) in items">{{ index }}. {{ item }}</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data: {
items: ['Apple', 'Banana', 'Orange']
}
})
</script>
运行结果:
在这个示例中,(item, index)
中的 index
就是每一项数据的索引值。
作用三:迭代对象
除了迭代数组,v-for
也可以用于迭代对象的键值对:
<div id="app">
<ul>
<li v-for="(value, key) in object">{{ key }}: {{ value }}</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data: {
object: {
name: 'John',
age: 30,
gender: 'male'
}
}
})
</script>
运行结果:
在这个示例中,(value, key)
中的 value
是对象的值,key
是对象的键。
当然有时候我们只需要对象的值,或者只需要键,可以使用 v-for
的特殊语法:
- 只获取对象的值:
<div v-for="value in object">{{ value }}</div>
- 只获取对象的键:
<div v-for="key in object">{{ key }}</div>
作用四:遍历字符串
代码示例:
<div id="app">
<p v-for="(char, index) in message" :key="index">{{ char }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
</script>
执行流程:
- 页面加载时,Vue 实例被创建并挂载到
id
为app
的<div>
元素上。 - Vue 实例开始解析模板,遇到
v-for
指令时,它会遍历message
字符串中的每个字符。 - 对于每个字符,Vue 实例将创建一个
<p>
元素,并将当前字符的值插入到<p>
元素的内容中。 - Vue 实例将解析后的 DOM 结构渲染到页面上,用户可以看到每个字符显示在独立的
<p>
元素中。
页面渲染结果:
每个字符都被渲染为一个独立的 <p>
元素,并按照它们在字符串中的顺序显示出来。
1.3.2 key 的作用
虚拟DOM中key的作用:
在Vue.js中,当渲染列表或者进行动态数据更新时,Vue会使用虚拟DOM来描述真实DOM的结构。而key就是虚拟DOM对象的标识,它的作用在于帮助Vue识别每个虚拟DOM节点的唯一性。
虚拟 DOM 对比算法规则:
在更新虚拟DOM时,Vue需要比较新旧虚拟DOM,以确定具体的更新操作。比较的规则如下:
-
当在旧虚拟DOM中找到与新虚拟DOM相同的key时:
- 若虚拟DOM中内容没变,则直接使用之前的真实DOM,不做更新操作。
- 若虚拟DOM中内容发生了变化,则生成新的真实DOM,并替换页面中之前的真实DOM。
-
当在旧虚拟DOM中未找到与新虚拟DOM相同的key时:
- 创建新的真实DOM,并将其渲染到页面中。
.用index作为key可能会引发的问题:
在某些情况下,使用列表的索引(index)作为key可能会导致一些问题:
- 若对数据进行逆序添加、逆序删除等破坏顺序的操作时,会导致没有必要的真实DOM更新,这会降低页面的效率。
- 如果列表中的结构还包含了输入类的DOM,使用index作为key可能会导致错误的DOM更新,从而使界面出现问题。
开发中如何选择key?
在选择key时,我们应该考虑以下几点:
- 最好使用每条数据的唯一标识作为key,例如id、手机号、身份证号、学号等具有唯一性的值。
- 如果确定不会对数据进行逆序添加、逆序删除等破坏顺序的操作,并且仅用于渲染列表用于展示,那么使用index作为key是没有问题的。
1.3.3 列表过滤
在Vue中,列表过滤通常指的是根据特定条件筛选出列表中的部分项进行展示。这在实际开发中非常常见,特别是当你需要根据用户输入或其他条件来动态显示数据时。
假设我们有一个包含一些用户的列表,我们想要实现一个搜索框,用户可以在搜索框中输入关键词,然后列表会根据输入的关键词动态过滤显示相匹配的用户。
HTML 模板:
<template>
<div>
<input type="text" v-model="searchKeyword" placeholder="Search...">
<ul>
<li v-for="(user, index) in filteredUsers" :key="user.id">
{{ user.name }}
</li>
</ul>
</div>
</template>
Vue 实例:
<script>
export default {
data() {
return {
searchKeyword: '', // 用户输入的搜索关键词
users: [ // 初始用户列表
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 3, name: 'Charlie' },
{ id: 4, name: 'David' }
]
};
},
computed: {
filteredUsers() {
// 使用计算属性过滤用户列表
return this.users.filter(user => {
return user.name.toLowerCase().includes(this.searchKeyword.toLowerCase());
});
}
}
};
</script>
下面是这段代码的执行流程:
-
定义计算属性:在Vue实例中,我们使用
computed
属性定义了一个名为filteredUsers
的计算属性。 -
计算属性逻辑:在
filteredUsers
计算属性中,我们使用了this.users.filter()
方法。这个方法用于对this.users
数组中的每个元素进行筛选,返回一个新的数组,该数组包含满足条件的元素。在这里,我们使用了箭头函数来定义filter
的筛选条件。 -
筛选条件:我们的筛选条件是
user.name.toLowerCase().includes(this.searchKeyword.toLowerCase())
。这个条件首先将user.name
和this.searchKeyword
转换为小写字母,然后通过includes()
方法检查user.name
中是否包含this.searchKeyword
。 -
动态更新:由于
filteredUsers
是一个计算属性,当this.searchKeyword
发生变化时,Vue会自动重新计算filteredUsers
,从而更新列表中显示的内容。这样就实现了根据用户输入动态过滤列表的功能。
所以这段代码通过计算属性实现了动态过滤用户列表的功能,用户可以通过输入搜索关键词来实时筛选出感兴趣的用户。
1.3.4 Vue监测数据改变的原理
当 Vue 实例创建时,会对 data
中的数据进行加工。加工的过程主要包括以下步骤:
-
配置 Getter 和 Setter:
Vue 会遍历data
中的每个属性,并为每个属性配置 getter 和 setter 方法。 -
代理:
加工完成后,Vue 将 data 中的数据拷贝到_vm.data
中,此时你可以通过this.xxx
的方式直接访data
中的数据,而不需要通过_vm.data.xxx
的形式。 -
数据监听:
在 setter 方法中,Vue 实现了一种调用机制,当数据被修改时,会调用 setter 方法。 setter 方法中写了一个引用,而这个引用能够引起模板的重新解析。
通过以上步骤,Vue 实现了数据的响应式监测,使数据变化能够自动更新相关视图,从实现了 Vue 监测数据改的原理。
1.3.5 Vue.set 和 this.$set 方法
Vue使用setter来实现监测对象中的数据,这意味着在创建Vue实例时就需要传入要监测的数据,对于后追加的属性,Vue默认不会做响应式处理
这意味着如果你在data中定义了一个对象,后续再给这个对象添加属性时,Vue不会自动更新相关视图。
若要让后添加的属性也具有响应式,需要使用Vue提供的API:Vue.set
和 this.$set
方法
Vue.set
和 this.$set
方法用于向响应式对象添加响应式属性,确保当属性被添加时,能够触发视图更新。
举个例子:
// 假设 student 对象在 data 中已经定义
Vue.set(this.student, 'sex', '男');//两种形式都可以
this.$set(this.student, 'sex', '男');
在这个例子中,假设 student
是一个响应式对象,我们想要添加一个新的属性 sex
,并且还希望 Vue 能够监听到这属性的变化。
此时我们可以使用 Vue.set
或 .$set
方法,将sex
属性添加到 student
中,并赋予其初始值 `‘男’。此后,Vue 将会监到 sex 属性的变化,并图中进行更新。
1.3.6 总结数据监视
vue会监视data中所有层次的数据
如何监测对象中的数据?
通过setter实现监视,且要在new Vue时就传入要监测的数据
(1)对象中后追加的属性,Vue默认不做响应式处理
(2)如需给后添加的属性做响应式,请使用如下API:
- Vue.set(target,propertyName/index,value)
- vm.$set(target,propertyName/index,value)
如何监测数组中的数据?
通过封装数组更新元素和原生数组方法实现,其本质就是做了两件事:
(1)调用原生对应的方法对数组进行更新
(2)重新解析模板,进而更新页面
在Vue修改数组中的某个元素一定要用如下方法:
- 使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
这些方法已经被Vue重写,能够触发响应式更新,这些方法的本质是两步:首先调用原生数组方法对数组进行更新,然后重新解析模板,从而更新页面。
- Vue.set() 或 vm.$set()
另外,也可以使用Vue.set()或vm.$set()方法来修改数组中的元素。
特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象(data等)添加属性
这个限制存在的原因是:
当Vue实例已经创建完成后,它的根数据对象已经被加工完毕,Vue不再允许动态地向根数据对象添加新的响应式属性。因为在实例化之后,Vue.js已经无法再对根数据对象进行监测和加工,所以在这个阶段使用Vue.set()
或vm.$set()
来添加属性是无效的。