为什么要学习Vue

1.前端必备技能

2.岗位多,绝大互联网公司都在使用Vue

3.提高开发效率

4.高薪必备技能(Vue2+Vue3)

什么是Vue

概念:Vue (读音 /vjuː/,类似于 view) 是一套 **构建用户界面 ** 的 渐进式 框架

Vue2官网:https://v2.cn.vuejs.org/

1.什么是构建用户界面

基于数据渲染出用户可以看到的界面

68187588702

2.什么是渐进式

所谓渐进式就是循序渐进,不一定非得把Vue中的所有API都学完才能开发Vue,可以学一点开发一点

Vue的两种开发方式:

  1. Vue核心包开发

    场景:局部模块改造

  2. Vue核心包&Vue插件&工程化

    场景:整站开发

3.什么是框架

所谓框架:就是一套完整的解决方案

举个栗子

如果把一个完整的项目比喻为一个装修好的房子,那么框架就是一个毛坯房。

我们只需要在“毛坯房”的基础上,增加功能代码即可。

提到框架,不得不提一下库。

  • 库,类似工具箱,是一堆方法的集合,比如 axios、lodash、echarts等
  • 框架,是一套完整的解决方案,实现了大部分功能,我们只需要按照一定的规则去编码即可。

下图是 库 和 框架的对比。

68187662027

框架的特点:有一套必须让开发者遵守的规则或者约束

咱们学框架就是学习的这些规则 官网

总结:什么是Vue?

Vue是什么:

什么是构建用户界面:

什么是渐进式:

什么是框架:

创建Vue实例

我们已经知道了Vue框架可以 基于数据帮助我们渲染出用户界面,那应该怎么做呢?

68187719013

比如就上面这个数据,基于提供好的msg 怎么渲染后右侧可展示的数据呢?

核心步骤(4步):

  1. 准备容器
  2. 引包(官网) — 开发版本/生产版本
  3. 创建Vue实例 new Vue()
  4. 指定配置项,渲染数据
    1. el:指定挂载点
    2. data提供数据

68187740500

总结:创建Vue实例需要执行哪4步

插值表达式 “{}”

插值表达式是一种Vue的模板语法

我们可以用插值表达式渲染出Vue提供的数据

68188649441

1.作用:利用表达式进行插值,渲染到页面中

表达式:是可以被求值的代码,JS引擎会讲其计算出一个结果

以下的情况都是表达式:

1
2
3
4
5
6
7
8
9
money + 100
money - 100
money * 10
money / 10
price >= 100 ? '真贵':'还行'
obj.name
arr[0]
fn()
obj.fn()

2.语法

插值表达式语法:”{ 表达式 }”

1
2
3
4
5
6
7
8
9
<h3>"{title}"<h3>

<p>"{nickName.toUpperCase()}"</p>

<p>"{age >= 18 ? '成年':'未成年'}"</p>

<p>"{obj.name}"</p>

<p>"{fn()}"</p>

3.错误用法

1
2
3
4
5
6
7
8
1.在插值表达式中使用的数据 必须在data中进行了提供
<p>"{hobby}"</p> //如果在data中不存在 则会报错

2.支持的是表达式,而非语句,比如:if for ...
<p>"{if}"</p>

3.不能在标签属性中使用 "{ }" 插值 (插值表达式只能标签中间使用)
<p title=""{username}"">我是P标签</p>

4.总结

1.插值表达式的作用是什么

2.语法是什么

3.插值表达式的注意事项

响应式特性

1.什么是响应式?

​ 简单理解就是数据变,视图对应变。

2.如何访问 和 修改 data中的数据(响应式演示)

data中的数据, 最终会被添加到实例上

① 访问数据: “实例.属性名”

② 修改数据: “实例.属性名”= “值”

68188853934

3.总结

  1. 什么是响应式
  2. 如何访问和修改data中的数据呢

Vue开发者工具安装

  1. 通过谷歌应用商店安装(国外网站)
  2. 极简插件下载(推荐) https://chrome.zzzmh.cn/index

安装步骤:

68188939040

安装之后可以F12后看到多一个Vue的调试面板

68188948344

Vue中的常用指令

概念:指令(Directives)是 Vue 提供的带有 v- 前缀 的 特殊 标签属性

为啥要学:提高程序员操作 DOM 的效率。

vue 中的指令按照不同的用途可以分为如下 6 大类:

  • 内容渲染指令(v-html、v-text)
  • 条件渲染指令(v-show、v-if、v-else、v-else-if)
  • 事件绑定指令(v-on)
  • 属性绑定指令 (v-bind)
  • 双向绑定指令(v-model)
  • 列表渲染指令(v-for)

指令是 vue 开发中最基础、最常用、最简单的知识点。

v-text

内容渲染指令用来辅助开发者渲染 DOM 元素的文本内容。常用的内容渲染指令有如下2 个:

  • v-text(类似innerText)

    • 使用语法:<p v-text="uname">hello</p>,意思是将 uame 值渲染到 p 标签中
    • 类似 innerText,使用该语法,会覆盖 p 标签原有内容
  • v-html(类似 innerHTML)

    • 使用语法:<p v-html="intro">hello</p>,意思是将 intro 值渲染到 p 标签中
    • 类似 innerHTML,使用该语法,会覆盖 p 标签原有内容
    • 类似 innerHTML,使用该语法,能够将HTML标签的样式呈现出来。

代码演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
<div id="app">
<h2>个人信息</h2>
// 既然指令是vue提供的特殊的html属性,所以咱们写的时候就当成属性来用即可
<p v-text="uname">姓名:</p>
<p v-html="intro">简介:</p>
</div>

<script>
const app = new Vue({
el:'#app',
data:{
uname:'张三',
intro:'<h2>这是一个<strong>非常优秀</strong>的boy<h2>'
}
})
</script>

v-show、v-if

条件判断指令,用来辅助开发者按需控制 DOM 的显示与隐藏。条件渲染指令有如下两个,分别是:

  1. v-show

    1. 作用: 控制元素显示隐藏
    2. 语法: v-show = “表达式” 表达式值为 true 显示, false 隐藏
    3. 原理: 切换 display:none 控制显示隐藏
    4. 场景:频繁切换显示隐藏的场景

    68189122828

  2. v-if

    1. 作用: 控制元素显示隐藏(条件渲染)
    2. 语法: v-if= “表达式” 表达式值 true显示, false 隐藏
    3. 原理: 基于条件判断,是否创建 或 移除元素节点
    4. 场景: 要么显示,要么隐藏,不频繁切换的场景

    68189123775

    示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <div id="app">
    <div class="box">我是v-show控制的盒子</div>
    <div class="box">我是v-if控制的盒子</div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
    const app = new Vue({
    el: '#app',
    data: {
    flag: false
    }
    })
    </script>
  3. v-else 和 v-else-if

    1. 作用:辅助v-if进行判断渲染
    2. 语法:v-else v-else-if=”表达式”
    3. 需要紧接着v-if使用

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<div id="app">
<p>性别:♂ 男</p>
<p>性别:♀ 女</p>
<hr>
<p>成绩评定A:奖励电脑一台</p>
<p>成绩评定B:奖励周末郊游</p>
<p>成绩评定C:奖励零食礼包</p>
<p>成绩评定D:惩罚一周不能玩手机</p>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>

const app = new Vue({
el: '#app',
data: {
gender: 2,
score: 95
}
})
</script>

v-on

使用Vue时,如需为DOM注册事件,及其的简单,语法如下:

  • <button v-on:事件名=”内联语句”>按钮
  • <button v-on:事件名=”处理函数”>按钮
  • <button v-on:事件名=”处理函数(实参)”>按钮
  • v-on: 简写为 @
  1. 内联语句

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <div id="app">
    <button @click="count--">-</button>
    <span>"{ count }"</span>
    <button v-on:click="count++">+</button>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
    const app = new Vue({
    el: '#app',
    data: {
    count: 100
    }
    })
    </script>
  2. 事件处理函数

    注意:

    • 事件处理函数应该写到一个跟data同级的配置项(methods)中
    • methods中的函数内部的this都指向Vue实例
1
2
3
4
5
6
7
8
9
10
11
12
13
<div id="app">
<button>切换显示隐藏</button>
<h1 v-show="isShow">黑马程序员</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
isShow: true
}
})
</script>

3.给事件处理函数传参

  • 如果不传递任何参数,则方法无需加小括号;methods方法中可以直接使用 e 当做事件对象

  • 如果传递了参数,则实参 $event 表示事件对象,固定用法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<style>
.box {
border: 3px solid #000000;
border-radius: 10px;
padding: 20px;
margin: 20px;
width: 200px;
}
h3 {
margin: 10px 0 20px 0;
}
p {
margin: 20px;
}
</style>

<div id="app">
<div class="box">
<h3>小黑自动售货机</h3>
<button>可乐5元</button>
<button>咖啡10元</button>
<button>牛奶8元</button>
</div>
<p>银行卡余额:"{ money }"元</p>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
money: 100
}
})
</script>

v-bind

  1. 作用:动态设置html的标签属性 比如:src、url、title
  2. 语法:**v-bind:**属性名=“表达式”
  3. **v-bind:**可以简写成 => :

比如,有一个图片,它的 src 属性值,是一个图片地址。这个地址在数据 data 中存储。

则可以这样设置属性值:

  • <img v-bind:src="url" />
  • <img :src="url" /> (v-bind可以省略)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div id="app">
<img v-bind:src="imgUrl" v-bind:title="msg" alt="">
<img :src="imgUrl" :title="msg" alt="">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
imgUrl: './imgs/10-02.png',
msg: 'hello 波仔'
}
})
</script>

v-for

Vue 提供了 v-for 列表渲染指令,用来辅助开发者基于一个数组来循环渲染一个列表结构。

v-for 指令需要使用 (item, index) in arr 形式的特殊语法,其中:

  • item 是数组中的每一项
  • index 是每一项的索引,不需要可以省略
  • arr 是被遍历的数组

此语法也可以遍历对象和数字

1
2
3
4
5
6
7
8
9
//遍历对象
<div v-for="(value, key, index) in object">"{value}"</div>
value:对象中的值
key:对象中的键
index:遍历索引从0开始

//遍历数字
<p v-for="item in 10">"{item}"</p>
item从1 开始

v-for中的key

语法: key=”唯一值”

作用:给列表项添加的唯一标识。便于Vue进行列表项的正确排序复用

