1,双向数据绑定原理发生了改变
vue2的双向数据绑定利用了es5的api object.definepropert(),而vue3中使用了es6的api proxy;
2.vue3支持碎片(Fragments)
就是说在组件可以拥有多个根节点。
vue2
<template>
<div class='form-element'>
<h3> {{ title }} </h3>
</div>
</template>
vue3
<template>
<div class='form-element'>
</div>
<h3> {{ title }} </h3>
</template>
3.Composition API
Vue2与Vue3 最大的区别 — Vue2使用选项类型API(Options API)对比Vue3合成型API(Composition API)
旧的选项型API在代码里分割了不同的属性: data,computed属性,methods,等等。新的合成型API能让我们用方法(function)来分割,相比于旧的API使用属性来分组,这样代码会更加简便和整洁。
vue2
export default {
props: {
title: String
},
data () {
return {
username: '',
password: ''
}
},
methods: {
login () {
// 登陆方法
}
},
components:{
"buttonComponent":btnComponent
},
computed:{
fullName(){
return this.firstName+" "+this.lastName;
}
}
}
vue3
export default {
props: {
title: String
},
setup () {
const state = reactive({ //数据
username: '',
password: '',
lowerCaseUsername: computed(() => state.username.toLowerCase()) //计算属性
})
//方法
const login = () => {
// 登陆方法
}
return {
login,
state
}
}
}
4.建立数据 data
Vue2 - 这里把数据放入data属性中
export default {
props: {
title: String
},
data () {
return {
username: '',
password: ''
}
}
}
在Vue3.0,我们就需要使用一个新的setup()方法,此方法在组件初始化构造的时候触发。
使用以下三步来建立反应性数据:
- 从vue引入reactive
- 使用reactive()方法来声名我们的数据为响应性数据
- 使用setup()方法来返回我们的响应性数据,从而我们的template可以获取这些响应性数据
import { reactive } from 'vue'
export default {
props: {
title: String
},
setup () {
const state = reactive({
username: '',
password: ''
})
return { state }
}
}
template使用,可以通过state.username和state.password获得数据的值。
<template>
<div>
<h3> {{ state.username }} </h3>
</div>
</template>
5.生命周期钩子 — Lifecyle Hooks
Vue2--------------vue3
beforeCreate -> setup()
created -> setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
activated -> onActivated
deactivated -> onDeactivated
- setup() :开始创建组件之前,在beforeCreate和created之前执行。创建的是data和method
- onBeforeMount() : 组件挂载到节点上之前执行的函数。
- onMounted() : 组件挂载完成后执行的函数。
- onBeforeUpdate(): 组件更新之前执行的函数。
- onUpdated(): 组件更新完成之后执行的函数。
- onBeforeUnmount(): 组件卸载之前执行的函数。
- onUnmounted(): 组件卸载完成后执行的函数
若组件被包含,则多出下面两个钩子函数。
- onActivated(): 被包含在中的组件,会多出两个生命周期钩子函数。被激活时执行 。
- onDeactivated(): 比如从 A组件,切换到 B 组件,A 组件消失时执行。
6,v-model
v-model在vue2中和vue3中还是有比较大的区别,特别是在组件上使用的时候
众所周知:v-model是 value 与 input事件的语法糖
如:v-model在vue3中的改变
父组件中调用Child1子组件
<template>
<div>
<div>父组件:{{ money }}</div>
<!-- <Child1 v-model="money" /> v-model 等同于以下-->
<Child1 :model-value="money" @update:modelValue="handler" />
<!-- 等价 -->
<Child1 :modelValue="money" @update:modelValue="handler" />
</div>
</template>
<script setup lang="ts">
import Child1 from './component/child1.vue'
import { ref } from 'vue'
const money = ref(1000)
const handler = (v) => {
money.value = v
}
</script>
<style scoped></style>
1,v-model="money" 不仅仅传值了(modelValue),还多了传的update修改事件(update:modelValue)
<Child1 :model-value="money" @update:modelValue="handler" />
等价: <Child1 v-model="money" />有同样的功能,v-model="money"身上相当于给子组件传递了一个
:model-value="值",和一个自定事件update:modelValue
子组件Child1.vue:
<template>
<div>zi</div>
<button @click="handler">加</button>
</template>
<script setup lang="ts">
const props = defineProps(['modelValue'])
const $emit = defineEmits(['update:modelValue'])
const handler = () => {
$emit('update:modelValue', props.modelValue + 1000)
}
</script>
<style scoped></style>
2,组件可定义多个v-model,因为把vue2中.sync修饰符移除了,采用v-model:xx方式
<Dialog v-model:isShow="isShowDialog" v-model:title="title"/>
3,v-model:xY和v-model:x-y等价
前面的"v-model:isShow"也可以写成"v-model:is-show", vue会自动识别.
<Dialog v-model:isShow="isShowDialog"/>
<!--等价-->
<Dialog v-model:is-show="isShowDialog"/>
7,函数API computed/watch
"computed/watch"等选项都有了函数形式.
const [a,b,c] = [1,2,3]
const total = computed(()=>a+b+c)
watch(total, ()=>{
// list变化了
}, {deep:true})
onMounted(()=>{
alert(1)
})
vue2中这么写:
export default {
computed:{
total(){}
},
watch:{
total(){}
}
mounted(){}
}
8,setup
平级于"data/computed"等字段, 增加了"setup"选项, 这些函数API必须在setup函数内使用, 且必须使用"return"返回数据模板才能使用定义的变量,比如这里的"total"
<script>
export default defineComponent({
setup(){
const [a,b,c] = [1,2,3]
const total = computed(()=>a+b+c)
return {a,b,c,total}
}
})
</script>
总之现在只定义一个setup就够了, "data/computed"等都在setup内部定义就行了, 暂叫他"setup语法"
9,setup语法糖(vue3.2)
vue3.2以后使用vite编译器可以更简单的使用"setup语法":
<script setup>
import {computed} from 'vue'
const [a,b,c] = [1,2,3]
const total = computed(()=>a+b+c)
</script>
只需要在"script"标签上增加"setup"属性, 那么标签内部的代码就会作为"setup"中的代码解析. defineComponent
不用写了, 注意return
返回值也不用写了, 因为默认标签内的变量都会被解析到模板中
setup语法糖,无法定义组件的name(参考)
默认组件的name就是文件的名称,如果想改,要不多加一个script标签,里边不用setup语法糖,利用export {name:''}。
要不就利用一个插件
1,安装一个插件
npm i vite-plugin-vue-setup-extend -D
2,配置
3,script里写name
<script setup name="MyName"></script>
10,vue3优点体现
这些函数API带来的最大好处就是粒度更小, 可以对逻辑进行更细的组合, 所以官方叫新的API"组合API",下面的代码假设我们有"a/b"2种功能逻辑, 用老语法实现如下:
<script>
defineComponent({
data(){
return {a:1,b:2}
},
computed:{
c(){
return this.a + this.b
}
},
watch:{
a(){},
b(){},
},
methods:{
doA(){},
doB(){},
}
})
</script>
用新语法:
<script setup>
import {ref,computed,watch} from 'vue'
const a = ref(1);
const b = ref(2);
const c = computed(()=>a+b)
watch(a,()=>{})
watch(b,()=>{})
function doA(){}
function doB(){}
</script>
看起来好像还不如前者清晰, 继续改造:
import {ref,watch} from 'vue'
export default function(){
const a = ref(1);
watch(a,()=>{})
function doA(){}
return [a,doA]
}
import {ref,watch} from 'vue'
export default function(){
const b = ref(2);
watch(b,()=>{})
function doB(){}
return [b,doB]
}
<script setup>
import {computed} from 'vue'
import useA from './useA.js'
import useB from './useB.js'
const [a,doA] = useA();
const [b,doB] = useB();
const c = computed(()=>a+b)
</script>
随着业务逻辑的复杂, 拆分就需要更细, 组合API的作用就留越大. 参考下面的图, 假想你的代码中还有"C/D/E/F"逻辑, 是不是"组合API"就香了.
题外话: 使用组合api开发的代码可以通过"tree shake"技术让编译后的代码更小, vite编译代码时默认已开启.
编辑器插件
如果选择了vue3开发, 那么就一定要安装Volar插件, 实现代码高亮和语法校验.
创建vue3工程
官方推荐基于vite 创建项目(vue2是基于webpack的vue-cli)