概念:Vue (读音 /vju?/,类似于 view) 是一套 **构建用户界面 ** 的 渐进式 框架
Vue2官网:https://v2.cn.vuejs.org/
1.1.1.什么是构建用户界面
基于数据渲染出用户可以看到的界面
1.1.2.什么是渐进式
所谓渐进式就是循序渐进,不一定非得把Vue中的所有API都学完才能开发Vue,可以学一点开发一点
Vue的两种开发方式:
-
Vue核心包开发
场景:局部模块改造
-
Vue核心包&Vue插件&工程化
场景:整站开发
1.1.3.什么是框架
所谓框架:就是一套完整的解决方案
举个栗子
如果把一个完整的项目比喻为一个装修好的房子,那么框架就是一个毛坯房。
我们只需要在“毛坯房”的基础上,增加功能代码即可。
提到框架,不得不提一下库。
- 库,类似工具箱,是一堆方法的集合,比如 axios、lodash、echarts等
- 框架,是一套完整的解决方案,实现了大部分功能,我们只需要按照一定的规则去编码即可。
下图是 库 和 框架的对比。
框架的特点:有一套必须让开发者遵守的规则或者约束
我们已经知道了Vue框架可以 基于数据帮助我们渲染出用户界面,那应该怎么做呢?
比如就上面这个数据,基于提供好的msg 怎么渲染后右侧可展示的数据呢?
核心步骤(4步):
- 准备容器
- 引包(官网) — 开发版本/生产版本
- 创建Vue实例 new Vue()
- 指定配置项,渲染数据
- el:指定挂载点
- data提供数据
1.2.1.插值表达式 {{}}
插值表达式是一种Vue的模板语法
我们可以用插值表达式渲染出Vue提供的数据
1.2.1.1.作用:利用表达式进行插值,渲染到页面中
表达式:是可以被求值的代码,JS引擎会讲其计算出一个结果
以下的情况都是表达式:
1.2.1.2.语法
插值表达式语法:{{ 表达式 }}
1.2.1.3.错误用法
1.3.1.什么是响应式?
? 简单理解就是数据变,视图对应变。
1.3.2.如何访问 和 修改 data中的数据(响应式演示)
data中的数据, 最终会被添加到实例上
① 访问数据: “实例.属性名”
② 修改数据: “实例.属性名”= “值”
- 通过谷歌应用商店安装(国外网站)
- 极简插件下载(推荐) https://chrome.zzzmh.cn/index
安装步骤:
安装之后可以F12后看到多一个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 开发中最基础、最常用、最简单的知识点。
内容渲染指令用来辅助开发者渲染 DOM 元素的文本内容。常用的内容渲染指令有如下2 个:
-
v-text(类似innerText)
- 使用语法:,意思是将 uame 值渲染到 p 标签中
- 类似 innerText,使用该语法,会覆盖 p 标签原有内容
-
v-html(类似 innerHTML)
- 使用语法:,意思是将 intro 值渲染到 p 标签中
- 类似 innerHTML,使用该语法,会覆盖 p 标签原有内容
- 类似 innerHTML,使用该语法,能够将HTML标签的样式呈现出来。
代码演示:
条件判断指令,用来辅助开发者按需控制 DOM 的显示与隐藏。条件渲染指令有如下两个,分别是:
-
v-show
- 作用: 控制元素显示隐藏
- 语法: v-show = “表达式” 表达式值为 true 显示, false 隐藏
- 原理: 切换 display:none 控制显示隐藏
- 场景:频繁切换显示隐藏的场景
-
v-if
- 作用: 控制元素显示隐藏(条件渲染)
- 语法: v-if= “表达式” 表达式值 true显示, false 隐藏
- 原理: 基于条件判断,是否创建 或 移除元素节点
- 场景: 要么显示,要么隐藏,不频繁切换的场景
示例代码:
-
v-else 和 v-else-if
- 作用:辅助v-if进行判断渲染
- 语法:v-else v-else-if=“表达式”
- 需要紧接着v-if使用
示例代码:
使用Vue时,如需为DOM注册事件,及其的简单,语法如下:
- <button v-on:事件名=“内联语句”>按钮
- <button v-on:事件名=“处理函数”>按钮
- <button v-on:事件名=“处理函数(实参)”>按钮
- 简写为 @
-
内联语句
-
事件处理函数
注意:
- 事件处理函数应该写到一个跟data同级的配置项(methods)中
- methods中的函数内部的this都指向Vue实例
3.给事件处理函数传参
-
如果不传递任何参数,则方法无需加小括号;methods方法中可以直接使用 e 当做事件对象
-
如果传递了参数,则实参 表示事件对象,固定用法。
- 作用:动态设置html的标签属性 比如:src、url、title
- 语法:**v-bind:**属性名=“表达式”
- **v-bind:**可以简写成 => :
比如,有一个图片,它的 属性值,是一个图片地址。这个地址在数据 data 中存储。
则可以这样设置属性值:
- (v-bind可以省略)
Vue 提供了 v-for 列表渲染指令,用来辅助开发者基于一个数组来循环渲染一个列表结构。
v-for 指令需要使用 形式的特殊语法,其中:
- item 是数组中的每一项
- index 是每一项的索引,不需要可以省略
- arr 是被遍历的数组
此语法也可以遍历对象和数字
语法: key=“唯一值”
作用:给列表项添加的唯一标识。便于Vue进行列表项的正确排序复用。
为什么加key:Vue 的默认行为会尝试原地修改元素(就地复用)
实例代码:
注意:
- key 的值只能是字符串 或 数字类型
- key 的值必须具有唯一性
- 推荐使用 id 作为 key(唯一),不推荐使用 index 作为 key(会变化,不对应)
所谓双向绑定就是:
- 数据改变后,呈现的页面结果会更新
- 页面结果更新后,数据也会随之而变
作用 :给表单元素(input、radio、select)使用,双向绑定数据,可以快速 获取 或 设置 表单元素内容
语法:v-model=“变量”
需求:使用双向绑定实现以下需求
- 点击登录按钮获取表单中的内容
- 点击重置按钮清空表单中的内容
? 所谓指令修饰符就是通过“.”指明一些指令后缀 不同的后缀封装了不同的处理操作 —> 简化代码
1.13.1.按键修饰符
- @keyup.enter —>当点击enter键的时候才触发
代码演示:
1.13.2.v-model修饰符
- v-model.trim —>去除首位空格
- v-model.number —>转数字
1.13.3.事件修饰符
- @事件名.stop —> 阻止冒泡
- @事件名.prevent —>阻止默认行为
- @事件名.stop.prevent —>可以连用 即阻止事件冒泡也阻止默认行为
为了方便开发者进行样式控制, Vue 扩展了 v-bind 的语法,可以针对 class 类名 和 style 行内样式 进行控制 。
1.14.1.语法:
1.14.2.对象语法
当class动态绑定的是对象时,键就是类名,值就是布尔值,如果值是true,就有这个类,否则没有这个类
? 适用场景:一个类名,来回切换
1.14.3.数组语法
当class动态绑定的是数组时 → 数组中所有的类,都会添加到盒子上,本质就是一个 class 列表
使用场景:批量添加或删除类
1.14.4.代码实例
1.15.1.语法
1.15.2.代码示例1
1.15.2.代码示例2:进度条
1.16.1.讲解内容:
常见的表单元素都可以用 v-model 绑定关联 → 快速 获取 或 设置 表单元素的值
它会根据 控件类型 自动选取 正确的方法 来更新元素
1.16.2.代码准备
1.17.1.概念
基于现有的数据,计算出来的新属性。 依赖的数据变化,自动重新计算。
1.17.2.语法
- 声明在 computed 配置项中,一个计算属性对应一个函数
- 使用起来和普通属性一样使用 {{ 计算属性名}}
1.17.3.注意
- computed配置项和data配置项是同级的
- computed中的计算属性虽然是函数的写法,但他依然是个属性
- computed中的计算属性不能和data中的属性同名
- 使用computed中的计算属性和使用data中的属性是一样的用法
- computed中计算属性内部的this依然指向的是Vue实例
1.17.4.案例
比如我们可以使用计算属性实现下面这个业务场景
1.17.5.代码准备
1.18.1.computed计算属性
作用:封装了一段对于数据的处理,求得一个结果
语法:
- 写在computed配置项中
- 作为属性,直接使用
- js中使用计算属性: this.计算属性
- 模板中使用计算属性:{{计算属性}}
1.18.2.methods计算属性
作用:给Vue实例提供一个方法,调用以处理业务逻辑。
语法:
- 写在methods配置项中
- 作为方法调用
- js中调用:this.方法名()
- 模板中调用 {{方法名()}} 或者 @事件名=“方法名”
1.18.3.计算属性的优势
-
缓存特性(提升性能)
计算属性会对计算出来的结果缓存,再次使用直接读取缓存,
依赖项变化了,会自动重新计算 → 并再次缓存
-
methods没有缓存特性
-
通过代码比较
1.18.4.总结
1.computed有缓存特性,methods没有缓存
2.当一个结果依赖其他多个值时,推荐使用计算属性
3.当处理业务逻辑时,推荐使用methods方法,比如事件的处理函数
- 计算属性默认的简写,只能读取访问,不能 “修改”
- 如果要 “修改” → 需要写计算属性的完整写法
完整写法代码演示
1.20.1.作用:
? 监视数据变化,执行一些业务逻辑或异步操作
1.20.2.语法:
-
watch同样声明在跟data同级的配置项中
-
简单写法: 简单类型数据直接监视
-
完整写法:添加额外配置项
deep:true 对复杂类型进行深度监听,watch 监听器将会递归地监视对象的所有属性
immdiate:true 初始化 立刻执行一次
1.20.3.总结
watch侦听器的写法有几种?
1.简单写法
2.完整写法
Vue生命周期:就是一个Vue实例从创建 到 销毁 的整个过程。
生命周期四个阶段:① 创建 ② 挂载 ③ 更新 ④ 销毁
1.创建阶段:创建响应式数据
2.挂载阶段:渲染模板
3.更新阶段:修改数据,更新视图
4.销毁阶段:销毁Vue实例
Vue生命周期过程中,会自动运行一些函数,被称为【生命周期钩子】→ 让开发者可以在【特定阶段】运行自己的代码
1.23.1.在created中发送数据
1.23.2.在mounted中获取焦点
- 核心包传统开发模式:基于html / css / js 文件,直接引入核心包,开发 Vue。
- 工程化开发模式:基于构建工具(例如:webpack)的环境中开发Vue。
工程化开发模式优点:
提高编码效率,比如使用JS新语法、Less/Sass、Typescript等通过webpack都可以编译成浏览器识别的ES3/ES5/CSS等
工程化开发模式问题:
- webpack配置不简单
- 雷同的基础配置
- 缺乏统一的标准
为了解决以上问题,所以我们需要一个工具,生成标准化的配置
基本介绍:
Vue CLI 是Vue官方提供的一个全局命令工具
可以帮助我们快速创建一个开发Vue项目的标准化基础架子。【集成了webpack配置】
好处:
- 开箱即用,零配置
- 内置babel等工具
- 标准化的webpack配置
使用步骤:
- 全局安装(只需安装一次即可) yarn global add @vue/cli 或者 npm i @vue/cli -g
- 查看vue/cli版本: vue --version
- 创建项目架子:vue create project-name(项目名不能使用中文)
- 启动项目:yarn serve 或者 npm run serve(命令不固定,找package.json)
2.2.1.项目目录介绍
虽然脚手架中的文件有很多,目前咱们只需人事三个文件即可
- main.js 入口文件
- App.vue App根组件
- index.html 模板文件
2.2.2.运行流程
2.3.组件化开发
? 组件化:一个页面可以拆分成一个个组件,每个组件有着自己独立的结构、样式、行为。
? 好处:便于维护,利于复用 → 提升开发效率。
? 组件分类:普通组件、根组件。
? 比如:下面这个页面,可以把所有的代码都写在一个页面中,但是这样显得代码比较混乱,难易维护。咱们可以按模块进行组件划分
2.4.根组件 App.vue
2.4.1.根组件介绍
整个应用最上层的组件,包裹所有普通小组件
2.4.2.组件是由三部分构成
-
语法高亮插件
-
三部分构成
- template:结构 (有且只能一个根元素)
- script: js逻辑
- style: 样式 (可支持less,需要装包)
-
让组件支持less
(1) style标签,lang=“less” 开启less功能
(2) 装包: yarn add less less-loader -D 或者npm i less less-loader -D
2.5.1.特点:
只能在注册的组件内使用
2.5.2.步骤:
- 创建.vue文件(三个组成部分)
- 在使用的组件内先导入再注册,最后使用
2.5.3.使用方式:
当成html标签使用即可 <组件名></组件名>
2.5.4.注意:
组件名规范 —> 大驼峰命名法, 如 HmHeader
2.5.5.语法:
2.5.6.案例练习
在App组件中,完成以下练习。在App.vue中使用组件的方式完成下面布局
components/HmHeader.vue
components/HmMain.vue
components/HmFooter.vue
App.vue
2.6.1.特点:
全局注册的组件,在项目的任何组件中都能使用
2.6.2.步骤
- 创建.vue组件(三个组成部分)
- main.js中进行全局注册
2.6.3.使用方式
当成HTML标签直接使用
<组件名></组件名>
2.6.4.注意
组件名规范 —> 大驼峰命名法, 如 HmHeader
2.6.5.语法
Vue.component(‘组件名’, 组件对象)
例:
2.6.6.案例练习
在以下3个局部组件中是展示一个通用按钮
components/HmButton.vue
components/HmHeader.vue
components/HmMain.vue
components/HmFooter.vue
App.vue
main.js
2.7.1.默认情况
写在组件中的样式会 全局生效 → 因此很容易造成多个组件之间的样式冲突问题。
-
全局样式: 默认组件中的样式会作用到全局,任何一个组件中都会受到此样式的影响
-
局部样式: 可以给组件加上scoped 属性,可以让样式只作用于当前组件
2.7.2.代码演示
baseOne.vue
baseTwo.vue
App.vue
2.7.3.scoped原理
- 当前组件内标签都被添加data-v-hash值 的属性
- css选择器都被添加 [data-v-hash值] 的属性选择器
最终效果: 必须是当前组件的元素, 才会有这个自定义属性, 才会被这个样式作用到
2.8.1.data为什么要写成函数
一个组件的 data 选项必须是一个函数。目的是为了:保证每个组件实例,维护独立的一份数据对象。
每次创建新的组件实例,都会新执行一次data 函数,得到一个新对象。
2.8.2.代码演示
baseCount.vue
App.vue
2.9.1.什么是组件通信?
组件通信,就是指组件与组件之间的数据传递
- 组件的数据是独立的,无法直接访问其他组件的数据。
- 想使用其他组件的数据,就需要组件通信
2.9.2.组件之间如何通信
2.9.3.组件关系分类
- 父子关系
- 非父子关系
2.9.4.通信解决方案
2.9.5.父子通信流程
- 父组件通过 props 将数据传递给子组件
- 子组件利用 $emit 通知父组件修改更新
2.9.6.父向子通信代码示例
父组件通过props将数据传递给子组件
父组件App.vue
子组件Son.vue
父向子传值步骤
- 给子组件以添加属性的方式传值
- 子组件内部通过props接收
- 模板中直接使用 props接收的值
2.9.7.子向父通信代码示例
子组件利用 $emit 通知父组件,进行修改更新
子向父传值步骤
- $emit触发事件,给父组件发送消息通知
- 父组件监听$emit触发的事件
- 提供处理函数,在函数的性参中获取传过来的参数
2.10.1.Props 定义
组件上 注册的一些 自定义属性
2.10.2.Props 作用
向子组件传递数据
2.10.3.特点
- 可以 传递 任意数量 的prop
- 可以 传递 任意类型 的prop
2.10.4.代码演示
父组件App.vue
子组件UserInfo.vue
2.11.1.作用
为组件的 prop 指定验证要求,不符合要求,控制台就会有错误提示 → 帮助开发者,快速发现错误
2.11.2.语法
- 类型校验
- 非空校验
- 默认值
- 自定义校验
2.12.3.代码演示
App.vue
baseProgress.vue
2.13.1.语法
2.13.2.代码实例
2.13.3.注意
1.default和required一般不同时写(因为当时必填项时,肯定是有值的)
2.default后面如果是简单类型的值,可以直接写默认。如果是复杂类型的值,则需要以函数的形式return一个默认值
2.14.1.共同点
都可以给组件提供数据
2.14.2.区别
- data 的数据是自己的 → 随便改
- prop 的数据是外部的 → 不能直接改,要遵循 单向数据流
2.14.3.单向数据流:
父级props 的数据更新,会向下流动,影响子组件。这个数据流动是单向的
2.14.4.代码演示
App.vue
baseCount.vue
2.14.5.口诀
谁的数据谁负责
2.15.1.作用
非父子组件之间,进行简易消息传递。(复杂场景→ Vuex)
2.15.2.步骤
-
创建一个都能访问的事件总线 (空Vue实例)
-
A组件(接受方),监听Bus的 $on事件
-
B组件(发送方),触发Bus的$emit事件
2.15.3.代码示例
EventBus.js
baseA.vue(接受方)
baseB.vue(发送方)
baseC.vue(接受方)
App.vue
2.16.1.作用
跨层级共享数据
2.16.2.场景
2.16.3.语法
- 父组件 provide提供数据
2.子/孙组件 inject获取数据
2.16.4.代码演示
GrandSon.vue
SonA.vue
SonB.vue
App.vue
2.16.5.注意
- provide提供的简单类型的数据不是响应式的,复杂类型数据是响应式。(推荐提供复杂类型数据)
- 子/孙组件通过inject获取的数据,不能在自身组件内修改
2.17.1.原理:
v-model本质上是一个语法糖。例如应用在输入框上,就是value属性 和 input事件 的合写
2.17.2.作用:
提供数据的双向绑定
- 数据变,视图跟着变 :value
- 视图变,数据跟着变 @input
2.17.3.注意
$event 用于在模板中,获取事件的形参
2.17.4.代码示例
2.17.5.v-model使用在其他表单元素上的原理
不同的表单元素, v-model在底层的处理机制是不一样的。比如给checkbox使用v-model
底层处理的是 checked属性和change事件。
2.18.1.需求目标
实现子组件和父组件数据的双向绑定 (实现App.vue中的selectId和子组件选中的数据进行双向绑定)
2.18.2.代码演示
App.vue
baseSelect.vue
2.19.1.目标:
父组件通过v-model 简化代码,实现子组件和父组件数据 双向绑定
2.19.2.如何简化:
v-model其实就是 :value和@input事件的简写
- 子组件:props通过value接收数据,事件触发 input
- 父组件:v-model直接绑定数据
2.19.3.代码示例
baseSelect.vue
App.vue
2.20.1.作用
可以实现 子组件 与 父组件数据 的 双向绑定,简化代码
简单理解:子组件可以修改父组件传过来的props值
2.20.2.场景
封装弹框类的基础组件, visible属性 true显示 false隐藏
2.20.3.本质
.sync修饰符 就是 :属性名 和 @update:属性名 合写
2.20.4.语法
父组件
子组件
2.20.5.代码示例
App.vue
baseDialog.vue
2.21.1.作用
利用ref 和 $refs 可以用于 获取 dom 元素 或 组件实例
2.22.2.特点:
查找范围 → 当前组件内(更精确稳定)
2.22.3.语法
1.给要获取的盒子添加ref属性
2.获取时通过 $refs获取 this.$refs.chartRef 获取
2.22.4.注意
之前只用document.querySelect(‘.box’) 获取的是整个页面中的盒子
2.22.5.代码示例
App.vue
baseChart.vue
2.23.1.需求
编辑标题, 编辑框自动聚焦
- 点击编辑,显示编辑框
- 让编辑框,立刻获取焦点
2.23.2.代码实现
2.23.3.问题
“显示之后”,立刻获取焦点是不能成功的!
原因:Vue 是异步更新DOM (提升性能)
2.23.4.解决方案
$nextTick:等 DOM更新后,才会触发执行此方法里的函数体
语法: this.$nextTick(函数体)
注意:$nextTick 内的函数体 一定是箭头函数,这样才能让函数内部的this指向Vue实例
2.24.1.作用
让组件内部的一些 结构 支持 自定义
2.24.2.需求
将需要多次显示的对话框,封装成一个组件
2.24.3.问题
组件的内容部分,不希望写死,希望能使用的时候自定义。怎么办
2.24.4.插槽的基本语法
- 组件内需要定制的结构部分,改用slot占位
- 使用组件时, MyDialog标签内部, 传入结构替换slot
- 给插槽传入内容时,可以传入纯文本、html标签、组件
2.24.5.代码示例
MyDialog.vue
App.vue
2.25.1.问题
通过插槽完成了内容的定制,传什么显示什么, 但是如果不传,则是空白
能否给插槽设置 默认显示内容 呢?
2.25.2.插槽的后备内容
封装组件时,可以为预留的 插槽提供后备内容(默认内容)。
2.25.3.语法
在 标签内,放置内容, 作为默认显示内容
2.25.4.效果
- 外部使用组件时,不传东西,则slot会显示后备内容
- 外部使用组件时,传东西了,则slot整体会被换掉
2.25.5.代码示例
App.vue
2.26.1.需求
一个组件内有多处结构,需要外部传入标签,进行定制
上面的弹框中有三处不同,但是默认插槽只能定制一个位置,这时候怎么办呢?
2.26.2.具名插槽语法
- 多个slot使用name属性区分名字
- template配合v-slot:名字来分发对应标签
app.vue
2.26.3.v-slot的简写
v-slot写起来太长,vue给我们提供一个简单写法 v-slot —> #
2.27.1.插槽分类
-
默认插槽
-
具名插槽
插槽只有两种,作用域插槽不属于插槽的一种分类
2.27.2.作用
定义slot 插槽的同时, 是可以传值的。给 插槽 上可以 绑定数据,将来 使用组件时可以用
2.27.3.场景
封装表格组件
2.27.4.使用步骤
-
给 slot 标签, 以 添加属性的方式传值
-
所有添加的属性, 都会被收集到一个对象中
-
在template中, 通过 接收,默认插槽名为 default
2.27.5.代码示例
MyTable.vue
App.vue
2.28.1.概念
单页应用程序:SPA【Single Page Application】是指所有的功能都在一个html页面上实现
2.28.2.具体示例
单页应用网站: 网易云音乐 https://music.163.com/
多页应用网站:京东 https://jd.com/
2.28.3.单页应用 VS 多页面应用
单页应用类网站:系统类网站 / 内部网站 / 文档类网站 / 移动端站点
多页应用类网站:公司官网 / 电商类网站
2.29.1.思考
单页面应用程序,之所以开发效率高,性能好,用户体验好
最大的原因就是:页面按需更新
比如当点击【发现音乐】和【关注】时,只是更新下面部分内容,对于头部是不更新的
要按需更新,首先就需要明确:访问路径和 组件的对应关系!
访问路径 和 组件的对应关系如何确定呢? 路由
2.29.2.路由的介绍
生活中的路由:设备和ip的映射关系
Vue中的路由:路径和组件的映射关系
2.30.1.目标
认识插件 VueRouter,掌握 VueRouter 的基本使用步骤
2.30.2.作用
修改地址栏路径时,切换显示匹配的组件
2.30.3.说明
Vue 官方的一个路由插件,是一个第三方包
2.30.4.官网
https://v3.router.vuejs.org/zh/
2.30.5.VueRouter的使用(5+2)
固定5个固定的步骤(不用死背,熟能生巧)
-
下载 VueRouter 模块到当前工程,版本3.6.5
-
main.js中引入VueRouter
-
安装注册
-
创建路由对象
-
注入,将路由对象注入到new Vue实例中,建立关联
当我们配置完以上5步之后 就可以看到浏览器地址栏中的路由 变成了 /#/的形式。表示项目的路由已经被Vue-Router管理了
2.30.6.代码示例
main.js
2.30.7.两个核心步骤
-
创建需要的组件 (views目录),配置路由规则
-
配置导航,配置路由出口(路径匹配的组件显示的位置)
App.vue
注意: .vue文件 本质无区别
2.31.1.组件分类
.vue文件分为2类,都是 .vue文件(本质无区别)
- 页面组件 (配置路由规则时使用的组件)
- 复用组件(多个组件中都使用到的组件)
2.31.2.存放目录
分类开来的目的就是为了 更易维护
-
src/views文件夹
页面组件 - 页面展示 - 配合路由用
-
src/components文件夹
复用组件 - 展示数据 - 常用于复用
将路由模块抽离出来。
好处:拆分模块,利于维护
路径简写:
脚手架环境下 @指代src目录,可以用于快速引入组件
2.33.1.需求
实现导航高亮效果
如果使用a标签进行跳转的话,需要给当前跳转的导航加样式,同时要移除上一个a标签的样式,太麻烦!!!
2.33.2.解决方案
vue-router 提供了一个全局组件 router-link (取代 a 标签)
- 能跳转,配置 to 属性指定路径(必须) 。本质还是 a 标签 ,to 无需 #
- 能高亮,默认就会提供高亮类名,可以直接设置高亮样式
语法: 发现音乐
2.33.3.通过router-link自带的两个样式进行高亮
使用router-link跳转后,我们发现。当前点击的链接默认加了两个class的值 和
我们可以给任意一个class属性添加高亮样式即可实现功能
当我们使用跳转时,自动给当前导航加了两个类名
2.34.1.router-link-active
模糊匹配(用的多)
to=“/my” 可以匹配 /my /my/a /my/b …
只要是以/my开头的路径 都可以和 to="/my"匹配到
2.34.2.router-link-exact-active
精确匹配
to=“/my” 仅可以匹配 /my
2.35.1.问题
router-link的两个高亮类名 太长了,我们希望能定制怎么办
2.35.2.解决方案
我们可以在创建路由对象时,额外配置两个配置项即可。 和
2.35.3.代码演示
2.36.1.目标
在跳转路由时,进行传参
比如:现在我们在搜索页点击了热门搜索链接,跳转到详情页,需要把点击的内容带到详情页,改怎么办呢?
2.36.2.跳转传参
我们可以通过两种方式,在跳转的时候把所需要的参数传到其他页面中
- 查询参数传参
- 动态路由传参
2.36.3.查询参数传参
-
传参:
< router-link to=“/path?参数名=值”>< /router-link>
-
接受参数:
固定用法:$router.query.参数名
2.36.4.代码演示
App.vue
Home.vue
Search.vue
router/index.js
main.js
2.37.1.动态路由传参方式
-
配置动态路由
动态路由后面的参数可以随便起名,但要有语义
-
配置导航链接
to=“/path/参数值”
-
对应页面组件接受参数
$route.params.参数名
params后面的参数名要和动态路由配置的参数保持一致
2.37.2.查询参数传参 VS 动态路由传参
-
查询参数传参 (比较适合传多个参数)
- 跳转:to=“/path?参数名=值&参数名2=值”
- 获取:$route.query.参数名
-
动态路由传参 (优雅简洁,传单个参数比较方便)
- 配置动态路由:path: “/path/:参数名”
- 跳转:to=“/path/参数值”
- 获取:$route.params.参数名
注意:动态路由也可以传多个参数,但一般只传一个
2.37.3.总结
声明式导航跳转时, 有几种方式传值给路由页面?
- 查询参数传参(多个参数)
- 动态路由传参(一个参数,优雅简洁)
2.38.1.问题
配了路由 path:“/search/:words” 为什么按下面步骤操作,会未匹配到组件,显示空白?
2.38.2.原因
/search/:words 表示,必须要传参数。如果不传参数,也希望匹配,可以加个可选符"?"
2.39.1.问题
网页打开时, url 默认是 / 路径,未匹配到组件时,会出现空白
2.39.2.解决方案
重定向 → 匹配 / 后, 强制跳转 /home 路径
2.39.3.语法
2.39.4.代码演示
2.40.1.作用
当路径找不到匹配时,给个提示页面
2.40.2.位置
404的路由,虽然配置在任何一个位置都可以,但一般都配置在其他路由规则的最后面
2.40.3.语法
path: “*” (任意路径) – 前面不匹配就命中最后这个
2.40.4.代码示例
NotFound.vue
router/index.js
2.41.1.问题
路由的路径看起来不自然, 有#,能否切成真正路径形式?
- hash路由(默认) 例如: http://localhost:8080/#/home
- history路由(常用) 例如: http://localhost:8080/home (以后上线需要服务器端支持,开发环境webpack给规避掉了history模式的问题)
2.41.2.语法
2.42.1.问题
点击按钮跳转如何实现?
2.42.2.方案
编程式导航:用JS代码来进行跳转
2.42.3.语法
两种语法:
- path 路径跳转 (简易方便)
- name 命名路由跳转 (适合 path 路径长的场景)
2.42.4.path路径跳转语法
特点:简易方便
2.42.5.name命名路由跳转
特点:适合 path 路径长的场景
语法:
-
路由规则,必须配置name配置项
-
通过name来进行跳转
2.43.1.问题
点击搜索按钮,跳转需要把文本框中输入的内容传到下一个页面如何实现?
2.43.2.两种传参方式
1.查询参数
2.动态路由传参
2.43.3.传参
两种跳转方式,对于两种传参方式都支持:
① path 路径跳转传参
② name 命名路由跳转传参
2.43.4.path路径跳转传参(query传参)
接受参数的方式依然是:$route.query.参数名
2.43…5.path路径跳转传参(动态路由传参)
接受参数的方式依然是:$route.params.参数值
**注意:**path不能配合params使用
2.44.1.name 命名路由跳转传参 (query传参)
2.44.2.name 命名路由跳转传参 (动态路由传参)
2.44.3.总结
1.path路径跳转
-
query传参
-
动态路由传参
2.name命名路由跳转
-
query传参
-
动态路由传参 (需要配动态路由)
1.安装脚手架 (已安装)
2.创建项目
- 选项
- 手动选择功能
- 选择vue的版本
- 是否使用history模式
- 选择css预处理
- 选择eslint的风格 (eslint 代码规范的检验工具,检验代码是否符合规范)
- 比如:const age = 18; => 报错!多加了分号!后面有工具,一保存,全部格式化成最规范的样子
- 选择校验的时机 (直接回车)
- 选择配置文件的生成方式 (直接回车)
- 是否保存预设,下次直接使用? => 不保存,输入 N
-
等待安装,项目初始化完成
-
启动项目
代码规范:一套写代码的约定规则。例如:赋值符号的左右是否需要空格?一句结束是否是要加;?…
没有规矩不成方圆
ESLint:是一个代码检查工具,用来检查你的代码是否符合指定的规则(你和你的团队可以自行约定一套规则)。在创建项目时,我们使用的是 Javascript Standard Style 代码风格的规则。
2.46.1.Javascript Standard Style 规范说明
建议把:https://standardjs.com/rules-zhcn.html 看一遍,然后在写的时候, 遇到错误就查询解决。
下面是这份规则中的一小部分:
- 字符串使用单引号 – 需要转义的地方除外
- 无分号 – 这没什么不好。不骗你!
- 关键字后加空格
- 函数名后加空格
- 坚持使用全等 摒弃 一但在需要检查 时可以使用
- …
2.46.2.代码规范错误
如果你的代码不符合standard的要求,eslint会跳出来刀子嘴,豆腐心地提示你。
下面我们在main.js中随意做一些改动:添加一些空行,空格。
按下保存代码之后:
你将会看在控制台中输出如下错误:
eslint 是来帮助你的。心态要好,有错,就改。
2.46.3.手动修正
根据错误提示来一项一项手动修正。
如果你不认识命令行中的语法报错是什么意思,你可以根据错误代码(func-call-spacing, space-in-parens,…)去 ESLint 规则列表中查找其具体含义。
打开 ESLint 规则表,使用页面搜索(Ctrl + F)这个代码,查找对该规则的一个释义。
- eslint会自动高亮错误显示
- 通过配置,eslint会自动帮助我们修复错误
-
如何安装
-
如何配置
- 注意:eslint的配置文件必须在根目录下,这个插件才能才能生效。打开项目必须以根目录打开,一次打开一个项目
- 注意:使用了eslint校验之后,把vscode带的那些格式化工具全禁用了 Beatify
settings.json 参考
目标:明确Vuex是什么,应用场景以及优势
2.48.1.是什么
Vuex 是一个 Vue 的 状态管理工具,状态就是数据。
大白话:Vuex 是一个插件,可以帮我们管理 Vue 通用的数据 (多组件共享的数据)。例如:购物车数据 个人信息数
2.48.2.使用场景
- 某个状态 在 很多个组件 来使用 (个人信息)
- 多个组件 共同维护 一份数据 (购物车)
2.48.3.优势
- 共同维护一份数据,数据集中化管理
- 响应式变化
- 操作简洁 (vuex提供了一些辅助函数)
2.48.4.注意:
官方原文:
- 不是所有的场景都适用于vuex,只有在必要的时候才使用vuex
- 使用了vuex之后,会附加更多的框架中的概念进来,增加了项目的复杂度 (数据的操作更便捷,数据的流动更清晰)
Vuex就像《近视眼镜》, 你自然会知道什么时候需要用它~
目标:基于脚手架创建项目,构建 vuex 多组件数据共享环境
效果是三个组件共享一份数据:
- 任意一个组件都可以修改数据
- 三个组件的数据是同步的
2.49.1.创建项目
2.49.2.创建三个组件, 目录如下
2.49.3.源代码如下
在入口组件中引入 Son1 和 Son2 这两个子组件
2.50.1.安装 vuex
安装vuex与vue-router类似,vuex是一个独立存在的插件,如果脚手架初始化没有选 vuex,就需要额外安装。
2.50.2.新建 专门存放 vuex
?为了维护项目目录的整洁,在src目录下新建一个store目录其下放置一个index.js文件。 (和 类似)
2.50.3.创建仓库
2.50.4 在 main.js 中导入挂载到 Vue 实例上
此刻起, 就成功创建了一个 空仓库!!
2.50.5.测试打印Vuex
App.vue
2.51.1.目标
明确如何给仓库 提供 数据,如何 使用 仓库的数据
2.51.2.提供数据
State提供唯一的公共数据源,所有共享的数据都要统一放到Store中的State中存储。
打开项目中的store.js文件,在state对象中可以添加我们要共享的数据。
2.51.3.访问Vuex中的数据
问题: 如何在组件中获取count?
- 通过$store直接访问 —> {{ $store.state.count }}
- 通过辅助函数mapState 映射计算属性 —> {{ count }}
2.51.4.通过$store访问的语法
2.51.5.代码实现
2.51.5.1模板中使用
组件中可以使用 $store 获取到vuex中的store对象实例,可通过state属性属性获取count, 如下
2.51.5.2组件逻辑中使用
将state属性定义在计算属性中 https://vuex.vuejs.org/zh/guide/state.html
2.51.5.3 js文件中使用
每次都像这样一个个的提供计算属性, 太麻烦了,我们有没有简单的语法帮我们获取state中的值呢?
mapState是辅助函数,帮助我们把store中的数据映射到 组件的计算属性中, 它属于一种方便的用法
用法 :
2.52.1.第一步:导入mapState (mapState是vuex中的一个函数)
2.52.2.第二步:采用数组形式引入state属性
上面代码的最终得到的是 类似于
2.52.3.第三步:利用展开运算符将导出的状态映射给计算属性
2.53.1.目标
明确 vuex 同样遵循单向数据流,组件中不能直接修改仓库的数据
2.53.2.直接在组件中修改Vuex中state的值
Son1.vue
2.53.3.开启严格模式
通过 可以开启严格模式,开启严格模式后,直接修改state中的值会报错
state数据的修改只能通过mutations,并且mutations必须是同步的
2.54.1.定义mutations
2.54.2.格式说明
mutations是一个对象,对象中存放修改state的方法
2.54.3.组件中提交 mutations
2.54.4
.总结
通过mutations修改state的步骤
1.定义 mutations 对象,对象中存放修改 state 的方法
2.组件中提交调用 mutations(通过$store.commit(‘mutations的方法名’))
2.55.1.目标:
掌握 mutations 传参语法
2.55.2.语法
看下面这个案例,每次点击不同的按钮,加的值都不同,每次都要定义不同的mutations处理吗?
提交 mutation 是可以传递参数的
2.55.2.1 提供mutation函数(带参数)
2.55.2.2 提交mutation
小tips: 提交的参数只能是一个, 如果有多个参数要传, 可以传递一个对象
2.56.1.步骤
2.56.2.代码实现
Son2.vue
store/index.js
2.57.1.目标
实时输入,实时更新,巩固 mutations 传参语法
2.57.2.实现步骤
2.57.3.代码实现
App.vue
store/index.js
mapMutations和mapState很像,它把位于mutations中的方法提取了出来,我们可以将它导入
上面代码的含义是将mutations的方法导入了methods中,等价于
此时,就可以直接通过this.addCount调用了
但是请注意: Vuex中mutations中要求不能写异步代码,如果有异步的ajax请求,应该放置在actions中
state是存放数据的,mutations是同步更新数据 (便于监测数据的变化, 更新视图等, 方便于调试工具查看变化),
actions则负责进行异步操作
说明:mutations必须是同步的
需求: 一秒钟之后, 要给一个数 去修改state
2.59.1.定义actions
2.59.2.组件中通过dispatch调用
1.目标:掌握辅助函数 mapActions,映射方法
mapActions 是把位于 actions中的方法提取了出来,映射到组件methods中
Son2.vue
直接通过 this.方法 就可以调用
除了state之外,有时我们还需要从state中筛选出符合条件的一些数据,这些数据是依赖state的,此时会用到getters
例如,state中定义了list,为1-10的数组,
组件中,需要显示所有大于5的数据,正常的方式,是需要list在组件中进行再一步的处理,但是getters可以帮助我们实现它
2.61.1.定义getters
2.61.2.使用getters
2.61.2.1原始方式-$store
2.61.2.2辅助函数 - mapGetters
2.63.1.目标
掌握核心概念 module 模块的创建
2.63.2.问题
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
这句话的意思是,如果把所有的状态都放在state中,当项目变得越来越大的时候,Vuex会变得越来越难以维护
由此,又有了Vuex的模块化
2.63.3.模块定义 - 准备 state
定义两个模块 user 和 setting
user中管理用户的信息状态 userInfo
setting中管理项目应用的 主题色 theme,描述 desc,
在文件中的modules配置项中,注册这两个模块
使用模块中的数据, 可以直接通过模块名访问 =>
也可以通过 mapState 映射
2.64.1.目标:
掌握模块中 state 的访问语法
尽管已经分模块了,但其实子模块的状态,还是会挂到根级别的 state 中,属性名就是模块名
2.64.2.使用模块中的数据
- 直接通过模块名访问 $store.state.模块名.xxx
- 通过 mapState 映射:
- 默认根级别的映射 mapState([ ‘xxx’ ])
- 子模块的映射 :mapState(‘模块名’, [‘xxx’]) - 需要开启命名空间 namespaced:true
3.代码示例
$store直接访问
mapState辅助函数访问
2.65.1.目标:
掌握模块中 getters 的访问语
2.65.2.语法:
使用模块中 getters 中的数据:
- 直接通过模块名访问
- 通过 mapGetters 映射
- 默认根级别的映射
- 子模块的映射 - 需要开启命名空间
2.65.3.代码演示
Son1.vue 直接访问getters
Son2.vue 通过命名空间访问
2.66.1.目标:
掌握模块中 mutation 的调用语法
2.66.2.注意:
默认模块中的 mutation 和 actions 会被挂载到全局,需要开启命名空间,才会挂载到子模块。
2.66.3.调用方式:
- 直接通过 store 调用 $store.commit('模块名/xxx ', 额外参数)
- 通过 mapMutations 映射
- 默认根级别的映射 mapMutations([ ‘xxx’ ])
- 子模块的映射 mapMutations(‘模块名’, [‘xxx’]) - 需要开启命名空间
2.66.4.代码实现
Son1.vue
Son2.vue
2.67.1.目标:
掌握模块中 action 的调用语法 (同理 - 直接类比 mutation 即可)
2.67.2.注意:
默认模块中的 mutation 和 actions 会被挂载到全局,需要开启命名空间,才会挂载到子模块。
2.67.3.调用语法:
- 直接通过 store 调用 $store.dispatch('模块名/xxx ', 额外参数)
- 通过 mapActions 映射
- 默认根级别的映射 mapActions([ ‘xxx’ ])
- 子模块的映射 mapActions(‘模块名’, [‘xxx’]) - 需要开启命名空间
2.67.4.代码实现
需求:
Son1.vue 直接通过store调用
Son2.vue mapActions映射
2.68.1.直接使用
- state --> $store.state.模块名.数据项名
- getters --> $store.getters[‘模块名/属性名’]
- mutations --> $store.commit(‘模块名/方法名’, 其他参数)
- actions --> $store.dispatch(‘模块名/方法名’, 其他参数)
2.68.2.借助辅助方法使用
1.import { mapXxxx, mapXxx } from ‘vuex’
computed、methods: {
? // …mapState、…mapGetters放computed中;
? // …mapMutations、…mapActions放methods中;
? …mapXxxx(‘模块名’, [‘数据项|方法’]),
? …mapXxxx(‘模块名’, { 新的名字: 原来的名字 }),
}
2.组件中直接使用 属性 或 方法
特点:
- 代码量变少
- 分散式维护变成集中式维护
3.3.1. 认识create-vue
create-vue是Vue官方新的脚手架工具,底层切换到了 vite (下一代前端工具链),为开发提供极速响应
3.3.2. 使用create-vue创建项目
前置条件 - 已安装16.0或更高版本的Node.js
执行如下命令,这一指令将会安装并执行 create-vue
3.3.3.熟悉项目和关键文件
3.4.1. setup选项的写法和执行时机
写法
执行时机
在beforeCreate钩子之前执行
3.4.2. setup中写代码的特点
在setup函数中写的数据和方法需要在末尾以对象的方式return,才能给模版使用
3.4.3.
script标签添加 setup标记,不需要再写导出语句,默认会添加导出语句
3.5.1. reactive
接受对象类型数据的参数传入并返回一个响应式的对象
3.5.2. ref
接收简单类型或者对象类型的数据传入并返回一个响应式的对象
3.5.3. reactive 对比 ref
- 都是用来生成响应式数据
- 不同点
- reactive不能处理简单类型的数据
- ref参数类型支持更好,但是必须通过.value做访问修改
- ref函数内部的实现依赖于reactive函数
- 在实际工作中的推荐
- 推荐使用ref函数,减少记忆负担,小兔鲜项目都使用ref
计算属性基本思想和Vue2保持一致,组合式API下的计算属性只是修改了API写法
侦听一个或者多个数据的变化,数据变化时执行回调函数,俩个额外参数 immediate控制立刻执行,deep开启深度侦听
3.7.1. 侦听单个数据
3.7.2. 侦听多个数据
侦听多个数据,第一个参数可以改写成数组的写法
3.7.3. immediate
在侦听器创建时立即出发回调,响应式数据变化之后继续执行回调
3.7.4. deep
通过watch监听的ref对象默认是浅层侦听的,直接修改嵌套的对象属性不会触发回调执行,需要开启deep
3.8.1. 选项式对比组合式
3.8.2. 生命周期函数基本使用
- 导入生命周期函数
- 执行生命周期函数,传入回调
3.8.3. 执行多次
生命周期函数执行多次的时候,会按照顺序依次执行
3.9.1. 父传子
基本思想
- 父组件中给子组件绑定属性
- 子组件内部通过props选项接收数据
3.9.2. 子传父
基本思想
- 父组件中给子组件标签通过@绑定事件
- 子组件内部通过 emit 方法触发事件
概念:通过 ref标识 获取真实的 dom对象或者组件实例对象
3.10.1. 基本使用
实现步骤:
- 调用ref函数生成一个ref对象
- 通过ref标识绑定ref对象到标签
3.10.2. defineExpose
默认情况下在
3.11.1. 作用和场景
顶层组件向任意的底层组件传递数据和方法,实现跨层组件通信
3.11. 2. 跨层传递普通数据
实现步骤
- 顶层组件通过 函数提供数据
- 底层组件通过 函数提供数据
3.11. 3. 跨层传递响应式数据
在调用provide函数时,第二个参数设置为ref对象
3.11. 4. 跨层传递方法
顶层组件可以向底层组件传递方法,底层组件调用方法修改顶层组件的数据
背景说明:
有 script setup 之前,如果要定义 props, emits 可以轻而易举地添加一个与 setup 平级的属性。
但是用了 script setup 后,就没法这么干了 setup 属性已经没有了,自然无法添加与其平级的属性。
为了解决这一问题,引入了 defineProps 与 defineEmits 这两个宏。但这只解决了 props 与 emits 这两个属性。
如果我们要定义组件的 name 或其他自定义的属性,还是得回到最原始的用法——再添加一个普通的 script 标签。
这样就会存在两个 script 标签。让人无法接受。
所以在 Vue 3.3 中新引入了 defineOptions 宏。顾名思义,主要是用来定义 Options API 的选项。可以用 defineOptions 定义任意的选项, props, emits, expose, slots 除外(因为这些可以使用 defineXXX 来做到)
在Vue3中,自定义组件上使用v-model, 相当于传递一个modelValue属性,同时触发 update:modelValue 事件
我们需要先定义 props,再定义 emits 。其中有许多重复的代码。如果需要修改此值,还需要手动调用 emit 函数。
于是乎 defineModel 诞生了。
生效需要配置 vite.config.js
3.14.1. 什么是Pinia
Pinia 是 Vue 的专属的最新状态管理库 ,是 Vuex 状态管理工具的替代品
3.14.2. 手动添加Pinia到Vue项目
后面在实际开发项目的时候,Pinia可以在项目创建时自动添加,现在我们初次学习,从零开始:
- 使用 Vite 创建一个空的 Vue3项目
- 按照官方文档安装 pinia 到项目中
3.14.3. Pinia基础使用
- 定义store
- 组件使用store
3.14.4. getters实现
Pinia中的 getters 直接使用 computed函数 进行模拟, 组件中需要使用需要把 getters return出去
3.14 5. action异步实现
方式:异步action函数的写法和组件中获取异步数据的写法完全一致
-
接口地址:http://geek.itheima.net/v1_0/channels
-
请求方式:get
-
请求参数:无
需求:在Pinia中获取频道列表数据并把数据渲染App组件的模板中
3.14 6. storeToRefs工具函数
使用storeToRefs函数可以辅助保持数据(state + getter)的响应式解构
3.14 7. Pinia的调试
Vue官方的 dev-tools 调试工具 对 Pinia直接支持,可以直接进行调试
3.14 8. Pinia持久化插件
官方文档:https://prazdevs.github.io/pinia-plugin-persistedstate/zh/
- 安装插件 pinia-plugin-persistedstate
- 使用 main.js
- 配置 store/counter.js
- 其他配置,看官网文档即可