为什么加key:Vue 的默认行为会尝试原地修改元素(就地复用

实例代码:

1
2
3
4
5
6
7
<ul>
  <li v-for="(item, index) in booksList" :key="item.id">
    <span>"{ item.name }"</span>
    <span>"{ item.author }"</span>
    <button @click="del(item.id)">删除</button>
  </li>
</ul>

注意:

  1. key 的值只能是字符串 或 数字类型
  2. key 的值必须具有唯一性
  3. 推荐使用 id 作为 key(唯一),不推荐使用 index 作为 key(会变化,不对应)

v-model

所谓双向绑定就是:

  1. 数据改变后,呈现的页面结果会更新
  2. 页面结果更新后,数据也会随之而变

作用:表单元素(input、radio、select)使用,双向绑定数据,可以快速 获取设置 表单元素内容

语法:v-model=”变量”

需求:使用双向绑定实现以下需求

  1. 点击登录按钮获取表单中的内容
  2. 点击重置按钮清空表单中的内容

68191312573

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div id="app">
账户:<input type="text"> <br><br>
密码:<input type="password"> <br><br>
<button>登录</button>
<button>重置</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
username: '',
password: ''
},
})
</script>

指令修饰符

1.什么是指令修饰符?

​ 所谓指令修饰符就是通过“.”指明一些指令后缀 不同的后缀封装了不同的处理操作 —> 简化代码

2.按键修饰符

  • @keyup.enter —>当点击enter键的时候才触发

代码演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div id="app">
<h3>@keyup.enter → 监听键盘回车事件</h3>
<input v-model="username" type="text">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
username: ''
},
methods: {

}
})
</script>

3.v-model修饰符

  • v-model.trim —>去除首位空格
  • v-model.number —>转数字

4.事件修饰符

  • @事件名.stop —> 阻止冒泡
  • @事件名.prevent —>阻止默认行为
  • @事件名.stop.prevent —>可以连用 即阻止事件冒泡也阻止默认行为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<style>
.father {
width: 200px;
height: 200px;
background-color: pink;
margin-top: 20px;
}
.son {
width: 100px;
height: 100px;
background-color: skyblue;
}
</style>

<div id="app">
<h3>v-model修饰符 .trim .number</h3>
姓名:<input v-model="username" type="text"><br>
年纪:<input v-model="age" type="text"><br>


<h3>@事件名.stop → 阻止冒泡</h3>
<div @click="fatherFn" class="father">
<div @click="sonFn" class="son">儿子</div>
</div>

<h3>@事件名.prevent → 阻止默认行为</h3>
<a @click href="http://www.baidu.com">阻止默认行为</a>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
username: '',
age: '',
},
methods: {
fatherFn () {
alert('老父亲被点击了')
},
sonFn (e) {
// e.stopPropagation()
alert('儿子被点击了')
}
}
})
</script>

v-bind对样式控制的增强

v-bind对样式控制的增强-操作class

为了方便开发者进行样式控制, Vue 扩展了 v-bind 的语法,可以针对 class 类名style 行内样式 进行控制 。

1.语法:

1
<div> :class = "对象/数组">这是一个div</div>

2.对象语法

当class动态绑定的是对象时,键就是类名,值就是布尔值,如果值是true,就有这个类,否则没有这个类

1
<div class="box" :class="{ 类名1: 布尔值, 类名2: 布尔值 }"></div>

​ 适用场景:一个类名,来回切换

3.数组语法

当class动态绑定的是数组时 → 数组中所有的类,都会添加到盒子上,本质就是一个 class 列表

1
<div class="box" :class="[ 类名1, 类名2, 类名3 ]"></div>

使用场景:批量添加或删除类

v-bind对有样式控制的增强-操作style

1.语法

1
<div class="box" :style="{ CSS属性名1: CSS属性值, CSS属性名2: CSS属性值 }"></div>

2.代码练习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<style>
.box {
width: 200px;
height: 200px;
background-color: rgb(187, 150, 156);
}
</style>
<div id="app">
<div class="box"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {

}
})
</script>

v-model在其他表单元素的使用

1.讲解内容:

常见的表单元素都可以用 v-model 绑定关联 → 快速 获取设置 表单元素的值

它会根据 控件类型 自动选取 正确的方法 来更新元素

1
2
3
4
5
6
输入框  input:text   ——> value
文本域 textarea ——> value
复选框 input:checkbox ——> checked
单选框 input:radio ——> checked
下拉菜单 select ——> value
...

computed计算属性

1.概念

基于现有的数据,计算出来的新属性依赖的数据变化,自动重新计算。

2.语法

  1. 声明在 computed 配置项中,一个计算属性对应一个函数
  2. 使用起来和普通属性一样使用 “{ 计算属性名}”

3.注意

  1. computed配置项和data配置项是同级
  2. computed中的计算属性虽然是函数的写法,但他依然是个属性
  3. computed中的计算属性不能和data中的属性同名
  4. 使用computed中的计算属性和使用data中的属性是一样的用法
  5. computed中计算属性内部的this依然指向的是Vue实例

computed计算属性 VS methods方法

1.computed计算属性

作用:封装了一段对于数据的处理,求得一个结果

语法:

  1. 写在computed配置项中
  2. 作为属性,直接使用
    • js中使用计算属性: this.计算属性
    • 模板中使用计算属性:”{计算属性}”

2.methods计算属性

作用:给Vue实例提供一个方法,调用以处理业务逻辑

语法:

  1. 写在methods配置项中
  2. 作为方法调用
    • js中调用:this.方法名()
    • 模板中调用 “{方法名()}” 或者 @事件名=“方法名”

