vue3.0 -初探 -持续更新中
一.创建vue工程方式有两种
- 传统的 vue-cli 方式
##首先保证本地的vue-cli版本在4.5.0以上
vue --version
##如果不是,先升级最新的vue-cli工具
npm i -g @vue\vue-cli
## 然后和之前的创建vue2的方式一样。
vue init webapack <project-name> ## 打包工具指定的是webpack
## 在后续list中,选择[vue3]即可。
传统的方式创建vue3,也没问题,但是这样一来的打包工具仍然是webpack。
- 使用 vite 创建
## 创建工程
npm init vite-app <project-name> # 指定了脚手架为vite 以及项目框架是vue3.x [为什么是vue3.0框架?因为这个vite工具就是vue3开发团队写的,所以人家直接默认就用 vite-app 创建的项目就是基于 vue3.0]
## 进入功能目录
cd <project-name>
## 安装依赖
npm install
## 运行
npm run dev
使用 vite 方式创建,打包工具就是 vite 了,项目也没有什么 build 文件夹,以及一堆 webpack.config.js webpack.base.js xxxxxx
二、 vue3.0中main.js文件
在 vue2.x 中,我们的 main.js 是这么写的。
import Vue from 'vue'
import App from './App'
const vm = new Vue({
render(h) => h(App)
})
vm.$mount('#app')
在 vue3.0中是这么写的。
import { createApp } from 'vue'
import App from './App'
const app = createApp(App)
app.mount('#app')
在vue2.0中,我们直接调用 new Vue 构造函数创建一个vm实例。在v3.0中,我们使用 createApp函数,传递进去一个options对象,来创建一个app实例。 后面的挂载都是一样的。
你把 app 和 vm 打印到控制台查看一下,就会发现 app 比 vm 属性少很多,也就是说 vue3.0 里的 app 更为轻量。
三、 Vue3.0中的 setup 函数
在 vue2.x 中,我们定义组件的数据,方法,计算属性,watch等都是以配置选项的方式来进行的。
export default {
name: 'App',
data () {
return {
num:1
}
},
methods: {},
computed: {},
watch: {}
}
在 vue3.0 中,所有需要的上述组件配置,都应该定义在 setup
函数里,并返回。(为什么要返回?返回才会挂载在当前组件实例上,才能在模板中使用。)
export default {
name: 'App',
setup () {
// 我定义的函数
// 我定义的数据
// 我定义的watch
// 我定义的计算属性
// .....
return {
我定义的函数,
我定义的数据,
我定义的,
我定义的计算属性
}
}
}
四、vue3.0中的ref函数
vue2.0 和 vue3.0 配置数据响应式也有区别。
在 vue2.0中,我们把数据放在 data 选项里,就可以完成响应式的配置了。
在vue3.0中,提供了更精细化的响应式数据配置。
// vue3.0 ref 函数功能说明
import { ref } from 'vue'
export default {
name: 'App',
setup () {
// 定义一个基本数据类型响应式
let num = ref(100)
// 返回的是一个 RefImpl 的对象 RefImpl { ......}
// 使用num
num.value = 100 // 触发setter
console.log(num.value) // 触发getter
// 定义一个对象类型数
let obj = ref({
name: '张三-老工具人了',
job: {
detail: {
title: '前端开发',
salary: 30
}
}
})
// 修改name属性
obj.value.name = '李四' //
obj.value.job.detail.title = 'python开发'
// tips: 可能有人觉得,obj.value.xxx 不如 obj.xxx 直接来的直观,但是 ref 定义数据响应式就是有这么一个特点。
return {
num, // 在模板中,使用num,不需要加.value
obj
}
}
}
// ref 函数内部逻辑
// 1. 如果你传递的参数是基本数据类型,那么内部直接使用Object.defineProperty来定义一个新属性叫.value来实现响应式。
// 2. 如果你传递的是一个对象数据类型,那么内部使用 new Proxy 来定义数据的响应式。
// 所以,对于ref来说,内部选择使用 Object.defineProperty 还是 new Proxy 取决于你传递进来的数据.
// 大概逻辑如下.
function ref (value) {
return new RefImpl(value)
}
function RefImpl (value) {
this.__v_Ref = true
this.__rawValue = value
this.__newValue = value
// this.__shallowRef = fasle
if (typeof value !== 'object') {
Object.define(this,'value', {
get () {
return this.__newValue
},
set (newVal) {
this.__newValue = newVal
}
})
} else {
this.value = new Proxy (this,{
get (target,propertyName) {
return Reflect.get(target,propertyName)
},
set (target,propertyName,value) {
Reflect.set(target,proeprtyName,value)
},
deleteProperty (target,propertyName) {
//...监听delete属性操作...
Reflect.delete(target,propertyName)
},
})
}
}
如果你给 ref 传递的是基本数据类型,那么 .value 拿到的就是由 Object.defineProperty定义的那个 .value 属性。
如果你给 ref 传递的是对象数据类型,那么 .value 拿到的就是有 new Proxy 定义的那个对象。
五、 vue3.0 中的 reactive 函数
在ref函数介绍里,我们有这么一段代码
let obj = ref({
name: '张三-老工具人了',
job: {
detail: {
title: '前端开发',
salary: 30
}
}
})
obj.value.name = '李四' //
obj.value.job.detail.title = 'python开发'
// 可能有人觉得,obj.value.xxx 不如 obj.xxx 直接来的直观,但是 ref 定义数据响应式就是有这么一个特点。
可能有人觉得,obj.value.xxx 不如 obj.xxx 直接来的直观,但是 ref 定义数据响应式就是有这么一个特点。
所以,使用 ref 定义对象类型数据,并不是很好的方式。
于是就有了 reactive
函数。
import { reactive } from 'vue'
export default {
name:'App',
setup () {
let person = reactive({
name: '张三-老工具人了',
job: {
detail: {
title: '前端开发',
salary: 30
}
}
})
/// 访问数据
console.log(person.name)
// 修改属性
person.job.detail.title = 'python开发' // 就没有烦人的.value了。
return {
person
}
}
}
所以,对于对象数据类型,使用 reactive 比 ref 更为合适。
建议: 基本数据类型,使用 ref, 对象类型使用 reactive
注意:不要给基本数据类型使用reactive做响应式,否则被报错
let num = reactive(0)
value cannot be made reactive: 0
总结ref和reactive
- ref 可以定义基本数据类型响应式,也可以定义对象类型数据响应式
- 当你给
ref
传递基本数据类型时,其内部的.value
是使用的Object.defineProperty
来实现响应式。 - 当给你
ref
传递对象类型数据是,其内部的.value是使用的new Proxy
来实现响应式。 - 使用
ref
定义响应式,想访问到真实的数据,必须加一个.value
- 当你给
-
reactive
只能定义对象类型数据响应式