(zichao)VUE3基础(仅作简单整理,未深入探究)
目录
一、创建Vue3.0工程
//查看@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
二、setup
(一)理解:
Vue3.0中一个新的配置项,值为一个函数。
(二)作用
setup是所有父亲,组件中所用到的:数据、方法等等,均要配置在setup中。
(三)setup函数的两种返回值:
若返回一个对象,则对象中的属性、方法, 在模板中均可以直接使用。(重点关注!)
(四)注意点
- 尽量不要与Vue2.x配置混用,如果有重名, setup优先。
- setup不能是一个async函数,因为返回值不再是return的对象, 而是promise, 模板看不到return对象中的属性。(后期也可以返回一个Promise实例,但需要Suspense和异步组件的配合)
(五)声明一个setup
setup(){
//数据
let name = '张三'
let age = 18
let a = 200
//方法
function sayHello(){
alert(`我叫${name},我${age}岁了,你好啊!`)
}
//返回一个对象(常用)
return {
name,
age,
sayHello,
a
}
}
三、ref函数
(一)作用
定义一个响应式的数据
(二)语法
//引入
import {ref} from 'vue'
//创建一个包含响应式数据
const xxx = ref(initValue)
(三)操作数据
//JS中操作数据
xxx.value
//模板中读取数据
<div>{{xxx}}</div>
(四)注意
- 接收的数据可以是:基本类型、也可以是对象类型。
- 基本类型的数据:响应式依然是靠
Object.defineProperty()
的get
与set
完成的。 - 对象类型的数据:内部求助 了Vue3.0中的一个新函数——
reactive
函数。
四、reactive函数
(一)作用
定义一个对象类型的响应式数据(基本类型不要用它,要用ref
函数)
(二)语法
const 代理对象= reactive(源对象)
接收一个对象(或数组),返回一个代理对象(Proxy的实例对象,简称proxy对象)
//引入reactive
import {reactive} from 'vue'
let person = reactive({
name:'张三',
age:18,
job:{
type:'前端工程师',
salary:'30K',
a:{
b:{
c:666
}
}
},
hobby:['抽烟','喝酒','烫头']
})
(三)深层次的
reactive定义的响应式数据是“深层次的”,对象和数组的增删改查都可以侦测到
五、setup的两个注意点
(一)setup执行的时机
在beforeCreate之前执行一次,this是undefined。
所以内部不能使用this
(二)setup的参数
1、props
值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性。
2、context
上下文对象
- attrs: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于
this.$attrs
。 - slots: 收到的插槽内容, 相当于
this.$slots
。 - emit: 分发自定义事件的函数, 相当于
this.$emit
。
六、计算属性
(一)写法
与Vue2.x中computed配置功能一致
import {computed} from 'vue'
setup(){
...
//计算属性——简写
let fullName = computed(()=>{
return person.firstName + '-' + person.lastName
})
//计算属性——完整
let fullName = computed({
get(){
return person.firstName + '-' + person.lastName
},
set(value){
const nameArr = value.split('-')
person.firstName = nameArr[0]
person.lastName = nameArr[1]
}
})
}
七、watch函数
(一)写法
//情况一:监视ref定义的响应式数据
watch(sum,(newValue,oldValue)=>{
console.log('sum变化了',newValue,oldValue)
},{immediate:true})
//情况二:监视多个ref定义的响应式数据
watch([sum,msg],(newValue,oldValue)=>{
console.log('sum或msg变化了',newValue,oldValue)
})
/* 情况三:监视reactive定义的响应式数据
若watch监视的是reactive定义的响应式数据,则无法正确获得oldValue!!
若watch监视的是reactive定义的响应式数据,则强制开启了深度监视
*/
watch(person,(newValue,oldValue)=>{
console.log('person变化了',newValue,oldValue)
},{immediate:true,deep:false}) //此处的deep配置不再奏效
//情况四:监视reactive定义的响应式数据中的某个属性,其他生效
watch(()=>person.job,(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{immediate:true,deep:true})
//情况五:监视reactive定义的响应式数据中的某些属性,其他生效
watch([()=>person.job,()=>person.name],(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{immediate:true,deep:true})
- 监视reactive定义的响应式数据时:oldValue无法正确获取、强制开启了深度监视(deep配置失效)。
- 监视reactive定义的响应式数据中某个属性时:deep配置有效。
(二)watchEffect函数
不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。
import {watchEffect} from 'vue'
//watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调。
watchEffect(()=>{
const x1 = sum.value
const x2 = person.age
console.log('watchEffect配置的回调执行了')
})
八、生命周期
Vue3.0也提供了 Composition API 形式的生命周期钩子,与Vue2.x中钩子对应关系如下:
beforeCreate
===>setup()
created
=======>setup()
beforeMount
===>onBeforeMount
mounted
=======>onMounted
beforeUpdate
===>onBeforeUpdate
updated
=======>onUpdated
beforeUnmount
==>onBeforeUnmount
unmounted
=====>onUnmounted
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}
}
九、自定义hook函数
-
什么是hook?—— 本质是一个函数,把setup函数中使用的Composition API进行了封装。
-
类似于vue2.x中的mixin。
-
自定义hook的优势: 复用代码, 让setup中的逻辑更清楚易懂。
//创建hooks文件夹下创建usePoint
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
}
//组件直接使用
import usePoint from '../hooks/usePoint'
export default {
name:'Test',
setup(){
const point = usePoint()
return {point}
}
}
<h2>我是Test组件</h2>
<h2>当前点击时鼠标的坐标为:x:{{point.x}},y:{{point.y}}</h2>
十、toRef和toRefs
- 作用:创建一个 ref 对象,其value值指向另一个对象中的某个属性。
- 语法:
const name = toRef(person,'name')
- 应用: 要将响应式对象中的某个属性单独提供给外部使用时。
import {ref,reactive,toRef,toRefs} from 'vue'
export default {
name: 'Demo',
setup(){
//数据
let person = reactive({
name:'张三',
age:18,
job:{
j1:{
salary:20
}
})
//返回一个对象(常用)
return {
person,
name:toRef(person,'name'),
age:toRef(person,'age'),
salary:toRef(person.job.j1,'salary'),
...toRefs(person)//返回所有属性
}
}
}
十一、其它 Composition API
(一)shallowReactive 与 shallowRef
- shallowReactive:只处理对象最外层属性的响应式(浅响应式)。
- shallowRef:只处理基本数据类型的响应式, 不进行对象的响应式处理。
(二)readonly 与 shallowReadonly
- readonly: 让一个响应式数据变为只读的(深只读)。
- shallowReadonly:让一个响应式数据变为只读的(浅只读)。
(三)toRaw 与 markRaw
- toRaw:将一个由
reactive
生成的响应式对象普通对象。 - markRaw:标记一个对象,使其永远不会再成为响应式对象。
(四)provide 与 inject
1、作用
实现祖与后代组件间通信
父组件有一个 provide
选项来提供数据,后代组件有一个 inject
选项来开始使用这些数据
2、实现
//父组件
let car = reactive({name:'奔驰',price:'40万'})
provide('car',car)
//子组件
const car = inject('car')
return {car}
十二、响应式数据的判断
- isRef: 检查一个值是否为一个 ref 对象
- isReactive: 检查一个对象是否是由
reactive
创建的响应式代理 - isReadonly: 检查一个对象是否是由
readonly
创建的只读代理 - isProxy: 检查一个对象是否是由
reactive
或者readonly
方法创建的代理
十三、新的组件
(一)Fragment
- 在Vue2中: 组件必须有一个根标签
- 在Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment虚拟元素中
- 好处: 减少标签层级, 减小内存占用
(二)Teleport
什么是Teleport?—— Teleport
是一种能够将我们的组件html结构移动到指定位置的技术。
//此时被teleport包裹的元素会出现到to所指定的元素上,to可以指定元素名,类名
<button @click="isShow = true">点我弹个窗</button>
<teleport to="body">
<div v-if="isShow" class="mask">
<div class="dialog">
<h3>我是一个弹窗</h3>
<h4>一些内容</h4>
<h4>一些内容</h4>
<h4>一些内容</h4>
<button @click="isShow = false">关闭弹窗</button>
</div>
</div>
</teleport>
十四、其他
(一)全局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 |
(二)过度类名的更改
Vue2.x写法
css
.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;
}
(三)移除过滤器(filter)
过滤器虽然这看起来很方便,但它需要一个自定义语法,打破大括号内表达式是 “只是 JavaScript” 的假设,这不仅有学习成本,而且有实现成本!建议用方法调用或计算属性去替换过滤器。