3.计算属性的优势

  1. 缓存特性(提升性能)

    计算属性会对计算出来的结果缓存,再次使用直接读取缓存,

    依赖项变化了,会自动重新计算 → 并再次缓存

  2. methods没有缓存特性

  3. 通过代码比较

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<style>
table {
border: 1px solid #000;
text-align: center;
width: 300px;
}
th,td {
border: 1px solid #000;
}
h3 {
position: relative;
}
span {
position: absolute;
left: 145px;
top: -4px;
width: 16px;
height: 16px;
color: white;
font-size: 12px;
text-align: center;
border-radius: 50%;
background-color: #e63f32;
}
</style>

<div id="app">
<h3>小黑的礼物清单🛒<span>?</span></h3>
<table>
<tr>
<th>名字</th>
<th>数量</th>
</tr>
<tr v-for="(item, index) in list" :key="item.id">
<td>"{ item.name }"</td>
<td>"{ item.num }"个</td>
</tr>
</table>

<p>礼物总数:"{ totalCount }" 个</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
// 现有的数据
list: [
{ id: 1, name: '篮球', num: 3 },
{ id: 2, name: '玩具', num: 2 },
{ id: 3, name: '铅笔', num: 5 },
]
},
computed: {
totalCount () {
let total = this.list.reduce((sum, item) => sum + item.num, 0)
return total
}
}
})
</script>

4.总结

1.computed有缓存特性,methods没有缓存

2.当一个结果依赖其他多个值时,推荐使用计算属性

3.当处理业务逻辑时,推荐使用methods方法,比如事件的处理函数

计算属性的完整写法

既然计算属性也是属性,能访问,应该也能修改了?

  1. 计算属性默认的简写,只能读取访问,不能 “修改”
  2. 如果要 “修改” → 需要写计算属性的完整写法

68204182296

完整写法代码演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<div id="app">
姓:<input type="text" v-model="firstName"> +
名:<input type="text" v-model="lastName"> =
<span></span><br><br>
<button>改名卡</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
firstName: '刘',
lastName: '备'
},
computed: {

},
methods: {

}
})
</script>

watch侦听器(监视器)

1.作用:

监视数据变化,执行一些业务逻辑或异步操作

2.语法:

  1. watch同样声明在跟data同级的配置项中

  2. 简单写法: 简单类型数据直接监视

  3. 完整写法:添加额外配置项

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    data: { 
      words: '苹果',
      obj: {
        words: '苹果'
      }
    },

    watch: {
    // 该方法会在数据变化时,触发执行
      数据属性名 (newValue, oldValue) {
    一些业务逻辑 或 异步操作。
    },
    '对象.属性名' (newValue, oldValue) {
    一些业务逻辑 或 异步操作。
    }
    }

3.完整写法

完整写法 —>添加额外的配置项

  1. deep:true 对复杂类型进行深度监听
  2. immdiate:true 初始化 立刻执行一次
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
data: {
  obj: {
    words: '苹果',
    lang: 'italy'
  },
},

watch: {// watch 完整写法
  对象: {
deep: true, // 深度监视
immdiate:true,//立即执行handler函数
    handler (newValue) {
      console.log(newValue)
    }
  }
}

4.总结

watch侦听器的写法有几种?

1.简单写法

1
2
3
4
5
6
7
8
watch: {
  数据属性名 (newValue, oldValue) {
一些业务逻辑 或 异步操作。
},
'对象.属性名' (newValue, oldValue) {
一些业务逻辑 或 异步操作。
}
}

2.完整写法

1
2
3
4
5
6
7
8
9
watch: {// watch 完整写法
  数据属性名: {
deep: true, // 深度监视(针对复杂类型)
immediate: true, // 是否立刻执行一次handler
    handler (newValue) {
      console.log(newValue)
    }
  }
}

Vue声明周期和生命周期的四个阶段

思考:什么时候可以发送初始化渲染请求?(越早越好)什么时候可以开始操作dom?(至少得dom渲染出来)

Vue声明周期:一个Vue实例从创建销毁的过程

生命周期四个阶段:1.创建 2.挂载 3.更新 4.销毁

image-20240418171447366

Vue声明周期函数(钩子函数)

Vue生命周期过程,会自动运行一些函数,被称为【生命周期钩子】→让开发者 在【特定阶段】运行自己的代码

image-20240418171711663

image-20240418171649423

created:发送初始化渲染请求

mounted:操作dom

before destory:释放Vue以外的资源(清除定时器,延时器….)

工程化开发 & 脚手架Vue CLI

基本介绍:

Vue CLI 是Vue官方提供的一个全局命令工具

可以帮助我们快速创建一个开发Vue项目的标准化基础架子,【集成了webspack配置】

好处:

1.开箱即用,零配置

2.内置babel

3.标准化

运行流程:

image-20240419091402170

组件化

  • 页面可以拆分成一个个组件,每个组件有着独立的结构、行为、样式
  • 好处:便于维护,利用复用 → 提升开发效率
  • 组件分类:普通组件、根组件

根组件

整个应用最上层的组件、包裹所有普通小组件

一个组件App.vue 包含的三个部分:

  • template:结构(有且只能有一个根元素)
  • script:js逻辑
  • style:样式(可支持less,需要装包)

普通组件的注册使用

组件注册的两种方式:

  1. 局部注册:只能在注册的组件中使用
    1. 创建.vue文件
      • image-20240419100716370
    2. 在使用的组件内导入并注册(在App.vue中完成)
      • image-20240419100739919
    3. 调用
      • image-20240419100800332
  2. 全局注册:所有组件都能使用
    1. 在main.js中导入
      • image-20240419100548570
    2. 在main.js进行全局注册
      • image-20240419100607199
    3. 去需要用到组件的vue中进行使用即可
      • image-20240419100645668

Scoped

