Vue3 代号:One Piece(海贼王) 。
vue3 比 vue2 的好处:
源码升级:
前提:确保@vue/cli的版本在4.5.0之前上!
# 查看版本命令
vue -V 或者 vue --version
# 创建一个名为vue3_test的项目
vue create vue3_test
# 注意中间要选择Vue3版本!!!
Vite是新一代的前端开发构建工具。和Webpack功能一样。
官方地址:https://vitejs.cn/
vite的优点:
图上前者是先将所有的模块准备好,在搭建好server服务器。后者是先准备好服务器,之后通过请求去找对应的模块,正好与前面反着,这样更加快一点。
命令如下:
# 创建工程
npm init vite-app <project-name>
# 进入工程目录
cd <project-name>
# 安装依赖
npm install
# 运行
npm run dev
main.js文件结构如下:
//引入的不再是Vue构造函数了,而引用的是createApp就是创建一个应用的工厂函数。
import { createApp } from 'vue'
import App from './App.vue'
//创建应用实例对象-app(类似于之前vue2中的vm,但app比vm更轻)
const app = createApp(App)
console.log('@@@',App)
//mount就是挂载,与vue3不同的是没有了$符号。
app.mount('#app')
setTimeout(()=>{
//调用unmount可以卸载app应用
app.unmount('#app')
},3000)
// 注意vue3构想的项目,并不支持vue2的写法!!!
// vue2 的写法,通过el或者$mount来指定容器,通过render来渲染。
// const vm = new Vue({
// // el:'#app'
// render:(h)=> h(App)
// })
//
// vm.$mount('#app')
Vue的dev-tools安装包:https://gitee.com/it-sherlock/develop-common-parameters/tree/master/%E5%89%8D%E7%AB%AF/Vue/dev-tools
Composition API:组合式API
setup是Vue3的新的配置项。
setup是所有Composition API(组合API)的表演舞台。
组件中所用到的:数据,方法等等,均要配置在setup中!!!
而Vue2,数据要配置在data配置项中,方法配置在methods中。
在vue3项目中,可以配置vue2的data,methods的写法,但是非常不建议!!
vue3的setup是不能够访问到vue2的data,methods等一些数据和方法的!!
注意:setup不能使用async修饰。如果加上了,async会将其的返回值包裹为一个promise对象,这样setup的返回值就不是一个单纯的对象了。
前提:先引入ref函数,从vue中!
import {ref} from 'vue'
vue2中的ref是作为一个属性,类似于id选择器,打标识用的。
在vue3中,多了一个ref函数,ref函数可以让定义的数据具有响应式。直接在setup定义并且返回的变量,是不具有响应式的,值变化页面并不会变化!
对于基本数据类型而言
,ref函数用到了ObjectDefineProperty方法来实现的,走的是get和set方法来实现响应式。
ref函数,对于处理对象数据类型,是用的ES6的Proxy代理对象。
对于对象,直接使用 对象.value.属性名 来触发响应式就可以。
前提:也是在vue中,引入reactive函数
import {reactive} from 'vue'
不要用reactive函数来处理基本数据类型,reactive专门用来处理对象类型!!
ref函数也能够处理对象类型,原因就是它在处理对象的时候底层也去使用了reactive函数。
reactive的底层不再通过ObjectDefineProperty函数达到响应式了。而是通过Proxy实现。
reactive函数可以支持深层次的对象数据的响应式,也支持数组数据的响应式。
小知识点:
vue3就弥补了vue2的这个缺点,即便是通过索引赋值也能够触发响应式!
reactive函数使用:
reactive的内部基于ES6的Proxy实现,通过代理对象操作源对象内部数据进行操作。
vue2的数组push,做了两件事,一个是往数组中添加数据,另一个是更新页面数据。
因为Vue2使用的是ObjectDefineProperty方法中的get和set方法,对于获取就用get,对于修改就用set,然而对于添加和删除却是无可奈何的!!
vue2对象添加一个属性:
有了reactive,vue3就弥补了上面vue2不能直接添加删除,数组索引项不能直接赋值的缺点!
还是那句话,Object.defineProperty能检测get获取和set设置,但是不能够检测到删除和添加属性。所以还是有小毛病的!
ES6的 Proxy对象:
//源数据
let person = {
name:'张三',
age:18
}
const p = new Proxy(person,{})
console.log(p)
//Vue3的响应式,通过配置第二个参数handler对象来达到响应式
const p = new Proxy(person,{
//读取p的某个属性时调用
get(target, propName, receiver) {
console.log(`有人读取了p身上的${propName}属性`)
console.log(target)
console.log(propName)
return target[propName]
},
//修改p的某个属性时调用 和 新增p的某个属性时调用
set(target, propName, value, receiver) {
console.log(`有人修改了p身上的${propName}属性,我要更新页面了!`)
console.log(target)
console.log(propName)
console.log(value)
target[propName] = value
},
//删除p的某个属性时调用
deleteProperty(target, propName) {
console.log(`有人删除了p身上的${propName}属性,我要更新页面了!`)
//delete返回的是一个布尔值,同时deleteProperty也要返回一个布尔值!!
let boolean = delete target[propName]
return boolean
}
})
Reflect也是可以对对象的属性进行获取,修改,新增,删除操作。
Object.defineProperty与 Reflect的对比:
Reflect相对比较健壮!!
vue3底层的对对象的增删改查,并不会直接使用target操作,而是通过Reflect函数进行操作如下:
//Vue3的响应式,通过配置第二个参数handler对象来达到响应式
const p = new Proxy(person,{
//读取p的某个属性时调用
get(target, propName, receiver) {
console.log(`有人读取了p身上的${propName}属性`)
console.log(target)
console.log(propName)
return Reflect.get(target,propName)
},
//修改p的某个属性时调用 和 新增p的某个属性时调用
set(target, propName, value, receiver) {
console.log(`有人修改了p身上的${propName}属性,我要更新页面了!`)
console.log(target)
console.log(propName)
console.log(value)
Reflect.set(target,propName,value)
},
//删除p的某个属性时调用
deleteProperty(target, propName) {
console.log(`有人删除了p身上的${propName}属性,我要更新页面了!`)
//delete返回的是一个布尔值,同时deleteProperty也要返回一个布尔值!!
let boolean = Reflect.deleteProperty(target,propName)
return boolean
}
})
$slot的作用:
setup的执行时机:
setup的props参数使用:
setup的第二个参数context(上下文):
在setup配置项里面,是肯定不会用this的,因为setup在beforeCreate之前会自动执行,打印过this是undefined!
vue2形式的computed也是可以在vue3的项目中使用的,对应的this自然就是vue对象。
vue3的写法如下:
import {computed} from 'vue'
setup(){
let person = reactive({
firstName: '张',
lastName: '三',
age: 18,
})
//计算属性 简写形式只考虑计算属性读,没有考虑计算属性的改
// 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
}
}
Vue2的watch使用:
watch:{
//vue2的监听简易写法:直接通过 数据对象名定义函数来监听
// sum(newValue,oldValue){
// console.log('sum的值变化了',newValue,oldValue)
// },
//vue2监听完整写法:
sum:{
immediate:true, // 配置立即监听属性,一进来就先执行一次。
deep:true, // 深度监视属性
handler(newValue,oldValue){
console.log('sum的值变化了',newValue,oldValue)
}
}
watch监听ref函数如下:
<template>
<h2>当前求和为:{{sum}}</h2>
<button @click="sum++">点我+1</button>
<h2>当前的信息为:{{msg}}</h2>
<button @click="msg += '!'">修改信息</button>
</template>
<script>
import {ref,watch} from 'vue'
export default {
name:'Demo',
setup(){
//数据
let sum = ref(0)
let msg = ref('你好啊')
//情况一:监视ref所定义一个的响应式数据
// watch(sum,(newValue,oldValue)=>{
// console.log('sum变了',newValue,oldValue)
// })
//情况二: 监视ref所定义的多个响应式数据
//第一个参数:监听的数据。第二个参数:监听的函数。第三个参数:配置项
watch([sum,msg],(newValue,oldValue)=>{
//此时的newValue和oldValue就变成了数组
console.log(newValue) //[0, '你好啊!']
console.log(oldValue)//[0, '你好啊']
console.log('sum变了',newValue,oldValue)
},{immediate:true,deep:true})
return {
sum,
msg
}
}
}
</script>
监听格式如下:
//就算用ref函数操作,因为是对象,对于对象ref还是走的reactive函数!
let person = reactive({
name:'张三',
age:18
})
//监视reactive所定义的一个响应式数据
watch(person,(newValue,oldVale)=>{
//注意:这里newValue和oldVale一样,也就是无法获得正常的oldValue
//这个问题目前无法解决!
console.log(newValue)//{name: '张三~', age: 19}
console.log(oldVale)//{name: '张三~', age: 19}
console.log('person的age变化了')
})
解决办法:如果无法业务上面真的需要获取到oldValue的话,那就只能把这个属性从对象中拿出来,放到ref函数中使用!
//单独把age拿出来,用ref来声明就可以监听到!!
let age = ref(18)
//就算用ref函数操作,因为是对象,对于对象ref还是走的reactive函数!
let person = reactive({
name:'张三',
})
//监视reactive所定义的一个响应式数据
watch(age,(newValue,oldVale)=>{
//注意:这里newValue和oldVale一样,也就是无法获得正常的oldValue
//这个问题目前无法解决!
console.log(newValue)
console.log(oldVale)
console.log('person的age变化了')
})
let person = reactive({
name:'张三',
age:18,
job:{
j1:{
salary: 20
}
}
})
//对象的某个属性,必须要用函数才能监听!!!
watch(()=>person.age,(newValue,oldVale)=>{
console.log(newValue)
console.log(oldVale)
console.log('person的age变化了')
})
//监视reactive所定义的一个响应式数据中的 多个属性!
let person = reactive({
name:'张三',
age:18,
job:{
j1:{
salary: 20
}
}
})
//那就将其多个函数写成数组的形式
watch([()=>person.age,()=>person.name],(newValue,oldVale)=>{
console.log(newValue)
console.log(oldVale)
console.log('person变化了')
})
let person = reactive({
name:'张三',
age:18,
job:{
j1:{
salary: 20
}
}
})
//监听一个对象里面的对象属性,因为我们更改的是对象中的对象的对象数据!!
//所以必须开启深度监视deep!!
watch(()=>person.job,(newValue,oldVale)=>{
console.log(newValue)
console.log(oldVale)
console.log('person的job变化了')
},{deep:true})
注意点1:监听ref定义的基本数据类型,不能添加sum.value!!
//数据
let sum = ref(0)
let msg = ref('你好啊')
let person = ref({
name:'张三',
age:18,
job:{
j1:{
salary: 20
}
}
})
//监听ref定义的基本数据类型,不能添加sum.value!!
//如果添加上了.value那监听的就是sum.value的这个值!并不是sum这个变量!
watch(sum,(newValue,oldValue)=>{
console.log('sum的值变化了',newValue,oldValue)
})
注意点2:ref代理对象的形式,通过.value来实现监听的效果。
let person = ref({
name:'张三',
age:18,
job:{
j1:{
salary: 20
}
}
})
watch(person,(newValue,oldValue)=>{
console.log('person的值变化了',newValue,oldValue)
},{deep:true}) // 开启深度监视就能监视到了!
watchEffect也是起到监听的效果,但宇watch不同!
export default {
name:'Demo',
setup(){
//数据
let sum = ref(0)
let msg = ref('你好啊')
let person = reactive({
name:'张三',
age:18,
job:{
j1:{
salary: 20
}
}
})
//watchEffect是用了谁,就监视谁!
watchEffect(()=>{
const x1 = sum.value
const x2 = person.job.j1.salary
console.log('watchEffect所指定的回调执行了!')
})
return {
sum,
msg,
person
}
}
总结: