打包大小减少41%
初次渲染快55%, 更新渲染快133%
内存减少54%
使用Proxy代替defineProperty实现响应式
重写虚拟DOM的实现和Tree-Shaking
Composition API(组合API)
新的内置组件
其他改变
使用传统OptionsAPI中,新增或者修改一个需求,就需要分别在data,methods,computed里修改 。
我们可以更加优雅的组织我们的代码,函数。让相关功能的代码更加有序的组织在一起。
Vue2项目的main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
看看vm是什么
const vm = new Vue({
render: h => h(App),
})
console.log(vm)
vm.$mount('#app')
我们再来看看Vue3项目中的main.js
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
我们来分析一下吧
// 引入的不再是Vue构造函数了,引入的是一个名为createApp的工厂函数
import { createApp } from 'vue'
import App from './App.vue'
// 创建应用实例对象——app(类似于之前Vue2中的vm,但app比vm更“轻”)
const app = createApp(App)
console.log(app)
// 挂载
app.mount('#app')
这里的app到底是啥,我们输出到控制台看看
我们再来看看组件
在template
标签里可以没有根标签了
<template>
<!-- Vue3组件中的模板结构可以没有根标签 -->
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</template>
官方文档:创建一个项目 | Vue CLI
## 查看@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
官方文档:快速上手 | Vue.js
vite官网:https://vitejs.cn
## 创建工程
npm init vite-app <project-name>
## 进入工程目录
cd <project-name>
## 安装依赖
npm install
## 运行
npm run dev
# 确保你安装了最新版本的 Node.js,然后在命令行中运行以下命令 (不要带上 > 符号):
> npm init vue@latest
# 这一指令将会安装并执行 create-vue,它是 Vue 官方的项目脚手架工具。你将会看到一些诸如 TypeScript 和测试支持之类的可选功能提示:
? Project name: … <your-project-name>
? Add TypeScript? … No / Yes
? Add JSX Support? … No / Yes
? Add Vue Router for Single Page Application development? … No / Yes
? Add Pinia for state management? … No / Yes
? Add Vitest for Unit testing? … No / Yes
? Add Cypress for both Unit and End-to-End testing? … No / Yes
? Add ESLint for code quality? … No / Yes
? Add Prettier for code formatting? … No / Yes
Scaffolding project in ./<your-project-name>...
Done.
# 如果不确定是否要开启某个功能,你可以直接按下回车键选择 No。在项目被创建后,通过以下步骤安装依赖并启动开发服务器:
> cd <your-project-name>
> npm install
> npm run dev
setup为Vue3.0中一个新的配置项,值为一个函数
setup是所有Composition API(组合API)编写的位置
组件中所用到的:数据、方法等等,均要配置在setup中
setup函数的返回值:返回一个对象,对象中的属性、方法, 在模板中均可以直接使用
注意:
尽量不要与Vue2.x配置混用
<template>
{{name}}--{{age}}--{{xx}}
</template>
<script>
export default {
name: 'App',
data(){
return {
xx:this.name
}
},
setup(){
let name='lqz'
let age =19
return {
name,age
}
},
}
</script>
const xxx = ref(initValue)
xxx.value
<div>{{xxx}}</div>
Object.defineProperty()
的get
与set
完成的reactive
函数ref
函数)const 代理对象= reactive(源对象)
接收一个对象(或数组),返回一个代理对象(Proxy的实例对象,简称proxy对象)<template>
{{ name }}--{{ age }}--{{ xx }}
<br>
{{person}}
<button @click="handleClick">点我</button>
<br>
</template>
<script>
import {ref, reactive} from 'vue'
export default {
name: 'App',
data() {
return {
xx: this.name
}
},
setup() {
let name = 'lqz'
let age = ref(19)
// const person = ref({ // 内部包装成reactive
const person = reactive({
name: '彭于晏',
age: 88
})
function handleClick() {
// console.log(age)
// age.value++
console.log(person)
person.age++
}
return {
name, age, handleClick,person
}
},
}
</script>
reactive
转为代理对象Object.defineProperty()
的get
与set
来实现响应式(数据劫持)。.value
,读取数据时模板中直接读取不需要.value
。.value
。setup执行的时机
setup的参数
this.$attrs
。this.$slots
。this.$emit
。与Vue2.x中computed配置功能一致
写法
<template>
<p>姓:<input type="text" v-model="person.firstName"></p>
<p>名:<input type="text" v-model="person.lastName"></p>
<p>全名:{{ person.fullName }}</p>
<p>全名修改:<input type="text" v-model="person.fullName"></p>
</template>
<script>
import {ref, reactive} from 'vue'
import {computed} from 'vue'
export default {
name: 'App',
setup() {
const person = reactive({
firstName: '刘',
lastName: '亦非'
})
// let fullName = computed(() => {
// return person.firstName + '-' + person.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>
与Vue2.x中watch配置功能一致
两个小“坑”:
<template>
<h2>年龄是:{{ age }}</h2>
<button @click="age++">点我年龄增加</button>
<hr>
<h2>姓名是:{{ person.name }}</h2>
<button @click="person.name+='?'">点我姓名变化</button>
<hr>
<h2>sum是:{{ sum }},msg是:{{ msg }}</h2>
<button @click="sum++">点我sum变化</button>
|
<button @click="msg+='?'">点我msg变化</button>
</template>
<script>
import {ref, reactive} from 'vue'
import {watch} from 'vue'
export default {
name: 'App',
setup() {
const age = ref(19)
const person = reactive({
name: 'lqz',
age: 20
})
//1 监听普通
watch(age, (newValue, oldValue) => {
console.log('sum变化了', newValue, oldValue)
})
// 2 监听对象
watch(() => person.name, (newValue, oldValue) => {
console.log('person.name变化了', newValue, oldValue)
})
// 3 监听多个
const sum = ref(100)
const msg = ref('很好')
watch([sum, msg], (newValue, oldValue) => {
console.log('sum或msg变化了', newValue, oldValue)
})
return {person, age, sum, msg}
},
}
</script>
watch的套路是:既要指明监视的属性,也要指明监视的回调。
watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。
watchEffect有点像computed:
//watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调。
watchEffect(() => {
const x1 = sum.value
const x2 = person.age
console.log('watchEffect配置的回调执行了')
})
beforeDestroy
改名为?beforeUnmount
destroyed
改名为?unmounted
beforeCreate
===>setup()
created
=======>setup()
beforeMount
?===>onBeforeMount
mounted
=======>onMounted
beforeUpdate
===>onBeforeUpdate
updated
?=======>onUpdated
beforeUnmount
?==>onBeforeUnmount
unmounted
?=====>onUnmounted
什么是hook?—— 本质是一个函数,把setup函数中使用的Composition API进行了封装。
类似于vue2.x中的mixin。
自定义hook的优势: 复用代码, 让setup中的逻辑更清楚易懂。
<template>
<h2>点击的x坐标:{{ point.x }},y坐标:{{ point.y }}</h2>
</template>
<script>
import {reactive} from 'vue'
import {onMounted, onBeforeUnmount} from 'vue'
export default {
name: 'Point',
setup() {
const point = reactive({
x: 0,
y: 0
})
function getPoint(event) {
console.log(event.pageX)
console.log(event.pageY)
point.x = event.pageX
point.y = event.pageY
}
// 挂在完成开始执行
onMounted(() => {
window.addEventListener('click', getPoint)
})
// 接除挂载时执行
onBeforeUnmount(() => {
console.log('sss')
window.removeEventListener('click', getPoint)
})
return {point}
},
}
</script>
<template>
<div>
<button @click="isShow=!isShow">点我显示隐藏</button>
<Point v-if="isShow"></Point>
</div>
</template>
<script>
import {ref, reactive} from 'vue'
import Point from "./components/Point.vue";
import Demo from './components/HelloWorld.vue'
export default {
name: 'App',
components: {Demo, Point},
setup() {
const isShow = ref(true)
return {isShow}
},
}
</script>
uesPoint.js
import {onBeforeUnmount, onMounted, reactive} from "vue";
export default function () {
let point = reactive({
x: 0,
y: 0
})
function getPoint(event) {
console.log(event.pageX)
console.log(event.pageY)
point.x = event.pageX
point.y = event.pageY
}
// 挂在完成开始执行
onMounted(() => {
window.addEventListener('click', getPoint)
})
// 接除挂载时执行
onBeforeUnmount(() => {
console.log('sss')
window.removeEventListener('click', getPoint)
})
return point
}
Point.vue
<template>
<h2>点击的x坐标:{{ point.x }},y坐标:{{ point.y }}</h2>
</template>
<script>
import usePoint from '../hooks/usePoint.js'
export default {
name: 'Point',
setup() {
let point = usePoint()
console.log(point)
return {point}
},
}
</script>
作用:创建一个 ref 对象,其value值指向另一个对象中的某个属性。
语法:const name = toRef(person,'name')
应用: 要将响应式对象中的某个属性单独提供给外部使用时。
扩展:toRefs
?与toRef
功能一致,但可以批量创建多个 ref 对象,语法:toRefs(person)
<template>
<div>
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{ age }}</h2>
<button @click="age++">改年龄</button>| <button @click="name+='~'">改姓名</button>
</div>
</template>
<script>
import {ref, reactive,toRefs} from 'vue'
export default {
name: 'App',
setup() {
const person = reactive({
name: 'lqz',
age: 19
})
return {
...toRefs(person)
}
},
}
</script>
//对象展开语法
let obj1 = {foo: 'bar', x: 42};
let obj2 = {foo: 'baz', y: 13};
let mergedObj = {...obj1, ...obj2};
console.log(mergedObj)