Vue3基础
前提:Vue3依然支持Vue2的语法。并且Vue3和Vue2的优先级相同。
1. Vue3项目的创建
1.1 使用 vue-cli 创建
// 查看@vue/cli版本,确保@vue/cli版本在4.5.0以上
vue --version
// 安装或者升级你的@vue/cli
npm install -g @vue/cli
// 创建
vue create <project-name>
// 启动
cd <project-name>
npm run serve
1.2 使用 vite 创建
## 创建工程
npm create vite <project-name>
## 进入工程目录
cd <project-name>
## 安装依赖
npm install
## 运行
npm run [dev](url)
2. Vue3的组合式API(Composition API)
2.1 Composition API是什么
- ① Composition API是一系列 API 的集合,使我们可以使用函数的方式书写 Vue 组件。
- ② 组合式 API 是 Vue 3 及 Vue 2.7 的内置功能
2.2 Composition API的分类
- ① 响应式API。例如
ref()
和reactive()
,使我们可以直接创建响应式状态、计算属性和侦听器。 - ② 生命周期钩子函数。例如
onMounted()
和onUnmounted()
,使我们可以在组件各个生命周期阶段添加逻辑。 - ③ 依赖注入。例如
provide()
和inject()
,使我们可以在使用响应式 API 时,利用 Vue 的依赖注入系统。
2.3 常用的Composition API
2.3.1 setup函数
- 作用:Vue3要求代码必须写在setup函数内部。包括响应式数据、计算属性、方法、生命周期钩子函数等。
- 参数:
-
①
props
。值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性 -
②
context
。上下文对象- 1、
attrs
。值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于 this.$attrs。 - 2、
emit
。分发自定义事件的函数, 相当于 this.$emit。 - 3、
slots
。收到的插槽内容, 相当于 this.$slots。
- 1、
-
2.3.2 ref函数
- 作用:
定义基本类型的响应式数据
- 原理:Object.defineProperty
- 【注意】建议只用来定义基本数据类型(string,boolean,number)。如果定义引用类型会在内部调用reactive方法来生成数据
- 使用:
- 在script中获取或者设置值时需要 .value。
- 在页面上使用不需要 .value
2.3.3 reactive函数
- 作用:
定义引用类型的响应式数据
- 原理:proxy代理
- 语法:
let 代理对象 = reactive(源对象)
2.3.4 toRef函数
- 作用:复制 reactive 里的单个属性并转成 ref
- 语法:
const name = toRef(person,'name')
2.3.5 toRefs函数
- 作用:复制 reactive 里的所有属性并转成 ref
- 语法:
toRefs(person)
【ref对象和reactive对象对toRef与toRefs的应用】
2.3.6 computed计算属性
写法1:默认是get的写法
<template>
<div>{{total}}</div>
</template>
<script>
import {ref,computed} from 'vue';
export default{
setup(){
let num = ref(10);
let total = computed(()=>{
return num.value+'美金';
})
return {
num,
total
}
}
}
</sctipt>
写法2:有get和set的写法。computed方法中放一个对象,对象中有get和set方法
<template>
<div>{{total=10000}}</div>
<div>{{total}}</div>
</template>
<script>
import {ref,computed} from 'vue';
export default {
setup(){
let num = ref(20);
let total = computed({
get(){
return num.value+'英镑'
}
set(val){
if(val==0){
num.value='一个子没有'
}else{
num.value = val
}
}
})
}
}
</script>
2.3.7 watch监听
情况一:监听单个ref响应式数据 (基本数据类型)
<script>
import {ref ,watch} from 'vue'
export default {
setup(){
let str = ref('abc');
watch(str,(newVal,oldVal)=>{
console.log(newVal);
console.log(oldVal)
},{immediate:true})
}
}
</script>
情况二:监听多个ref响应式数据 (基本数据类型) ---> 利用数组实现多个监听
<script>
import {ref,watch} from 'vue'
export default {
setup(){
let str = ref('字符串数据');
let num = ref(99)
watch([str,num],(newVal,oldVal)=>{
console.log(newVal);
console.log(oldVal);
},{immediate:true})
}
}
</script>
情况三:监听1个reactive响应式数据 (引用数据类型)
特点:强制开启深度监听(只要有数据变化,就能被监听到)
<script>
import {reactive,watch} from 'vue'
export default {
let person = reactive({
name:'大刘',
age:30,
children:{
name:'小刘',
age:2
}
})
watch(person,(newVal,oldVal)=>{
console.log(newVal);
console.log(oldVal);
},{immediate:true,deep:true})
}
</script>
情况四:监听reactive响应式数据的1个属性 ---> 利用函数
<script>
import {reactive,watch} from 'vue'
export default {
let person = reactive({
name:'大刘',
age:30,
children:{
name:'小刘',
age:2
}
})
watch(()=>person.children,(newVal,oldVal)=>{
console.log(newVal);
console.log(oldVal);
},{immediate:true,deep:true})
}
</script>
情况五:监听reactive响应式数据的多个属性 ---> 利用函数+数组
<script>
import {reactive,watch} from 'vue'
export default {
let person = reactive({
name:'大刘',
age:30,
children:{
name:'小刘',
age:2
}
})
watch([()=>person.name,()=>person.children],(newVal,oldVal)=>{
console.log(newVal);
console.log(oldVal);
},{immediate:true,deep:true})
}
</script>
2.3.8 watchEffect函数
-
watch:明确指出监听的数据
-
watchEffect:没有明确指出监听的数据。在监听回调用了哪个数据,就监听哪个数据
<template> <div>{{str}}</div> <button @click='change'>改变</button> </template> <script> import {ref,watchEffect} from 'vue'; let str = ref('str的数据') const change = ()=>{ str.value='修改后的数据'; // cancelWatch(); 调用该方法会取消监听 } let cancelWatch = watchEffect(()=>{ str.value; // 在这里用到了str,所以触发了str的watchEffect监听 console.log('触发了str的监听') }) </script>
2.3.9 hook函数 ---> 第2个setup函数
- hook本质就是一个函数,和setup函数类似。类比Vue2中的mixin
2.3.10 生命周期钩子函数
-
vue2与Vue3生命周期钩子函数的对应关系:
- beforeCreate ===> setup()
- created=======> setup()
- beforeMount ===> onBeforeMount
- mounted =======> onMounted
- beforeUpdate ===> onBeforeUpdate
- updated =======> onUpdated
- beforeDestroy ==> onBeforeUnmount
- Destroyed =====> onUnmounted
-
【重要】vue2和vue3的生命周期图解
-
vue2生命周期
-
vue3生命周期
-
2.3.11 vue3中配置全局过滤器
【注意】在vue3中过滤器已经被废弃。全局过滤器只是定义了一些全局方法。
-
在main.js中配置全局过滤器,代码如下
import {createApp} from 'vue'; import App from './App.vue' let app = createApp(App) //配置全局过滤器 app.config.globalProperties.$filters = { // $filters是自己取的一个属性名 RMB(val,str){ return val+str } } app.mount('#app')
-
全局过滤器的使用,例如在组件Home.vue中使用:
$filters.RMB(20,'元')
<template> <div>{{ $filter.RMB(20,'元') }}</div> </template>
2.3.12 vue3配置全局自定义指令
-
在main.js中配置全局自定义指令,代码如下
import {createApp} from 'vue'; import App from './App.vue' let app = createApp(App) //配置全局自定义指令 app.directive = ('drag',{ mounted(el,binding,vnode){ //第一次插入DOM时触发。相当于vue2的bind(){} //写一个盒子拖拽的指令 el.onmousedown=function(e){ let disX = e.offsetX; let disY = e.offsetY; document.onmousemove=function(e){ el.style.left=e.pageX-disX+'px'; el.style.top=e.pageY=disY+'px' } document.onmouseup=function(){ document.onmousemove=document.onmouseup=null } } } updated(el,binding,vnode){ //每次DOM更新都会触发。相当于vue2的update(){} } }) app.mount('#app')
-
全局自定义指令的使用,例如在组件Home.vue中使用:
v-drag
<template> <div v-drag></div> </template>
2.4 其他一些Composition API
2.4.1 shallowReactive 和 shallowRef ---> 数据会改变,视图不更新
reactive
:定义引用类型的响应式数据。并且在watch时强制开启深度监听。属于深响应(所有的数据都会在视图有响应式处理)。shallowReactive
:只会处理最外层属性的响应式。属于浅响应(只对外层数据响应式处理)。ref
:定义基本数据类型的响应式数据。假如用ref定义引用类型的响应式数据,内部会调用reactive方法生成数据。ref定义的应用类型响应式数据也属于深响应。shallowRef
:只处理基本数据类型的响应式, 不进行对象的响应式处理。假如用shallowRef定义引用类型的响应式数据,不会响应式处理
【注意】shallowReactive和shallowRef定义的引用数据实际已经发生了改变,只是视图没有更新。只要视图更新,shallowReactive和shallowRef数据改变的地方也会响应到页面上。
2.4.2 readonly 和 shallowReactive ---> 数据不改变
readonly
:将一个响应式数据变成只读。(深只读:所有的数据都不能修改)shallowReadyonly
:将一个响应式数据变成只读。(浅只读:引用类型的响应式数据的深层次可以修改)
2.4.3 provide 和 inject
- 作用:实现祖先组件与后代组件间的通信
转载自:https://juejin.cn/post/7236689719076634682