vue速查
目录
- 目录
- vue 语法
- 组件
- 样式
- vue3 中其他新特性
- vue2 中已过时特性
Table of contents generated with markdown-toc
vue 语法
定义响应式变量
响应式数据原理,参见
下面都是vue3的
ref()
支持所有类型,官方也推荐用ref来创建响应式数据
const foo = ref('bar') |
reactive()
只能接受对象作为参数,返回的代理对象不能解构,解构就丢了响应式
const foo = reactive({bar: 'bar'}) |
如果给reactive传入一个ref变量,会自动解包
const count = ref(0) |
下面是vue2
<script> |
插值语法
语法:解析标签体的内容。 写法:{{xxx}}(类似Mustache模板语法,但解析用vue自己的解析器)xxx为变量、单个表达式,会直接读取vue对象下的data属性中的值
<h3>foo,{{name}}</h3> |
指令语法(属性绑定)
语法:用于解析标签(包括:标签属性、标签体内容、绑定事件…..) 写法:v-bind:href="xxx"或简写为 :href="xxx"(xxx同样要写单个表达式、变量)
<a v-bind:href="school.url.toUpperCase()" x="hello">点我去{{school.name}}学习1</a> |
v-bind、v-model
- v-bind:单向数据绑定
- v-model:双向数据绑定
<!-- 单向数据绑定: --> |
input、textarea
v-bind绑定需要自己手动处理input事件,v-model则不需要
select、input[type=”radio|checkbox”]
v-bind要手动处理change事件,v-model则不需要
<input type="radio" value="A" v-model="picked" /> A |
可见灵活使用v-model是多么的方便
v-model原理
很简单,就是v-bind+处理事件
<input type="text" v-model="name"/> |
组件的v-model
<!-- vue3 --> |
在子组件中接收可以使用defineModel()宏定义,就不需要使用defineProps和defineEmits来处理绑定的变量和值变化时的处理方法
// 指定默认值 |
使用也很简单,defineModel返回一个ref变量,直接使用.value
const model = defineModel({ default: 1 }) |
vue2中,需要定义model属性,只支持配置一个子组件v-model绑定,不支持vue3中的多个
Vue.component('my-checkbox', { |
修饰符
修饰符可以修饰绑定指令、事件指令
.trim:去除输入的空格的,’a bc‘ => ‘abc‘.number:自动转换输入的数据为float,如果不能转换的数据会原模原样的输出.lazy:触发onChange事件,不触发onInput事件,表现结果如下<input type="text" v-model="testfoo" />
如果加上
.lazy<input type="text" v-model.lazy="testfoo" />
只会在最后失焦或者回车,不是触发
change事件的时候去更新值.sync:简化绑定在子组件上的数据的双向更新<!-- 子组件 -->
<template>
<div>
<input @input="updateTitle" :value="title" />
</div>
</template>
<script>
export default {
props: ['title'],
methods: {
updateTitle(event) {
this.$emit('update:title', event.target.value);
}
}
}
</script><!-- 父组件 -->
<template>
<child-component :title.sync="docTitle" />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
data() {
return {
docTitle: 'Initial Title'
};
}
}
</script>父组件不需要再提供一个事件绑定到子组件上,子组件也不需要在
docTitle数据变化的时候去触发绑定到自己身上的自定义事件。而是直接触发update:title事件即可完成子组件对绑定到自身值(docTitle)的更新,为了方便不写@update:title="val => docTitle = val"这么一坨,用这个.sync修饰符
v-on
使用v-on:xxx或者@xxx绑定事件,xxx是事件名称
<!-- 内联事件处理器 --> |
PS. 注意:@click="demo" 和 @click="demo(参数1, 参数2, $event)" 效果一致,但后者可以传参
如果绑定的方法事件处理为闭包,要注意
<button @click="foo()">Add 1</button> |
理论上想让其触发foo方法返回的那个箭头函数,但实际上触发的还是foo函数。也就是控制台打印的为foo
因为vue会认为你调用这个函数想往里传递自己的参数,而不是先执行这个函数
拿到返回的函数再作为click事件传递给组件,让组件触发。如果碰到既需要默认参数,又需要自定义参数,就得在外面包装一层,外面接受默认参数,里头放自定义参数
组件自定义事件
组件自定义事件就是放到组件标签身上的事件,而不是一般的html标签所使用的事件 可以实现子组件向父组件传递数据
绑定事件
以下都为vue2写法,vue3同理
- 第一种方法(属性绑定):
<!-- 通过父组件给子组件传递函数类型的props实现:子给父传递数据 --> |
- 第二种方法(事件绑定):
<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第一种写法,使用@或v-on) --> |
使用ref
<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种写法,使用ref) --> |
解绑事件
this.$off
this.$off('atguigu') //解绑一个自定义事件 |
注意:销毁后$destory所有的组件的自定义事件都无效了
事件修饰符
- prevent:阻止默认事件(常用)
- stop:阻止事件冒泡(常用)
- once:事件只触发一次(常用)
- capture:使用事件的捕获模式
- self: 只有
event.target是当前操作的元素时才触发事件 - passive:事件的默认行为立即执行,无需等待事件回调执行完毕
键盘事件
vue中的键盘按键别名:
- 回车 => enter
- 删除 => delete (捕获“删除”和“退格”键)
- 退出 => esc
- 空格 => space
- 换行 => tab (特殊,必须配合keydown去使用)
- 上 => up
- 下 => down
- 左 => left
- 右 => right
系统修饰键(用法特殊):ctrl、alt、shift、meta
事件绑定:@keyup和@keydown
- 配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发
- 配合keydown使用:正常触发事件
注意:
- Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名)
Vue.config.keyCodes.自定义键名 = 键码,可以去定制按键别名- 也可以使用keyCode去指定具体的按键(不推荐)
<input type="text" placeholder="按下回车提示输入" @keydown.huiche="showInfo"> |
v-if、v-for
v-if
条件渲染(动态控制节点是否存存在)v-if、v-else、v-else-if、v-show
v-for
可遍历数组、对象
<!-- const myObject = reactive({ |
老生常谈,为何不建议用索引值作为v-for列表项的key
在DOM更新时,双端比对、快速比对,都需要比对两个列表(新虚拟DOM列表,旧虚拟DOM列表)。如果列表出现了插入新增,删除列表项,旧虚拟DOM中原本没发生任何变化的节点会因为前方插入了新的节点导致自身索引改变,那么两个算法对比时,相同索引值对应的两个节点就发生了变化
例如. [1, 2, 3, 4]代表旧节点,在‘3’之前插入了一个‘5’,会变成[1, 2, 5, 3, 4]。用索引值做key,索引值为2的位置(也就是’3’节点嘛)变成了‘5’节点,索引值为3的位置变成了‘3’节点,最后多出来一项,要创建一个‘4’节点
本来是一个简单的创建一个‘5’节点,插入到‘3’节点前。结果变成了,修改‘3’节点为‘5’,修改‘4’节点为‘3’,最后再创建一个‘4’节点,这不妥妥增加计算、渲染开销嘛
所以,用一个不变值做Id就很重要
其他指令
v-text
- 作用:向其所在的节点中渲染文本内容。
- 与插值语法的区别:v-text会替换掉节点中的内容,则不会。
<div v-text="name"></div> |
v-html
- 作用:向指定节点中渲染包含html结构的内容。
- 与插值语法的区别
- v-html会替换掉节点中所有的内容,则不会。
- v-html可以识别html结构。
<div v-html="name"></div> |
注意:有安全性问题,错误使用会导致XSS攻击 v-cloak指令(没有值):
- 本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
- 使用css配合
v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。
<h2 v-cloak>{{name}}</h2> |
v-once
- v-once所在节点在初次动态渲染后,就视为静态内容了。
- 以后数据的改变不会引起
v-once所在结构的更新,可以用于优化性能。
<h2 v-once>{{name}}</h2> |
v-pre
- 跳过其所在节点的编译过程。
- 可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。
<h2 v-pre>{{name}}</h2> |
自定义指令
语法:在vue实例中添加配置对象directives,之后在里面添加自定义函数
// vue3 模板内指令 |
element和binding分别指的是什么:
- element(vue3为el):使用自定义指令的DOM
- binding:一个对象,里面包含指令接收的参数名字,参数值等信息
- vnode:底层虚拟DOM
指令钩子 vue2 vs vue3
| Vue 2 钩子 | Vue 3 对应钩子 | 说明 |
|---|---|---|
bind |
created |
指令第一次绑定到元素时调用 |
inserted |
mounted |
元素插入父节点时调用 |
update |
beforeUpdate + updated |
所在组件VNode 更新时调用,Vue 3 拆成前后两个阶段,beforeUpdate绑定元素的父组件更新前调用,updated在绑定元素的父组件及他自己的所有子节点都更新后调用 |
componentUpdated |
updated |
组件和子组件更新完成后调用 |
unbind |
unmounted |
指令与元素解绑时调用 |
| ❌ 无 | beforeMount / beforeUnmount |
Vue 3 新增,更精细的 |
注意:
指令定义时不加v-,但使用时要加v-
directives里面的this指向window(vue2)全局指令(类似于过滤器)
// vue3 |
计算属性
可以用已定义的响应式数据做简单处理得到一个新的响应式数据,这个响应式对象是带有缓存的,会缓存计算的结果(类似React useMemo(),不完全是)
<!-- vue3 --> |
简写
// vue3 |
PS. 注意
上面的fullName计算属性自己提供了setter,所以可以直接使用fullName.value = 'foo'这种形式去改变的,但如果使用简写形式的计算属性,不可以更改计算属性返回的对象,vue会给出警告⚠️
compute 原理
vue3.3和之后的版本多加了一层优化
如何判断compute数据要更新(也就是compute内提供的回调何时执行)
- 要读取
compute定义的响应式数据 - 内部要标记
compute定义的数据为脏数据(初始化compute时为脏数据,compute内部依赖的响应式数据变化时为脏数据)
两个vue版本的有何不同
优化在哪?优化在需要读取 compute定义的数据的地方多加了一层逻辑,先执行一次 compute回调,内部获取到新的值,之后判断是否是脏数据
watch
监听一个响应式数据(普通数据也能监听,但非响应式数据不会依赖收集,没意义),变化时执行注册的回调。不会自动执行,是惰性函数
vue2和vue3的响应式原理不同,参见
// vue3 |
watchEffect()
仅vue3支持,接收一个回调函数,自动收集回调中的响应式依赖,并自动执行。会在setup执行完毕后执行一次,非惰性函数
cleanup清理函数
watchEffect((onCleanup) => { |
停止监听
const unwatch = watchEffect(() => {}) |
vue中的复用逻辑
Composition Api 组合式函数
vue3中有状态逻辑的函数(主要用于逻辑复用、代码组织)类似于一个纯逻辑的组件,没有模版template标签。⚠️但不是只有<script>标签的组件,不会经过组件编译器去解析标签等有这种复杂的开销
实例:
// useFetch示例 封装fetch useFetch.js |
<!-- 在其他的组件中使用 --> |
在组合式函数中,可以使用vue的钩子,可以让组合式函数挂靠到对应组件的钩子上面去执行。
接收参数:接收的参数可以是一个ref响应式的值,也可以是一个普通的值。里面对响应式的值使用unref做了处理(响应式值只返回value,普通值原样返回)
返回值:返回值是一个普通的对象,不是响应式对象。可以在使用时,用reactive包裹自定义hook,返回的对象中的ref会自动解包,如果使用了响应式的值使用了解构就会破坏原有值的响应式
PS. 注意
mixin混入本质是把一堆代码flat扁平化展开成同级的,而组合式函数实现了逻辑隔离,不会耦合代码
mixin混入
vue2和3都支持,vue3中不推荐使用,有composition api了
混合属性,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项
// 定义一个混入对象 |
- 属性重名:会覆盖,优先使用组件身上的配置对象
- 重名:组件的和混入对象配置的都会执行,执行顺序vue2为组件先,mixin后,vue3反过来
全局混入
通过Vue.mixin()API创建,每一个组件都会自动使用到这个混入器。全局mixin都是先执行的
// 为自定义的选项 'myOption' 注入一个处理器。 |
插件
通常用来为 Vue 添加全局功能(增强功能),比如组件库,vue-route,vuex等,也是一种代码复用方式
// vue3 |
ref引用
引用,和react的ref差不多,都是为了避免原生的DOM操作,给子组件注册引用信息。 普通的html标签上的ref指向的是这个DOM元素,普通的组件的ref属性指向的这个组件的实例对象
<ChildComponent ref="childComponent" /> |
nextTick
会在DOM更新结束后,下一轮的微任务队列中执行。这么做目的就是能确保DOM是最新的,这里涉及一点事件循环机制
vue3的用法和vue2有点差异,且nextTick默认返回一个Promise,可以await,vue2会根据环境自动调整是否使用Promise
// vue3 |
组件
SFC(Single-File Component)单文件组件,一般是一个.vue结尾的文件,里面至少要有如下三个标签
<script><template><style>
这里还有一些限制,只能有一个<template>、可以同时有<script setup> <script>这两个标签,但不能同时写两个<script>标签。可以有多个<style>,会在编译模版时合并
注册组件
全局注册
// vue3 |
局部注册
// vue3 直接在使用的组件中引入即可 |
vue2 组件实例原型链
关系:vue构造->vue组件->vue实例
//vue构造 |
这三者之间类似于继承 重要的内置关系:
VueComponent.prototype.__proto__ === Vue.prototype |
上面一行代码的图片解释
为什么要这么做?
让组件实例对象(vc)可以访问到 Vue原型上的属性、方法
组件通信
props属性
类似react的props属性,都是接受父组件传递的值。接收的方式有下面的三种
// vue3 setup() |
但是,传入子组件的prop属性,都是直接放到了子组件的身上,但是没有放到_data下。可以直接使用this.xx来使用。react中是放到了组件的props属性下,使用的时候要this.props.xxx
Provide、inject
组件间的通信方式(适合祖孙组件、跨级组件之间的的通信)
// root组件 |
setup(props,context){ |
模版
占位标签template
和react的Fragment标签一致,vue中如下功能
- 作为单文件组件最外层标签
- 插槽模版标签
- 列表渲染、条件渲染也可以在
template标签上使用v-for、v-if。标签不会渲染成真实dom,可以增加代码可读性,使代码结构清晰
vue3 <script setup>
<script setup>以下简称setup
<script setup> |
在setup中,定义的变量、方法是默认导出的,且支持下面三种宏定义
defineProps:定义接收的propsdefineExpose:暴漏出组件的属性、方法(外部组件通过ref引用无法直接获取引用组件内部的属性,需要此宏暴漏)defineEmits:接收父组件传入的方法defineModel:处理组件v-model绑定defineOptions:配置组件定义时的一些选项
<script setup> |
vue3 的 setup()
常规写法简称setup()函数
setup()函数签名
setup(props, { attrs, slots, emit, expose }) { |
- props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性。
- context:上下文对象
- attrs: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于
this.$attrs - slots: 收到的插槽内容, 相当于
this.$slots - emit: 分发自定义事件的函数, 相当于
this.$emit - expose:暴漏给外部组件的属性、方法
- attrs: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于
// 在普通script标签中的setup()函数写法 |
插槽
vue提供的一种模版嵌套的功能,可以在一个组件的模版中放入另一个组件的模版
PS. 注意:下面的两个属性slot和slot-scope(vue2的)已经被废弃 (vue3) 但是没有被移除,所以还是可以使用这两个属性
默认插槽
<!-- 父组件中: --> |
父组件中的Category标签里面的div就会被加入到子组件中的slot标签中
具名插槽
给slot一个属性“name” <slot name="xxx"></slot>
<!-- 父组件中: --> |
作用域插槽
可以往slot标签中传递数据,按照属性的方式传递。传递的数据会给插槽的使用者用。官方称:插槽 prop
<!-- 父组件中: --> |
PS. 有可能你会看见老vue代码中的作用域插槽中含有接收数据用属性scope或者slot-scope,这俩必须要使用template标签来接收数据,且这俩属性已经在vue2.6+后废弃
生命周期
vue3
vue2
mounted
vue完成模版解析以后,把真实DOM放到页面后调用mounted 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】
beforeDestory
vue执行销毁过程之前(马上要执行销毁操作) 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】
Destory流程 销毁组件流程
- 销毁后借助Vue开发者工具看不到任何信息。
- 销毁后自定义事件会失效,但原生DOM事件依然有效。
- 一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了。
变化的部分为:
vue2中需要先创建一个vue的实例对象(下面称之为vm)之后执行
beforeCreate和 created这两个钩子,之后会检查有没有 el配置项。vue3中则是在 createApp这个工厂函数中先行提供好vue要用的配置,比如 el等组件的卸载钩子变为:
beforeUnmount和 unmounted
vue3 和 vue2 对比生命周期
| vue2 | vue3 |
|---|---|
| beforeCreate | setup() |
| created | setup() |
| beforeMount | onBeforeMount() |
| mounted | onMounted() |
| beforeUpdate | onBeforeUpdate() |
| updated | onUpdate() |
| beforeUnmount | onBeforeUnmount() |
| unmounted | onUnmounted() |
KeepAlive
缓存组件,方便下次跳过渲染组件的流程
属性
interface KeepAliveProps { |
<!-- 以英文逗号分隔的字符串 --> |
特有的生命周期
onActivated(() => { |
样式
样式绑定
<div id="root"> |
// script setup |
scope
可以限定组件的样式范围,让其仅在当前组件中生效 (写样式很常用)
<style scoped> |
原理:在编译时,会生成特定的属性data-v-开头的标签属性,样式会根据对应标签的对应属性进行绑定
动画
Transition、TransitionGroup
<Transition>:控制单个进入、离开动画<TransitionGroup>:控制内部多个元素的进入、离开动画
过渡阶段的类名
v-enter-from:进入动画的起始状态。在元素插入之前添加,在元素插入完成后的下一帧移除。(比如文字显入的效果,文字从没显示到刚开始显示的过程)v-enter-active:进入动画的生效状态。应用于整个进入动画阶段。在元素被插入之前添加,在过渡或动画完成之后移除。这个 class 可以被用来定义进入动画的持续时间、延迟与速度曲线类型。(还是上面的效果,文字刚开始显示到动画执行完毕的这个过程)v-enter-to:进入动画的结束状态。在元素插入完成后的下一帧被添加 (也就是 v-enter-from 被移除的同时),在过渡或动画完成之后移除。(还是续着上面的效果,文字刚显示完了,动画执行完毕的这个过程)v-leave-from:离开动画的起始状态。在离开过渡效果被触发时立即添加,在一帧后被移除。(比如文字隐出的过程,文字刚开始从显示到隐藏的过程)v-leave-active:离开动画的生效状态。应用于整个离开动画阶段。在离开过渡效果被触发时立即添加,在过渡或动画完成之后移除。这个 class 可以被用来定义离开动画的持续时间、延迟与速度曲线类型。(文字刚开始隐藏到完全隐藏的过程)v-leave-to:离开动画的结束状态。在一个离开动画被触发后的下一帧被添加 (也就是 v-leave-from 被移除的同时),在过渡或动画完成之后移除。(文字刚完全隐藏到动画执行完的过程)
触发时机
- v-if、v-show切换,条件渲染
<component :is=""></component>动态组件加载- 标签的
key属性改变
Transition
<Transition> |
.v-enter-active, |
TransitionGroup
主要针对v-for渲染的列表中元素的动画
<TransitionGroup name="list" tag="ul"> |
过渡动画中类名的变化
| vue2 | vue3 |
|---|---|
| v-enter | v-enter-from |
| v-leave | v-leave-from |
vue3 中其他新特性
toRef、toRefs
创建一个 ref 对象,其value值指向另一个对象中的某个属性。 语法:const name = toRef(person,'name')
应用
要将响应式对象中的某个属性单独提供给外部使用时、reactive数据要解构时
扩展
toRefs 与toRef功能一致,但可以批量创建多个 ref 对象,语法:toRefs(person)
shallowReactive、shallowRef
浅层数据监听,对象,数组这种具有深层结构的数据仅监听最外层的属性变化,监听的数据类型看他们名字也就能类比到reactive和ref
什么时候使用?
- 如果有一个对象数据,结构比较深, 但变化时只是外层属性变化 ===> shallowReactive。
- 如果有一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换 ===> shallowRef。
readonly、shallowReadonly
readonly: 让一个响应式数据变为只读的(深只读) shallowReadonly:让一个响应式数据变为只读的(浅只读) 比如其他组件提供了一些数据,为了不产生副作用,可以使用上面的两个API
toRaw、markRaw
toRaw:- 作用:将一个由
reactive生成的响应式对象转为普通对象。 - 使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新。
- 作用:将一个由
markRaw:- 作用:标记一个对象,使其永远不会再成为响应式对象。
- 应用场景:
- 有些值不应被设置为响应式的,例如复杂的第三方类库等。
- 当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能。
customRef
自定义ref,自定义处理响应式数据的依赖跟踪和更新触发,进行显式控制
例子(便于理解)防抖效果(多次执行会刷新执行的间隔时间,间隔时间结束才能执行)
<template> |
几个工具函数
- isRef: 检查一个值是否为一个 ref 对象
- isReactive: 检查一个对象是否是由
reactive创建的响应式代理 - isReadonly: 检查一个对象是否是由
readonly创建的只读代理 - isProxy: 检查一个对象是否是由
reactive或者readonly方法创建的代理
Fragment组件:<Fragment>
和react的同名标签一个作用
Teleport组件:<Teleport></Teleport>
<teleport to="移动位置"> |
可以将组件传送到指定的位置(标签名,css选择器)
Suspend组件
作用和react的Suspend组件一样,定义一个异步加载的组件,底层为一个插槽,name="fallback"插槽的组件是保底机制,在第一个组件加载不出来时挂载到页面
import {defineAsyncComponent} from 'vue' |
<template> |
vue2 中已过时特性
过滤器
模板中使用数据的再处理,或格式化
<!-- 过滤器实现 --> |
语法
- 注册过滤器:
Vue.filter(name,callback)或new Vue{filters:{}} - 使用过滤器:
{{ xxx | 过滤器名}}或v-bind:属性 = "xxx | 过滤器名"
注意
- 过滤器也可以接收额外参数、多个过滤器也可以串联
- 并没有改变原本的数据, 是产生新的对应的数据
- vue3中已经放弃此写法
自定义事件总线(用于任意组件通信)
new Vue({ |
其实是利用了vm.$on、vm.$once和vm.$emit,监听自定义事件,注册回调用于接收数据







