Vue3快速上手
提示:Vue尚硅谷笔记整理
一、使用 vue-cli 创建Vue3.0工程(js版)
官方文档:https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
## 查看@vue/cli版本,确保@vue/cli版本在4.5.0以上
vue --version
## 安装或者升级你的@vue/cli
npm install -g @vue/cli
## 创建
vue create vue_test
## 启动
cd vue_test
npm run serve
二、常用 Composition API
1. setup
理解:
Vue3.0中一个新的配置项,值为一个函数。
setup是所有Composition API(组合API)“ 表演的舞台 ”。
组件中所用到的:数据、方法等等,均要配置在setup中。
- setup函数的两种返回值:
- 若返回一个对象,则对象中的属性、方法, 在模板中均可以直接使用。(重点关注!)
若返回一个渲染函数:则可以自定义渲染内容。(了解)
- 注意点:
尽量不要与Vue2.x配置混用
- Vue2.x配置
(data、methos、computed...)
中可以访问到setup
中的属性、方法。 - 但在
setup
中不能访问到Vue2.x配置(data、methos、computed...)
。 - 如果有重名,
setup
优先。
- Vue2.x配置
setup不能是一个
async
函数,因为返回值不再是return
的对象, 而是promise
, 模板看不到return
对象中的属性。(后期也可以返回一个Promise
实例,但需要Suspense
和异步组件的配合)<template> <h1>一个人的信息</h1> <h2>姓名:{{name}}</h2> <h2>年龄:{{age}}</h2> <button @click="sayHello">说话(Vue3所配置的——sayHello)</button> </template> <script> export default { name: 'App', //此处只是测试一下setup,暂时不考虑响应式的问题。 setup(){ //数据 let name = '张三' let age = 18 let a = 200 //方法 function sayHello(){ alert(`我叫${name},我${age}岁了,你好啊!`) } //返回一个对象(常用) return { name, age, sayHello, } } } </script>
1.1 setup的两个注意点
- setup执行的时机
在
beforeCreate
之前执行一次,this
是undefined
。- setup的参数
props
:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性。attrs
: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于this.$attrs
。slots
: 收到的插槽内容, 相当于 this.$slots。emit
: 分发自定义事件的函数, 相当于 this.$emit。
context
:上下文对象
2. ref函数
1、作用: 定义一个响应式的数据
2、语法: const xxx = ref(initValue)
- 创建一个包含响应式数据的引用对象(reference对象,简称ref对象)。
- JS中操作数据:
xxx.value
- 模板中读取数据: 不需要
.value
,直接:<div>{{ xxx }}</div>
3、备注:
- 接收的数据可以是:基本类型、也可以是对象类型。
- 基本类型的数据:响应式依然是靠
Object.defineProperty()
的get
与set
完成的。
4、vue3如何通过ref属性获取元素
<template>
<div ref='box'>I am DIV</div>
</template>
<script>
import {ref,onMounted}
export default{
setup(){
let box = ref(null);
onMounted(()=>{
console.log(box.value)
});
return {box}
}
}
</script>
5、Vue3 父组件调用子组件的方法
// 父组件
<template>
<div>
父页面
<son-com ref="sonRef"/>
<button @click="handleClick">test</button>
</div>
</template>
<script>
import {
defineComponent,
ref,
} from 'vue';
export default defineComponent({
setup(){
const sonRef = ref(null);
const handleClick = () => {
sonRef.value.song();
}
return { sonRef, handleClick, }
}
})
</script>
// 子组件
<template>
<div>
子页面
</div>
</template>
<script>
import {
defineComponent
} from 'vue';
export default defineComponent({
setup(){
const song = () => alert('hello world');
return {
song, // 别忘记 return
}
}
})
</script>
<template>
<h1>一个人的信息</h1>
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<h3>工作种类:{{job.type}}</h3>
<h3>工作薪水:{{job.salary}}</h3>
<button @click="changeInfo">修改人的信息</button>
</template>
<script>
import {ref} from 'vue'
export default {
name: 'App',
setup(){
//数据
let name = ref('张三')
let age = ref(18)
let job = ref({
type:'前端工程师',
salary:'30K'
})
//方法
function changeInfo(){
// name.value = '李四'
// age.value = 48
console.log(job.value)
// job.value.type = 'UI设计师'
// job.value.salary = '60K'
// console.log(name,age)
}
//返回一个对象(常用)
return {
name,
age,
job,
changeInfo
}
}
}
</script>
3. reactive函数
- 作用: 定义一个对象类型的响应式数据(基本类型不要用它,要用ref函数)
- 语法:
const 代理对象= reactive(源对象)
接收一个对象(或数组),返回一个代理对象(Proxy的实例对象,简称proxy对象) reactive
定义的响应式数据是“深层次的”。内部基于
ES6
的Proxy
实现,通过代理对象操作源对象内部数据进行操作。<template> <h1>一个人的信息</h1> <h2>姓名:{{person.name}}</h2> <h2>年龄:{{person.age}}</h2> <h3>工作种类:{{person.job.type}}</h3> <h3>工作薪水:{{person.job.salary}}</h3> <h3>爱好:{{person.hobby}}</h3> <h3>测试的数据c:{{person.job.a.b.c}}</h3> <button @click="changeInfo">修改人的信息</button> </template> <script> import {reactive} from 'vue' export default { name: 'App', setup(){ //数据 let person = reactive({ name:'张三', age:18, job:{ type:'前端工程师', salary:'30K', a:{ b:{ c:666 } } }, hobby:['抽烟','喝酒','烫头'] }) //方法 function changeInfo(){ person.name = '李四' person.age = 48 person.job.type = 'UI设计师' person.job.salary = '60K' person.job.a.b.c = 999 person.hobby[0] = '学习' } //返回一个对象(常用) return { person, changeInfo } } } </script>
4. Vue3.0中的响应式原理
4.1 vue2.x的响应式
1、 实现原理:
- 对象类型:通过
Object.defineProperty()
对属性的读取、修改进行拦截(数据劫持)。 数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。
Object.defineProperty(data, 'count', { get () {}, set () {} })
2、 存在问题:
- 新增属性、删除属性, 界面不会更新。
- 直接通过下标修改数组, 界面不会自动更新。
模拟Vue2中实现响应式
//源数据 let person = { name:'张三', age:18 } Object.defineProperty(p,'name',{ configurable:true, get(){ //有人读取name时调用 return person.name }, set(value){ //有人修改name时调用 console.log('有人修改了name属性,我发现了,我要去更新界面!') person.name = value } }) Object.defineProperty(p,'age',{ get(){ //有人读取age时调用 return person.age }, set(value){ //有人修改age时调用 console.log('有人修改了age属性,我发现了,我要去更新界面!') person.age = value } })
4.2 Vue3.0的响应式
1、实现原理:
- 通过
Proxy
(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。 - 通过
Reflect
(反射): 对源对象的属性进行操作。 MDN文档中描述的
Proxy
与Reflect
:
2、模拟Vue3中实现响应式
//源数据
let person = {
name:'张三',
age:18
}
const p = new Proxy(person,{
//有人读取p的某个属性时调用
get(target,propName){
console.log(`有人读取了p身上的${propName}属性`)
return Reflect.get(target,propName)
},
//有人修改p的某个属性、或给p追加某个属性时调用
set(target,propName,value){
console.log(`有人修改了p身上的${propName}属性,我要去更新界面了!`)
Reflect.set(target,propName,value)
},
//有人删除p的某个属性时调用
deleteProperty(target,propName){
console.log(`有人删除了p身上的${propName}属性,我要去更新界面了!`)
return Reflect.deleteProperty(target,propName)
}
})
5. reactive对比ref
1、从定义数据角度对比:
ref
用来定义:基本类型数据。reactive
用来定义:对象(或数组)类型数据。- 备注:
ref
也可以用来定义对象(或数组)类型数据, 它内部会自动通过reactive
转为代理对象。
2、从原理角度对比:
ref
通过Object.defineProperty()
的get与set来实现响应式(数据劫持)。reactive
通过使用Proxy来实现响应式(数据劫持), 并通过Reflect
操作源对象内部的数据。
3、从使用角度对比:
ref
定义的数据:操作数据需要.value
,读取数据时模板中直接读取不需要.value
。reactive
定义的数据:操作数据与读取数据:均不需要.value
。
7. 计算属性与监视
7.1. computed函数
- 与Vue2.x中computed配置功能一致
写法
<template> <h1>一个人的信息</h1> 姓:<input type="text" v-model="person.firstName"> <br> 名:<input type="text" v-model="person.lastName"> <br> <span>全名:{{person.fullName}}</span> <br> 全名:<input type="text" v-model="person.fullName"> </template> <script> import {reactive,computed} from 'vue' export default { name: 'Demo', setup(){ //数据 let person = reactive({ firstName:'张', lastName:'三' }) //计算属性——简写(没有考虑计算属性被修改的情况) /* person.fullName = computed(()=>{ return person.firstName + '-' + person.lastName }) */ //计算属性——完整写法(考虑读和写) person.fullName = computed({ get(){ return person.firstName + '-' + person.lastName }, set(value){ const nameArr = value.split('-') person.firstName = nameArr[0] person.lastName = nameArr[1] } }) //返回一个对象(常用) return { person } } } </script>
7.2. watch函数
1、与
Vue2.x
中watch
配置功能一致
2、两个小“坑”:- 监视
reactive
定义的响应式数据时:oldValue
无法正确获取、强制开启了深度监视(deep
配置失效)。 - 监视
reactive
定义的响应式数据中某个属性时:deep
配置有效。
3、写法
<template>
<h2>当前求和为:{{sum}}</h2>
<button @click="sum++">点我+1</button>
<hr>
<h2>当前的信息为:{{msg}}</h2>
<button @click="msg+='!'">修改信息</button>
<hr>
<h2>姓名:{{person.name}}</h2>
<h2>年龄:{{person.age}}</h2>
<h2>薪资:{{person.job.j1.salary}}K</h2>
<button @click="person.name+='~'">修改姓名</button>
<button @click="person.age++">增长年龄</button>
<button @click="person.job.j1.salary++">涨薪</button>
</template>
<script>
import {ref,reactive,watch} from 'vue'
export default {
name: 'Demo',
setup(){
//数据
let sum = ref(0)
let msg = ref('你好啊')
let person = reactive({
name:'小叮当啊~',
age:18,
job:{
j1:{
salary:20
}
}
})
//情况一:监视ref所定义的一个响应式数据
watch(sum,(newValue,oldValue)=>{
console.log('sum变了',newValue,oldValue)
},{immediate:true})
//情况二:监视ref所定义的多个响应式数据
watch([sum,msg],(newValue,oldValue)=>{
console.log('sum或msg变了',newValue,oldValue)
},{immediate:true})
/*
情况三:监视reactive所定义的一个响应式数据的全部属性
1.注意:此处无法正确的获取oldValue
2.注意:强制开启了深度监视(deep配置无效)
*/
watch(person,(newValue,oldValue)=>{
console.log('person变化了',newValue,oldValue)
},{deep:false}) //此处的deep配置无效
//情况四:监视reactive所定义的一个响应式数据中的某个属性
watch(()=>person.name,(newValue,oldValue)=>{
console.log('person的name变化了',newValue,oldValue)
})
//情况五:监视reactive所定义的一个响应式数据中的某些属性
watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{
console.log('person的name或age变化了',newValue,oldValue)
})
//特殊情况
watch(()=>person.job,(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{deep:true})
//此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效
//返回一个对象(常用)
return {
sum,
msg,
person
}
}
}
</script>
7.3. watchEffect函数
1、watch
的套路是:既要指明监视的属性,也要指明监视的回调。
2、watchEffect
的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。
3、watchEffect
有点像computed
:
- 但
computed
注重的计算出来的值(回调函数的返回值),所以必须要写返回值。 而
watchEffect
更注重的是过程(回调函数的函数体),所以不用写返回值。<template> <h2>求和为:{{sum}}</h2> <button @click="sum++">点我+1</button> <hr> <h2>当前信息:{{msg}}</h2> <button @click="msg+='!'">修改</button> <hr> <h2>姓名:{{person.name}}</h2> <h2>年龄:{{person.age}}</h2> <h2>薪资:{{person.job.j1.salary}}K</h2> <button @click="person.name+='~'">修改姓名</button> <button @click="person.age++">增长年龄</button> <button @click="person.job.j1.salary++">涨薪</button> </template> <script> import {ref,reactive,watch,watchEffect} from 'vue' export default { name: 'Demo', setup(){ //数据 let sum = ref(0) let msg = ref('你好啊') let person = reactive({ name:'张三', age:18, job:{ j1:{ salary:20 } } }) //监视 /* watch(sum,(newValue,oldValue)=>{ console.log('sum的值变化了',newValue,oldValue) },{immediate:true}) */ watchEffect(()=>{ const x1 = sum.value const x2 = person.job.j1.salary console.log('watchEffect所指定的回调执行了') }) //返回一个对象(常用) return { sum, msg, person } } } </script>
8. 生命周期
1、Vue3.0
中可以继续使用Vue2.x
中的生命周期钩子,但有有两个被更名:
beforeDestroy
改名为beforeUnmount
destroyed
改名为unmounted
2、Vue3.0
也提供了 Composition API
形式的生命周期钩子,与Vue2.x
中钩子对应关系如下:
beforeCreate
===>setup()
created
=======>setup()
beforeMount
===>onBeforeMount
mounted
=======>onMounted
beforeUpdate
===>onBeforeUpdate
updated
=======>onUpdated
beforeUnmount
==>onBeforeUnmount
unmounted
=====>onUnmounted
<template>
<h2>当前求和为:{{sum}}</h2>
<button @click="sum++">点我+1</button>
</template>
<script>
import {ref,onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted} from 'vue'
export default {
name: 'Demo',
setup(){
console.log('---setup---')
//数据
let sum = ref(0)
//通过组合式API的形式去使用生命周期钩子
onBeforeMount(()=>{
console.log('---onBeforeMount---')
})
onMounted(()=>{
console.log('---onMounted---')
})
onBeforeUpdate(()=>{
console.log('---onBeforeUpdate---')
})
onUpdated(()=>{
console.log('---onUpdated---')
})
onBeforeUnmount(()=>{
console.log('---onBeforeUnmount---')
})
onUnmounted(()=>{
console.log('---onUnmounted---')
})
//返回一个对象(常用)
return {sum}
},
//通过配置项的形式使用生命周期钩子
//#region
beforeCreate() {
console.log('---beforeCreate---')
},
created() {
console.log('---created---')
},
beforeMount() {
console.log('---beforeMount---')
},
mounted() {
console.log('---mounted---')
},
beforeUpdate(){
console.log('---beforeUpdate---')
},
updated() {
console.log('---updated---')
},
beforeUnmount() {
console.log('---beforeUnmount---')
},
unmounted() {
console.log('---unmounted---')
},
//#endregion
}
</script>
9. 自定义hook函数
1、什么是hook
?—— 本质是一个函数,把setup
函数中使用的Composition API
进行了封装。
2、类似于vue2.x
中的mixin
。
3、自定义hook
的优势: 复用代码, 让setup
中的逻辑更清楚易懂。
4、Demo.vue
中
<template>
<h2>当前求和为:{{sum}}</h2>
<button @click="sum++">点我+1</button>
<hr>
<h2>当前点击时鼠标的坐标为:x:{{point.x}},y:{{point.y}}</h2>
</template>
<script>
import {ref} from 'vue'
import usePoint from '../hooks/usePoint'
export default {
name: 'Demo',
setup(){
//数据
let sum = ref(0)
let point = usePoint()
//返回一个对象(常用)
return {sum,point}
}
}
</script>
5、hooks/usePoint.js
中
import {reactive,onMounted,onBeforeUnmount} from 'vue'
export default function (){
//实现鼠标“打点”相关的数据
let point = reactive({
x:0,
y:0
})
//实现鼠标“打点”相关的方法
function savePoint(event){
point.x = event.pageX
point.y = event.pageY
console.log(event.pageX,event.pageY)
}
//实现鼠标“打点”相关的生命周期钩子
onMounted(()=>{
window.addEventListener('click',savePoint)
})
onBeforeUnmount(()=>{
window.removeEventListener('click',savePoint)
})
return point
}
10. toRef
1、作用:创建一个 ref
对象,其value
值指向另一个对象中的某个属性。
2、语法:const name = toRef(person,'name')
3、应用: 要将响应式对象中的某个属性单独提供给外部使用时。
4、扩展:toRefs
与toRef
功能一致,但可以批量创建多个 ref
对象,语法:toRefs(person)
<template>
<h4>{{person}}</h4>
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<h2>薪资:{{job.j1.salary}}K</h2>
<button @click="name+='~'">修改姓名~</button>
<button @click="age++">增长年龄~</button>
<button @click="job.j1.salary++">升职加薪走上人生巅峰</button>
</template>
<script>
import {ref,reactive,toRef,toRefs} from 'vue'
export default {
name: 'Demo',
setup(){
//数据
let person = reactive({
name:'张三',
age:18,
job:{
j1:{
salary:20
}
}
})
// const name1 = person.name
// console.log('***',name1)
// const name2 = toRef(person,'name')
// console.log('...',name2)
const x = toRefs(person)
console.log('******',x)
//返回一个对象(常用)
return {
person,
// name:toRef(person,'name'),
// age:toRef(person,'age'),
// salary:toRef(person.job.j1,'salary'),
...toRefs(person)
}
}
}
</script>
三、其它 Composition API
1. shallowReactive 与 shallowRef
1、shallowReactive
:只处理对象最外层属性的响应式(浅响应式)。
2、shallowRef
:只处理基本数据类型的响应式, 不进行对象的响应式处理。
3、什么时候使用?
- 如果有一个对象数据,结构比较深, 但变化时只是外层属性变化 ===>
shallowReactive
。 - 如果有一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换 ===>
shallowRef
。
<template>
<h4>当前的x.y值是:{{x.y}}</h4>
<button @click="x={y:888}">点我替换x</button>
<button @click="x.y++">点我x.y++</button>
<hr>
<h4>{{person}}</h4>
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<h2>薪资:{{job.j1.salary}}K</h2>
<button @click="name+='~'">修改姓名</button>
<button @click="age++">增长年龄</button>
<button @click="job.j1.salary++">涨薪</button>
</template>
<script>
import {ref,reactive,toRef,toRefs,shallowReactive,shallowRef} from 'vue'
export default {
name: 'Demo',
setup(){
//数据
// let person = shallowReactive({ //只考虑第一层数据的响应式
let person = reactive({
name:'张三',
age:18,
job:{
j1:{
salary:20
}
}
})
let x = shallowRef({
y:0
})
console.log('******',x)
//返回一个对象(常用)
return {
x,
person,
...toRefs(person)
}
}
}
</script>
2. readonly 与 shallowReadonly
1、readonly
: 让一个响应式数据变为只读的(深只读)。
2、shallowReadonly
:让一个响应式数据变为只读的(浅只读)。
3、应用场景: 不希望数据被修改时。
<template>
<h4>当前求和为--:{{sum}}</h4>
<button @click="sum++">点我++</button>
<hr>
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<h2>薪资:{{job.j1.salary}}K</h2>
<button @click="name+='~'">修改姓名</button>
<button @click="age++">增长年龄</button>
<button @click="job.j1.salary++">涨薪</button>
</template>
<script>
import {ref,reactive,toRefs,readonly,shallowReadonly} from 'vue'
export default {
name: 'Demo',
setup(){
//数据
let sum = ref(0)
let person = reactive({
name:'张三',
age:18,
job:{
j1:{
salary:20
}
}
})
person = readonly(person)
// person = shallowReadonly(person)
// sum = readonly(sum)
// sum = shallowReadonly(sum)
//返回一个对象(常用)
return {
sum,
...toRefs(person)
}
}
}
</script>
3. toRaw 与 markRaw
1、toRaw:
- 作用:将一个由
reactive
生成的响应式对象转为普通对象。 - 使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新。
2、markRaw: - 作用:标记一个对象,使其永远不会再成为响应式对象。
应用场景:
- 有些值不应被设置为响应式的,例如复杂的第三方类库等。
- 当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能。
<template> <h4>当前求和为:{{sum}}</h4> <button @click="sum++">点我++</button> <hr> <h2>姓名:{{name}}</h2> <h2>年龄:{{age}}</h2> <h2>薪资:{{job.j1.salary}}K</h2> <h3 v-show="person.car">座驾信息:{{person.car}}</h3> <button @click="name+='~'">修改姓名</button> <button @click="age++">增长年龄</button> <button @click="job.j1.salary++">涨薪</button> <button @click="showRawPerson">输出最原始的person</button> <button @click="addCar">给人添加一台车</button> <button @click="person.car.name+='!'">换车名</button> <button @click="changePrice">换价格</button> </template> <script> import {ref,reactive,toRefs,toRaw,markRaw} from 'vue' export default { name: 'Demo', setup(){ //数据 let sum = ref(0) let person = reactive({ name:'张三', age:18, job:{ j1:{ salary:20 } } }) function showRawPerson(){ const p = toRaw(person) p.age++ console.log(p) } function addCar(){ let car = {name:'奔驰',price:40} person.car = markRaw(car) } function changePrice(){ person.car.price++ console.log(person.car.price) } //返回一个对象(常用) return { sum, person, ...toRefs(person), showRawPerson, addCar, changePrice } } } </script>
4. customRef
1、作用:创建一个自定义的 ref
,并对其依赖项跟踪和更新触发进行显式控制。
2、实现防抖效果:
<template>
<input type="text" v-model="keyWord">
<h3>{{ keyWord }}</h3>
</template>
<script>
import {ref,customRef} from 'vue'
export default {
name: 'App',
setup() {
//自定义一个ref——名为:myRef
function myRef(value,delay){
let timer
return customRef((track,trigger)=>{
return {
get(){
console.log(`有人从myRef这个容器中读取数据了,我把${value}给他了`)
track() //通知Vue追踪value的变化(提前和get商量一下,让他认为这个value是有用的)
return value
},
set(newValue){
console.log(`有人把myRef这个容器中数据改为了:${newValue}`)
clearTimeout(timer)
timer = setTimeout(()=>{
value = newValue
trigger() //通知Vue去重新解析模板
},delay)
},
}
})
}
// let keyWord = ref('hello') //使用Vue提供的ref
let keyWord = myRef('hello',500) //使用程序员自定义的ref
return {keyWord}
}
}
</script>
5. provide 与 inject
1、作用:实现祖与后代组件间通信
2、套路:父组件有一个 provide
选项来提供数据,后代组件有一个 inject
选项来开始使用这些数据
3、具体写法:
祖组件中:
setup(){ ...... let car = reactive({name:'奔驰',price:'40万'}) provide('car',car) ...... }
后代组件中:
setup(props,context){ ...... const car = inject('car') return {car} ...... }
6. 响应式数据的判断
- isRef: 检查一个值是否为一个
ref
对象 - isReactive: 检查一个对象是否是由
reactive
创建的响应式代理 - isReadonly: 检查一个对象是否是由
readonly
创建的只读代理 isProxy: 检查一个对象是否是由
reactive
或者readonly
方法创建的代理setup(){ let car = reactive({name:'奔驰',price:'40W'}) let sum = ref(0) let car2 = readonly(car) console.log(isRef(sum)) console.log(isReactive(car)) console.log(isReadonly(car2)) console.log(isProxy(car)) console.log(isProxy(sum)) return {...toRefs(car)} }
四、新的组件
1. Fragment
1、在Vue2中: 组件必须有一个根标签
2、在Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment
虚拟元素中
3、好处: 减少标签层级, 减小内存占用
2. Teleport
什么是Teleport?—— Teleport
是一种能够将我们的组件html
结构移动到指定位置的技术。
<teleport to="移动位置">
<div v-if="isShow" class="mask">
<div class="dialog">
<h3>我是一个弹窗</h3>
<button @click="isShow = false">关闭弹窗</button>
</div>
</div>
</teleport>
3. Suspense
1、等待异步组件时渲染一些额外内容,让应用有更好的用户体验
2、使用步骤:
异步引入组件
import {defineAsyncComponent} from 'vue' const Child = defineAsyncComponent(()=>import('./components/Child.vue')) 使用Suspense包裹组件,并配置好default 与 fallback <template> <div class="app"> <h3>我是App组件</h3> <Suspense> <template v-slot:default> <Child/> </template> <template v-slot:fallback> <h3>加载中.....</h3> </template> </Suspense> </div> </template>
五、其它
1. 全局API的转移
1、Vue 2.x 有许多全局 API 和配置。
例如:注册全局组件、注册全局指令等。
//注册全局组件 Vue.component('MyButton', { data: () => ({ count: 0 }), template: '<button @click="count++">Clicked {{ count }} times.</button>' }) //注册全局指令 Vue.directive('focus', { inserted: el => el.focus() }
2、Vue3.0中对这些API做出了调整:
- 将全局的API,即:Vue.xxx调整到应用实例(app)上
2.x 全局 API(Vue ) | 3.x 实例 API (app ) |
---|---|
Vue.config.xxxx | app.config.xxxx |
Vue.config.productionTip | 移除 |
Vue.component | app.component |
Vue.directive | app.directive |
Vue.mixin | app.mixin |
Vue.use | app.use |
Vue.prototype | app.config.globalProperties |
2. 其他改变
1、data
选项应始终被声明为一个函数。
过度类名的更改:
.v-enter, .v-leave-to { opacity: 0; } .v-leave, .v-enter-to { opacity: 1; }
Vue3.x写法
.v-enter-from, .v-leave-to { opacity: 0; } .v-leave-from, .v-enter-to { opacity: 1; }
3、移除
keyCode
作为v-on
的修饰符,同时也不再支持config.keyCodes
4、移除v-on.native
修饰符父组件中绑定事件
<my-component v-on:close="handleComponentEvent" v-on:click="handleNativeClickEvent" />
子组件中声明自定义事件
<script> export default { emits: ['close'] } </script>
5、移除过滤器(
filter
)
过滤器虽然这看起来很方便,但它需要一个自定义语法,打破大括号内表达式是 “只是 JavaScript” 的假设,这不仅有学习成本,而且有实现成本!建议用方法调用或计算属性去替换过滤器。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。