默认情况:写在组件中的样式会 全局生效 → 因此很容易造成多个组件之间的样式冲突问题

  • 全局样式:默认组件中的样式会作用到全局
  • 局部样式:可以给组件加上scoped属性,可以让样式只作用于当前组件

原理:

  1. 当前组件内标签都被添加 data-v-hash值 的属性
    • image-20240419120757751
  2. css 选择器都被添加 [data-v-hash值] 的属性选择器
    • image-20240419120808041

最终效果:必须是当前组件的元素,才会有这个自定义属性,才会被这个样式作用到

data函数

组件中的data是一个函数,并非之前的data对象

1
2
3
4
5
6
7
8
9
<script>
export default {
data() {
return {
count: 100
}
}
}
</script>

两种组件关系分类 和 对应的组件通信方案

父子关系 ——→ **props **& $emit

非父子关系 ——→ provide & injecteventbus

通用方案 ——→ vuex

父子通信方案的核心流程

父 → 子 props

  • 父中给子添加属性传值
  • 子props接收
  • 使用

image-20240419131754371

子 → 父 $emit

  • 子$emit发送消息
  • 父中给子添加消息监听
  • 父中实现处理函数

image-20240419131827371

props

Prop定义

组件上注册一些自定义属性

Prop作用

向子组件传递数据

特点:

  • ​ 可以 传递 任意数量 的prop
  • ​ 可以 传递 任意类型 的prop

image-20240419134855205

prop校验

思考:组件的prop 可以乱穿么? 不可以

作用:为组件的prop指定验证要求,不符合要求,控制台就会有错误提示 → 帮助开发者,快速发现错误

语法

  • 类型校验
  • 非空校验
  • 默认值
  • 自定义校验

image-20240419135923055
image-20240419140715188

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
props: {
w: number
}

-------------------------------------------
props: {
w: {
type: 类型,
required: true, // 是否必填
default:默认值, //默认值
validator(value) {
if(逻辑判断) {
// 自定义校验逻辑
return true
}
}
}
}

prop & data、单向数据流

共同点:都可以给组件提供数据

区别:

  • data 的数据是自己的 → 随便改
  • prop 的数据是外部的 → 不能随便改, 要遵循单向数据流

单项数据流:父级prop的数据更新,会向下流动,影响子组件。这个数据流动是单项的

image-20240419141355768

非父子通信(拓展)-event bus 事件总线

image-20240419154933160

作用:非父子组件之间,进行简易消息传递。(复杂场景 → Vuex)

  1. 创建一个都能访问到的事件总线(空Vue实例) → utils/EventBus.js
    • image-20240419154832119
  2. A组件(接收方),监听Bus实例的事件
    • image-20240419154858841
  3. B组件(发送方),触发Bus实例的事件
    • image-20240419154924207

实现

组件A:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
<div class="base-a">
我是A组件(接受方)
<p>"{msg}"</p>
</div>
</template>

<script>
import Bus from '../utils/EventBus'
export default {
data() {
return {
msg: '',
}
},
created() {
Bus.$on('sendMsg', (msg) => {
this.msg = msg
})
},
}
</script>

组件B:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<div class="base-b">
<div>我是B组件(发布方)</div>
<button @click="sendMsgFn">发送消息</button>
</div>
</template>

<script>
import Bus from '../utils/EventBus'
export default {
methods: {
sendMsgFn() {
Bus.$emit('sendMsg', '今天天气不错,适合旅游')
},
},
}
</script>

非父子通信-provide & inject

provide & inject的作用:跨层级共享数据

父组件: provide 提供数据

image-20240420094110639

响应式:当修改数据时 页面会做出响应

非响应式:当修改数据时,页面不会做出响应

子/孙组件: inject 取值使用

image-20240420094226560

v-model原理

原理:

v-model本质上是一个语法糖。例如应用在输入框上,就是value属性 和 input事件 的合写

1
2
3
4
5
6
7
8
<template>
  <div id="app" >
    <input v-model="msg" type="text">

    <input :value="msg" @input="msg = $event.target.value" type="text">
  </div>
</template>

作用:

提供数据的双向绑定

  • 数据变,视图跟着变:value
  • 视图变,数据跟着变:@input

注意

$event 用于在模板中,获取事件的形参

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<div class="app">
<input type="text" />
<br />
<input type="text" />
</div>
</template>

<script>
export default {
data() {
return {
msg1: '',
msg2: '',
}
},
}
</script>
<style>
</style>

v-model使用在其他表单元素上的原理

不同的表单元素, v-model在底层的处理机制是不一样的。比如给checkbox使用v-model

底层处理的是 checked属性和change事件。

不过咱们只需要掌握应用在文本框上的原理即可

表单类组件封装 & v-model 简化代码

1.表单类组件封装

  • 父传子:数据 应该时父组件props传递 过来的, v-model拆解绑定数据
  • 子传父:监听输入,子传父传值给父组件修改

image-20240420101931245

image-20240420101937810

2.v-model简化代码

其实就是凑value和input这两个变量名

  • 子组件中:props 通过 value 接收,事件触发 input
  • 父组件中:v-model 给组件直接绑定数据(:value + @input)

image-20240420103350723

.sycn修饰符

作用:可以实现 子组件 与 **父组件数据 ** 的 双向绑定,简化代码

特点:prop属性名,可以自定义,非固定为 value

场景:封装弹框类的基础组件,visible 属性,true显示 false隐藏

本质:就是 :属性名@update:属性名 合写

image-20240420110430553

image-20240420110554179

ref 和 $refs

作用:利用ref 和 $refs 可以用于获取 dom 元素组件实例

特点:查找范围 → 当前组件内(更精确稳定)

  • 获取dom
    • 目标标签 - 添加ref属性
      • image-20240420113017419
    • 恰当时机,通过this.$refs.xxx,获取目标标签
      • image-20240420113105006

案例1:

image-20240420113439198

image-20240420113612685

案例2:

App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<template>
<div class="app">
<h4>父组件 -- <button>获取组件实例</button></h4>
<BaseForm ref="BaseForm"></BaseForm>

<button @click="handleGet">获取数据</button>
<button @click="handleReset">重置数据</button>
</div>
</template>

<script>
import BaseForm from './components/BaseForm.vue'
export default {
components: {
BaseForm,
},
methods: {
handleGet () {
console.log(this.$refs.BaseForm.getValues())
},
handleReset () {
this.$refs.BaseForm.resetValues()
}
}
}
</script>

BaseForm.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<template>
<div class="app">
<div>
账号: <input v-model="username" type="text">
</div>
<div>
密码: <input v-model="password" type="text">
</div>
</div>
</template>

<script>
export default {
data() {
return {
username: '',
password: '',
}
},
methods: {
getValues() {
return {
username: this.username,
password: this.password
}
},
resetValues() {
this.username = ''
this.password = ''
},
}
}
</script>

效果:

获取输入框里面的值

image-20240420113737083

Vue异步更新 & $nextTick

Vue是异步更新DOM的

Vue.js是一种用于构建用户界面的渐进式 JavaScript 框架。其中一个非常重要的特性是异步更新。异步更新是指当数据发生变化时,Vue不会立即更新DOM。相反,它会在下一个“tick”或渲染循环中异步执行DOM更新。这种机制可以提高性能,减少不必要的操作。

1
当我们直接修改 Vue 实例的数据时,Vue 会在内部将数据更新操作放入一个异步队列中,而不是立即进行更新。

案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 当点击编辑按钮时,输入框显示 并且自动获取焦点
<template>
<div class="app">
<!-- 编辑状态 -->
<div v-if="isShowEdit">
<input type="text" v-model="editValue" ref="inp" />
<button>确认</button>
</div>

<!-- 默认状态 -->
<div v-else>
<span>"{ title }"</span>
<button @click="handleAppearance">编辑</button>
</div>
</div>
</template>

<script>
export default {
data() {
return {
title: '大标题',
isShowEdit: false,
editValue: '',
}
},
mehods: {
handleAppearance() {
// 显示输入框 (Vue异步更新的)
this.isShowEdit = true
// this.$refs.inp.focus() 直接这么写 是不能获取焦点的 因为Vue是异步更新的,而$nextTick 可以实现同步更新
// 获取焦点 ($nextTick 等dom渲染完毕后 立即执行)
this.$nextTick(() => {
this.$refs.inp.focus()
})
}
}
}
</script>

$nextTick

$nextTick:等DOM更新后,才会触发执行此方法里的函数体

语法:this.$nextTick(函数体)

1
2
3
4
5
6
someDataProperty = newValue; // 异步更新

this.$nextTick(() => {
// 在更新操作完成后执行回调函数
// 可以获取最新的数据状态
});
1
对于那些依赖于 Vue 更新的 DOM 操作,我们需要使用 `$nextTick` 方法来确保在DOM更新完成后执行操作。

自定义指令

简介

自己定义的指令:可以定义的一些指令,可以封装一些 dom 操作,扩展额外功能

  • 在需要绑定的标签上写上自定义的指令

    • image-20240421102351808
  • 全局注册 - 语法

    • 在main.js中注册
      • image-20240421102218477
  • 局部注册 - 语法

    • 在app.vue中注册
      • image-20240421102316638

自定义指令 - 指令的值

需求:实现一个color指令 - 传入不同的颜色,给标签设置文字颜色

  • 语法:在绑定指令时,可以通过 “等号” 的形式 为指令绑定 具体的参数值 v-指令名= "指令值"
    • image-20240421104209131
  • 而后通过 binding.value 可以拿到指令值,指令值修改会触发update函数
1
注意:inserted函数 是当元素添加到页面中时才会触发,如果已经添加到页面中,再去修改属性值 是不会触发的 这个时候 要用到一个update函数

image-20240421104436281

自定义指令 - 封装v-loading指令

效果:当我们去请求数据时,页面可能会空白一段时间,我们想要在空白的这段时间内 让他显示加载的动画

  • 实现步骤

    • image-20240421111012155

    • image-20240421111145791

插槽

插槽 - 默认插槽

作用:让组件内部的一些 结构 支持 自定义

场景:当组内某一部分结构不确定,想要自定义时。

需求:要在页面中显示一个对话框,封装成一个组件

问题:组件的内部部分,不希望写死,希望能使用的时候自定义。怎么办?

image-20240421115110618

插槽基本语法:

  1. 组件内需要定制的结构部分,改用占位
  2. 使用组件时,标签内部,传入结构替代slot

案例:

image-20240421115716517

image-20240421115722869

image-20240421115726763

插槽 - 后备插槽

插槽后备内容:封装组件时,可以为预留的 <slot> 插槽提供后备内容(默认内容)

  • 语法:在 标签内,放置内容,作为默认显示内容
  • 效果:
    • 外部使用组件时,步传东西,则slot会显示后备内容
    • 外部使用组件时,传东西了,则slot整体会被换掉
      • 我是内容

image-20240421120721410

插槽 - 具名插槽

组件内 有多处不确定的结构 怎么办?

具名插槽

  • slot占位,给name属性起名字来区分
  • template配合 v-slot:插槽名 分发内容v-slot:插槽名 可以简化成什么?
    • #插槽名

image-20240421122052310

插槽 - 作用域插槽

作用域插槽:定义slot插槽的同时,是可以传值的。给插槽上可以绑定数据,将来 使用组件时可以使用

场景:封装表格组件

  1. 子传父,动态渲染表格内容
  2. 利用默认插槽,定制操作列
  3. 删除或查看都需要用到当前项的id,属于组件内部的数据通过作用域插槽传值绑定,进而使用

image-20240421160300672

image-20240421160240117

作用域插槽的作用:可以给插槽上绑定数据,供将来使用组件时使用

作用域插槽使用步骤?

  • 给slot标签,以添加属性的方式传值
    • image-20240421160527128
  • 所有属性都会被收集到一个对象中
    • image-20240421160535688
  • template中,通过 #插槽名= "obj" 接收
    • image-20240421160545873

路由

简介

什么是路由?

路由是一种映射关系

Vue中的路由是什么?

路径和组件的映射关系

根据路由就能知道不同路径的,应该匹配渲染哪个组件

VueRouter的使用(5+2)

  • 5个基础步骤(固定)
    1. 下载:下载VueRouter模块到工程中
      • vue2 → vueRouter3 → Vuex3 vue4 → vueRouter4 → Vuex4
      • image-20240422111024686
    2. 引入
      • image-20240422111041771
    3. 安装注册
      • image-20240422111058438
    4. 创建路由对象
      • image-20240422111110375
    5. 注入,将路由对象注入到new Vue实例中,建立关联
      • image-20240422111133017
  • 2个核心步骤
    1. 创建需要的组件(放在views目录下),配置路由规则
      • Find.vue My.vue Friend.vue
      • image-20240422112132161
    2. 配置导航,配置路由出口(路径匹配的组件显示的位置)
      • image-20240422112213300

Vue组件的分类

  1. 组件分类有哪几类? 分类的目的是什么?
    • 页面组件 和 分类组件 便于维护
  2. 放在什么文件夹?作用分别是什么?
    • 页面组件 - views文件夹 => 配合路由,页面展示
    • 复用组件 - components文件夹 => 封装复用

路由的封装抽离

问题:所有的路由配置都堆在main.js中合适么?

目标:将路由模块抽离出来。好处:拆分模块,利于维护

  1. 创建router/index.js文件
    • 将main.js中路由的配置 剪贴到index.js
    • image-20240422143533462
  2. 在main.js中引入router
    • image-20240422143436011

声明式导航 - 导航链接

需求:实现导航高亮效果

Vue-router 提供了一个全局组件 router-link (取代a标签)

  • 能跳转,配置 to 属性执行路径(必须)。本质还是 a 标签, to无需 #
  • 能高亮,默认就会提供高亮类名,可以直接设置高亮样式
1
2
3
<router-link to="/find">发现音乐</router-link>
<router-link to="/my">我的音乐</router-link>
<router-link to="/friend">朋友</router-link>

声明式导航 - 两个类名

说明:我们发现 router-link 自动给当前导航添加了两个高亮类名

  • router-link-active 模糊匹配(用的多)
    • to=”/my” 可以匹配 /my /my/a /my/b ….
  • router-link-exact-active 精确匹配
    • to=”/my” 尽可以匹配 /my

如何自定义router-link 的两个高亮类名?

  • linkActiveClass 模糊匹配 类名自定义
  • linkExactActiveClass 精确匹配 类名自定义

声明式导航 - 跳转传参

  • 查询参数查询(多个参数)
    • 路由
      • image-20240422155413600
    • 跳转:to="/path?参数名=值"
      • image-20240422155050008
    • 接收:$route.query.参数名
      • image-20240422155142353
  • 动态参数查询(简洁优雅)
    • 路由:/path/:参数名
      • image-20240422155244854
    • 跳转:to="/path/值"
      • image-20240422155200504
    • 接收:$route.params.参数名
      • image-20240422155210918

动态参数查询有一个问题:当我们不通过传参的方式访问搜索页 而是直接访问搜索页时,会发现 没有任何页面

image-20240422155930937

原因:/search/:words 表示,必须要传参数。如果不传参数,也希望匹配,可以加一个可选符 “?”

image-20240422160108022

image-20240422160120338

Vue路由 - 重定向

问题:网页打开,url默认是 / 路径,未匹配到组件时,会出现空白

说明:重定向 → 匹配path后,强制跳转path路径

语法:{path: 匹配路径, redirect: 重定向到的路径}

image-20240422160707625

image-20240422160647127

Vue路由-404

作用:当路径找不到匹配时,给个提示页面

位置:配在路由最后

语法:path: "*" (任意路径) - 前面不匹配就命中最后这个

image-20240422162333727

Vue路由 - 模式设置

问题:路由的路径看起来不自然,有#,能都切成真正路径形式?

image-20240422162624077

Vue路由 - 基本跳转

问题:点击按钮跳转如何实现

两种语法:

  • path 路径跳转(简单方便) 注意这里是 $router 不是 $route
    • image-20240423153004901
  • name 命名路由跳转(适合path超长的场景)
    • image-20240423153406895
    • image-20240423153152450

