一、vue简介
Vue (读音 /vjuː/,类似于 view) 是一套 构建用户界面 的 渐进式 框架
什么是构建用户界面:基于数据渲染用户看到的界面
什么是渐进式:也就是循序渐进,不一定要学习vue中的所有API学完才能开发Vue,可以学一点开发一点
二、Vue中的常用指令
概念: 指令(Directives)是 Vue 提供的带有 v- 前缀 的 特殊 标签属性。使用指令可以帮助我们提高操作dom的效率。
(一)、内容渲染指令
内容渲染指令用来辅助开发者渲染 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标签的样式呈现出来。
(二)、条件渲染指令
条件判断指令,用来辅助开发者按需控制 DOM 的显示与隐藏。条件渲染指令有如下两个,分别是
-
v-show
-
作用: 控制元素显示隐藏
-
语法: v-show = "表达式" 表达式值为 true 显示, false 隐藏
-
原理: 切换 display:none 控制显示隐藏
-
场景:频繁切换显示隐藏的场景
-
-
v-if
-
作用: 控制元素显示隐藏(条件渲染)
-
语法: v-if= "表达式" 表达式值 true显示, false 隐藏
-
原理: 基于条件判断,是否创建 或 移除元素节点
-
场景: 要么显示,要么隐藏,不频繁切换的场景
-
(三)、事件绑定指令
使用Vue时,如需为DOM注册事件,及其的简单,语法如下:
-
<button v-on:事件名="内联语句">按钮</button>
-
<button v-on:事件名="处理函数">按钮</button>
-
<button v-on:事件名="处理函数(实参)">按钮</button>
事件处理函数:
- 事件处理函数应该写到一个跟data同级的配置项(methods)中
(四)、属性绑定指令
动态设置html的标签属性 比如:src、url、title
-
语法 :**v-bind:**属性名="表达式"
-
v-bind: 可以简写成 =>:
(五)、双向绑定指令
给表单元素 (input、radio、select)使用,双向绑定数据,可以快速 获取 或 设置 表单元素内容
**语法:**v-model="变量"
(六)、列表渲染指令
v-for 列表渲染指令,用来辅助开发者基于一个数组来循环渲染一个列表结构。
v-for 指令需要使用 (item, index) in arr
形式的特殊语法,其中:
-
item 是数组中的每一项
-
index 是每一项的索引,不需要可以省略
-
arr 是被遍历的数组
此语法也可以遍历对象和数字
html
//遍历对象
<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 的默认行为会尝试原地修改元素(就地复用)
-
key 的值只能是字符串 或 数字类型
-
key 的值必须具有唯一性
-
推荐使用 id 作为 key(唯一),不推荐使用 index 作为 key(会变化,不对应)
三、计算属性computed
基于现有的数据 ,计算出来的新属性 。 如果依赖 的数据变化,自动重新计算。
-
声明在 computed 配置项中,一个计算属性对应一个函数
-
使用起来和普通属性一样使用 {{ 计算属性名}}
注意:
-
computed配置项和data配置项是同级的
-
computed中的计算属性虽然是函数的写法 ,但他依然是个属性
-
computed中的计算属性不能 和data中的属性同名
-
使用computed中的计算属性和使用data中的属性是一样的用法
-
computed中计算属性内部的this 依然指向的是Vue实例
-
计算属性默认的简写,只能读取访问,不能 "修改"
完整写法:
计算属性的优势:
-
缓存特性(提升性能)
计算属性会对计算出来的结果缓存,再次使用直接读取缓存,
依赖项变化了,会自动重新计算 → 并再次缓存
-
methods没有缓存特性
四、watch侦听器(监视器)
监视数据变化,执行一些业务逻辑或异步操作
语法;简单写法
javascript
watch: {
// 该方法会在数据变化时,触发执行
数据属性名 (newValue, oldValue) {
一些业务逻辑 或 异步操作。
},
'对象.属性名' (newValue, oldValue) {
一些业务逻辑 或 异步操作。
}
完整写法:
deep:true深度监视,监视对象里的所有属性都进行一个监视
五、生命周期
Vue生命周期:就是一个Vue实例从创建 到 销毁 的整个过程。
生命周期四个阶段:① 创建 ② 挂载 ③ 更新 ④ 销毁
1.创建阶段:创建响应式数据
2.挂载阶段:渲染模板
3.更新阶段:修改数据,更新视图
4.销毁阶段:销毁Vue实例
Vue生命周期过程中,会自动运行一些函数 ,被称为【生命周期钩子 】→ 让开发者可以在【特定阶段 】运行自己的代码
-
beforeCreate
:在实例初始化之后,数据观测(data observer)和事件/watcher 设置之前被调用。 -
created
:实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:数据观测(data observer),属性和方法的运算,watch/event
事件回调。然而,挂载阶段还没开始,$el
属性目前不可见。 -
beforeMount
:在挂载开始之前被调用。相关的render
函数首次被调用。 -
mounted
:el 被新创建的vm.$el
替换,并挂载到实例上去之后调用。 -
beforeUpdate
:数据更新时调用,发生在虚拟DOM重新渲染和打补丁之前。 -
updated
:由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子。 -
beforeDestroy
:实例销毁之前调用。此时实例仍然有效。 -
destroyed
:Vue实例销毁后调用。此时所有的事件监听器会被移除,所有的子实例也会被销毁。
六、组件通信
组件通信,就是指组件与组件 之间的数据传递
-
组件的数据是独立的,无法直接访问其他组件的数据。
-
想使用其他组件的数据,就需要组件通信
(一)、父子通信
-
父组件通过 props 将数据传递给子组件
-
子组件利用 $emit 通知父组件修改更新
(二)、非父子通信
创建一个都能访问的事件总线 (空Vue实例)
javascript
import Vue from 'vue'
const Bus = new Vue()
export default Bus
A组件(接受方),监听Bus的 $on事件
javascript
created () {
Bus.$on('sendMsg', (msg) => {
this.msg = msg
})
}
B组件(发送方),触发Bus的$emit事件
javascript
Bus.$emit('sendMsg', '这是一个消息')
复杂场景使用vuex或其他状态管理工具
七、.sync修饰符
可以实现 子组件 与 父组件数据 的 双向绑定,简化代码
简单理解:子组件可以修改父组件传过来的props值
.sync修饰符 就是 :属性名 和 @update:属性名 合写
八、ref和$refs
利用ref 和 $refs 可以用于 获取 dom 元素 或 组件实例, 查找范围 → 当前组件内(更精确稳定)
语法;
- 给要获取的盒子添加ref属性
- 获取时通过 refs获取 this.refs.xxx获取
九、$nextTick
等 DOM更新后,才会触发执行此方法里的函数体
语法: this.$nextTick(函数体)
javascript
this.$nextTick(() => {
this.$refs.inp.focus()
})
$nextTick 内的函数体 一定是箭头函数,这样才能让函数内部的this指向Vue实例
十、自定义指令
自己定义的指令,可以封装一些DOM操作,扩展额外的功能
语法;
- 全局注册
javascript
//在main.js中
Vue.directive('指令名', {
"inserted" (el) {
// 可以对 el 标签,扩展额外功能
el.focus()
}
})
- 局部注册
javascript
//在Vue组件的配置项中
directives: {
"指令名": {
inserted () {
// 可以对 el 标签,扩展额外功能
el.focus()
}
}
}
-
使用指令
注意:在使用指令的时候,一定要先注册 ,再使用,否则会报错 使用指令语法: v-指令名。如:<input type="text" v-focus/>
注册 指令时不用 加v-前缀 ,但使用时 一定要加v-前缀
-
inserted:被绑定元素插入父节点时调用的钩子函数
十一、插槽
作用:让组件内部的一些 结构 支持 自定义
例如: 将需要多次显示的对话框,封装成一个组件,组件的内容部分,不希望写死 ,希望能使用的时候自定义。
插槽的默认内容:也即是插槽未传值时候的默认值,封装组件时,可以为预留的 <slot>
插槽提供后备内容(默认内容)。 在 <slot> 标签内,放置内容, 作为默认显示内容
十二、Vuex
Vuex 是一个 Vue 的 状态管理工具,状态就是数据。是 Vue.js 应用程序开发中用于状态管理的模式和库。它旨在解决在大型单页应用中,多个组件之间数据共享和状态同步的问题,使得应用的状态管理更加清晰、可维护和可预测。
大白话:Vuex 是一个插件,可以帮我们管理 Vue 通用的数据 (多组件共享的数据)。例如:购物车数据 个人信息数
(一)State
定义与作用
- State 是 Vuex 存储的中心,它包含了应用中所有组件可能需要共享的数据。可以将其看作是一个全局的数据仓库。
访问方式
- 在 Vue 组件中,可以通过
this.$store.state
来访问 State 中的数据。例如,如果 State 中有一个名为userInfo
的对象,在组件中可以这样获取:this.$store.state.userInfo
。
(二)Getter
- 概念与用途
- Getter 是基于 State 派生出来的计算属性。它可以对 State 中的数据进行加工和处理后返回结果,类似于 Vue 组件中的计算属性,但它是在 Vuex store 层面进行定义的。
- 比如,在一个博客应用中,有一个包含多篇文章的数组存储在 State 中,我们可能需要一个 Getter 来计算文章的总数,或者筛选出特定分类的文章。
- 使用方法
- 在组件中通过
this.$store.getters
来访问 Getter。假设我们有一个名为articleCount
的 Getter,在组件中可以这样使用:this.$store.getters.articleCount
。 - Getter 还可以接收其他 Getter 作为参数,实现更复杂的计算逻辑。例如,有一个 Getter 需要根据文章总数和已发布文章数计算未发布文章数,而文章总数和已发布文章数都有各自的 Getter,那么这个计算未发布文章数的 Getter 就可以接收这两个 Getter 作为参数进行计算。
- 在组件中通过
(三)Mutation
- 定义与特点
- Mutation 是更改 Vuex state 的唯一方法。它是一个对象,其中包含了多个用于修改 State 的方法,每个方法都有一个唯一的名称(type)和一个对应的函数(handler)。
- Mutation 中的函数必须是同步的,这是为了保证状态的变更可以被可预测地跟踪和调试。如果在 Mutation 中进行异步操作,可能会导致状态的变化不可控,难以调试。
- 提交方式
- 在 Vue 组件中,通过
this.$store.commit('mutationName', payload)
的方式来提交 Mutation,其中mutationName
是 Mutation 中定义的方法名,payload
是可选的参数,用于传递给 Mutation 函数进行状态修改。 - 例如,有一个名为
incrementCount
的 Mutation 用于增加 State 中count
的值,在组件中可以这样调用:this.$store.commit('incrementCount')
。如果 Mutation 函数需要接收一个参数,比如要增加指定的数值,可以这样调用:this.$store.commit('incrementCount', 5)
。
- 在 Vue 组件中,通过
(四)Action
- 作用与特点
- Action 类似于 Mutation,但它主要用于处理异步操作和包含多个 Mutation 的逻辑。Action 可以包含任意异步代码,比如发送 AJAX 请求、进行定时器操作等。
- Action 提交的是 Mutation,而不是直接修改 State。这是为了保持状态修改的一致性和可预测性,通过 Action 来协调异步操作和 Mutation 的提交。
- 使用方式
- 在 Vue 组件中,通过
this.$store.dispatch('actionName', payload)
的方式来触发 Action,其中actionName
是 Action 中定义的方法名,payload
是可选的参数,用于传递给 Action 函数。 - 例如,有一个名为
fetchData
的 Action 用于从服务器获取数据并更新 State,在组件中可以这样调用:this.$store.dispatch('fetchData')
。在 Action 函数中,可以先进行异步操作,获取数据后,再通过commit
提交相应的 Mutation 来更新 State。
- 在 Vue 组件中,通过
(五)Vuex 的工作流程
- 组件与 Vuex 的交互
- 当组件需要读取或修改共享状态时,它会通过
this.$store
与 Vuex 进行交互。 - 读取数据时,组件可以直接访问
this.$store.state
或this.$store.getters
来获取 State 中的数据或经过计算后的 Getter 值。 - 当组件需要修改状态时,它不能直接修改 State,而是要通过提交 Mutation 来实现。组件会调用
this.$store.commit('mutationName', payload)
来触发相应的 Mutation 函数,从而修改 State 中的数据。
- 当组件需要读取或修改共享状态时,它会通过
- Action 的执行过程
- 如果涉及到异步操作,组件会触发 Action。例如,当用户登录时,组件可能会 dispatch 一个名为
login
的 Action,在 Action 中会发送登录请求到服务器。 - Action 函数接收到 dispatch 的参数后,执行异步操作。在异步操作完成后,通过
commit
提交 Mutation 来更新 State。这样,状态的更新是在异步操作成功后有秩序地进行的,保证了数据的一致性和可靠性。
- 如果涉及到异步操作,组件会触发 Action。例如,当用户登录时,组件可能会 dispatch 一个名为
- 状态更新与组件响应
- 当 State 中的数据通过 Mutation 被修改后,Vuex 会自动通知所有使用了该数据的组件进行更新。
- Vue 组件的响应式系统会检测到 State 的变化,从而自动重新渲染组件,使得组件显示最新的状态数据。这是通过 Vue 的响应式原理和 Vuex 的集成实现的,确保了界面与数据的实时同步。
(六)Vuex 的使用场景
多组件共享复杂数据
- 示例:电商应用中的购物车
- 在一个电商应用中,购物车的数据需要在多个页面和组件中共享和操作。购物车可能包含商品信息、数量、总价等多个属性。
- 使用 Vuex 可以将购物车的状态集中管理在 State 中。当用户在商品列表页面将商品添加到购物车时,通过提交 Mutation 来更新购物车状态。在购物车页面和结算页面等其他组件中,都可以直接从
this.$store.state.cart
获取购物车的最新数据,而无需在各个组件之间传递数据或维护本地的购物车状态副本。
- 用户登录状态管理
- 在应用中,用户的登录状态需要在多个组件中进行判断和使用,比如显示登录用户的头像、用户名,或者根据用户是否登录来决定某些功能的显示或隐藏。
- 通过 Vuex 管理用户登录状态,可以将登录信息存储在 State 中。当用户登录成功后,提交 Mutation 更新登录状态和用户信息。在其他组件中,通过读取
this.$store.state.user.isLoggedIn
和this.$store.state.user.userInfo
等属性来判断用户状态和获取用户信息,实现全局统一的用户登录状态管理。
跨组件通信与数据同步
- 多个页面之间的数据传递
- 例如在一个新闻应用中,有一个新闻列表页面和新闻详情页面。当用户在新闻列表页面点击一篇新闻时,需要将该新闻的详细信息传递到新闻详情页面。
- 可以在 Vuex 的 State 中存储当前选中新闻的 ID 或详细信息。当用户点击新闻时,提交 Mutation 更新 State 中的相关数据。在新闻详情页面加载时,从
this.$store.state.selectedNews
获取新闻详情数据进行展示,实现了页面之间的数据同步和无缝过渡。
- 实时数据更新与多个组件响应
- 在一个在线聊天应用中,当有新消息到达时,需要实时更新多个聊天窗口和相关组件的显示。
- 可以通过 Action 从服务器接收新消息,然后提交 Mutation 更新 State 中的消息列表。由于 Vuex 的状态变化会自动通知相关组件更新,所有显示消息列表的组件都会实时显示最新的消息,保证了数据的一致性和实时性,避免了多个组件之间复杂的通信和同步逻辑。
大型应用中的状态管理架构
- 模块划分与组织
- 在大型应用中,Vuex 可以通过模块(Modules)来对状态进行划分和组织。例如,一个电商应用可以分为用户模块、商品模块、订单模块等。
- 每个模块都有自己的 State、Getter、Mutation 和 Action,并且可以进行独立的开发和维护。同时,模块之间可以通过 Vuex 的命名空间(Namespaced Modules)来避免命名冲突,实现清晰的代码结构和模块间的解耦。
- 团队协作与代码维护
- 在团队开发中,Vuex 的集中式状态管理有助于提高代码的可维护性和协作效率。不同的开发人员可以负责不同的模块,对状态的修改和操作都通过明确的 Mutation 和 Action 进行,减少了因代码混乱导致的错误和冲突。
- 对于后续的代码维护和升级,通过 Vuex 可以更清晰地了解数据的流向和状态的变化过程,方便进行调试和优化。例如,当需要对购物车的结算逻辑进行修改时,可以直接在相关的 Vuex 模块中找到对应的 Mutation 和 Action 进行修改,而无需在各个组件中查找可能涉及到购物车操作的代码片段。
(七)Vuex 的最佳实践
遵循单向数据流原则
- 严格的状态变更流程
- 始终遵循从组件触发 Action(如果有异步操作),Action 提交 Mutation,Mutation 更改 State 的流程。这样可以确保状态的变更有清晰的路径和可追溯性。
- 避免在组件中直接修改 State 或者绕过 Mutation 进行状态变更,否则会破坏 Vuex 的状态管理机制,导致状态的不可预测性和难以调试。
- 例如,在一个计数器应用中,如果组件需要增加计数器的值,应该通过
this.$store.dispatch('increment')
来触发 Action,在 Action 中如果没有异步操作,可以直接commit('incrementMutation')
提交 Mutation,而incrementMutation
函数则负责在 State 中对计数器的值进行增加操作。
- 清晰的代码结构与命名规范
- 为 Mutation 和 Action 定义清晰、有意义的名称,遵循一定的命名规范,以便于理解和维护。通常可以采用动词 + 名词的形式,比如
incrementCount
、updateUserInfo
等。 - 对于 State 中的数据结构,也应该设计得合理清晰,尽量避免过于复杂和嵌套的数据结构,以减少数据读取和修改时的复杂性。如果数据结构比较复杂,可以考虑使用模块化的方式进行组织,或者使用一些工具函数来处理数据的操作和转换。
- 为 Mutation 和 Action 定义清晰、有意义的名称,遵循一定的命名规范,以便于理解和维护。通常可以采用动词 + 名词的形式,比如
合理使用模块
- 模块划分的策略
- 根据应用的功能模块进行合理划分,每个模块应该具有相对独立的业务逻辑和数据。例如,在一个社交应用中,可以将用户相关的操作(注册、登录、个人信息修改等)划分为一个用户模块,将朋友圈的发布、点赞、评论等操作划分为一个朋友圈模块。
- 模块之间的划分要清晰,避免功能交叉和数据混乱。同时,要考虑模块的可扩展性,以便在后续开发中能够方便地添加新的功能和数据到相应的模块中。
- 模块间的通信与共享
- 当不同模块之间需要进行通信和数据共享时,可以通过 Vuex 的根 State 或者使用 Action 来进行协调。例如,在一个电商应用中,用户模块中的用户信息可能需要在订单模块中使用,这时可以在根 State 中定义一个包含用户基本信息的对象,然后在订单模块的 Action 中通过
commit
提交 Mutation 来更新订单状态时,同时可以读取根 State 中的用户信息进行相关操作。 - 对于一些通用的功能或数据,可以提取到一个公共模块中,供其他模块复用。比如,一个工具模块可以包含一些常用的日期处理函数、数据验证函数等,其他模块可以通过引入该模块并调用相应的函数来实现通用功能,提高代码的复用性和可维护性。
- 当不同模块之间需要进行通信和数据共享时,可以通过 Vuex 的根 State 或者使用 Action 来进行协调。例如,在一个电商应用中,用户模块中的用户信息可能需要在订单模块中使用,这时可以在根 State 中定义一个包含用户基本信息的对象,然后在订单模块的 Action 中通过
调试与测试
- 调试 Vuex 应用
- 在开发过程中,可以利用 Vue Devtools 来调试 Vuex 应用。Vue Devtools 可以实时查看 State 的变化、跟踪 Mutation 和 Action 的执行情况,方便快速定位问题。
- 可以在浏览器中打开开发者工具,切换到 Vue 选项卡,查看 Vuex 相关的状态和操作记录。当应用出现状态异常或数据不一致的问题时,可以通过查看 Vue Devtools 中的记录来分析是哪个环节出现了问题,比如是否有错误的 Mutation 提交或者 Action 执行异常。
- 编写测试用例
- 为 Vuex 的 Mutation 和 Action 编写单元测试用例是保证代码质量和稳定性的重要措施。可以使用 Jest、Mocha 等测试框架来编写测试代码。
- 对于 Mutation 的测试,主要验证其是否正确地修改了 State 中的数据。例如,编写一个测试用例来测试
incrementCount
Mutation 是否将 State 中的计数器值增加了 1。对于 Action 的测试,除了验证其是否正确提交了 Mutation 外,还可以模拟异步操作的情况,确保 Action 在异步操作完成后正确地更新了 State。通过编写全面的测试用例,可以在代码修改和重构时及时发现问题,保证 Vuex 状态管理的正确性和可靠性。