Vue路由 - 两种跳转方式传参

  • path 路径跳转带参数
    • 简写方式
      • image-20240423160230082
      • image-20240423160238246
    • 完整写法(适合传参时,使用)
      • image-20240423160435212
      • image-20240423160442688
    • name 命名路径跳转带参数
      • image-20240423161131934
      • 对应的如果是params 则是 $route.query.参数名
      • 对应的如果是query 则是 $route.params.参数名 注意:这里的参数名是配置动态路径参数时写的:参数名

总结:

  • image-20240423161645115
  • image-20240423161703948
1
路径短用path 路径长用name

Vue路由 - 子路由(嵌套路由)

  • 在children属性中,配置属性
    • image-20240423195103501
  • 配置路由出口
    • image-20240423194955155

面经项目

参考D:/vscode/Vue/vue-mianJ-projiect文件

image-20240423162529145

组件缓存

当我通过路由跳转到其他页面时,这个页面会被销毁,再次返回的时候会被重新加载 这个时候可以用一个数据缓存

  • keep-alive 是什么?
    • Vue的内置组件,包裹动态组件时,可以缓存
  • keep-alive的优点
    • 组件切换过程中,把切换出去的组件保留在内存中(提升性能)
  • keep-alive的三个属性(了解)
    • include:组件名数组,只有匹配的组件会被缓存
    • exclude:组件名数组,任何匹配的组件都不会被缓存
    • max:最多可以缓存多少组件实例
  • keep-alive的使用会触发两个生命周期函数(了解) 当组件被缓存时,created,mounted函数就不会执行了
    • activated 当组件被激活(使用)的时候触发 → 进入页面触发
    • deactivated 当组件不被使用的时候触发 → 离开页面触发

Vuex

简介

目标:明确vuex 是什么?应用场景,优势

  1. 是什么?

    • vuex 是一个vue的状态管理工具 (状态就是数据)
    • 大白话:vuex是一个插件,可以帮我们管理 vue 通用的数据 (多组间共享的数据)
  2. 场景:

    • 某个状态在 很多个组件 来使用(个人信息)
    • 多个组件共同维护一份数据(购物车)
  3. 优势

    • 共同维护一份数据,数据集中化管理
    • 响应式变化
    • 操作简洁(vuex提供了一些辅助函数)

vuex 的使用 - 创建仓库

68321278417

1.安装 vuex

安装vuex与vue-router类似,vuex是一个独立存在的插件,如果脚手架初始化没有选 vuex,就需要额外安装。

1
yarn add vuex@3 或者 npm i vuex@3

2.新建 store/index.js 专门存放 vuex

​ 为了维护项目目录的整洁,在src目录下新建一个store目录其下放置一个index.js文件。 (和 router/index.js 类似)

68321280582

3.创建仓库 store/index.js

1
2
3
4
5
6
7
8
9
10
11
12
// 导入 vue
import Vue from 'vue'
// 导入 vuex
import Vuex from 'vuex'
// vuex也是vue的插件, 需要use一下, 进行插件的安装初始化
Vue.use(Vuex)

// 创建仓库 store
const store = new Vuex.Store()

// 导出仓库
export default store

4 在 main.js 中导入挂载到 Vue 实例上

1
2
3
4
5
6
7
8
9
10
import Vue from 'vue'
import App from './App.vue'
import store from './store'

Vue.config.productionTip = false

new Vue({
render: h => h(App),
store
}).$mount('#app')

此刻起, 就成功创建了一个 空仓库!!

5.测试打印Vuex

App.vue

1
2
3
created(){
console.log(this.$store)
}

核心概念 - state状态

目标:明确如何给仓库 提供 数据,如何 使用 仓库的数据

image-20240424145605209

使用数据:

  • 通过store直接访问
    • 模板中:”{ $store.state.xxx }”
    • 组件逻辑中:this.$store.state.xxx
    • JS模块中:store.state.xxx
  • 通过辅助函数(简化)
    • 导入mapState
      • image-20240424150816193
    • 封装到computed属性中
      • image-20240424150832149
    • 直接调用属性名
      • image-20240424150906678

核心概念 - mutations

vuex同样遵循单行数据流,组件中不能直接修改仓库的数据

掌握mutations对象,对象中存放修改state的方法

  • 定义mutations对象,对象中存放修改state的方法
    • image-20240424152950268
  • 组件中提交调用mutations
    • image-20240424153031490

mutation传参

目标:掌握mutations传参语法

提交mutation是可以传递参数的 this.$store.commit('xxx', 参数)

  • 提供mutation 函数 (带参数 - 提交载荷 payload)
    • image-20240424155414155
  • 页面中提交调用 mutation
    • image-20240424155446162

注意:

  • 所有mutation函数,第一个参数,都是state
  • mutation参数有且只有一个,state除外,如果需要多个参数,包装成一个对象
    • image-20240424155638070
    • image-20240424155652632

案例:

目标:实时输入,实施更新

image-20240424162014664

image-20240424162019320

  • 输入框内容渲染
    • image-20240424162131956
  • 监听输入获取内容
    • image-20240424162347473
  • 封装mutation处理函数
    • image-20240424162230980
  • 调用传参
    • image-20240424162354835

辅助函数:mapMutations

mapMutations 和 mapState 很像,它是把位于mutations中的方法提取了出来,映射到组件methods中

  • 在mutation创建方法
    • image-20240424165023840
  • 导入mapMutation的包 在需要用到的组件中 只需要写左边
    • image-20240424165445012
    • image-20240424165110169
  • 直接调用
    • image-20240425132514363