一、单文件组件<script setup>
<script setup> 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。
使用方法:
要使用这个语法,需要将 setup attribute 添加到script 代码块上:
<script setup>
console.log('hello script setup')
</script>
里面的代码会被编译成组件 setup() 函数的内容。这意味着与普通的 <script> 只在组件被首次引入的时候执行一次不同,<script setup> 中的代码会在每次组件实例被创建的时候执行。
相比于普通的 <script> 语法,它具有更多的优势。
1、属性和方法无需返回,可直接使用
使用 script setup 语法糖,不需要 return 和 setup函数,只需要全部定义到 script setup 内。
<template>
{{todoList}}
</template>
<script setup>
let todoList = [
{todo:"我想看海",isCheck:false},
{todo:"我想浪漫",isCheck:true},
]
</script>
2、组件自动注册
在 script setup 语法糖中,引入的组件可以自动注册,不需要再通过 components 进行注册,而且无法指定当前组件的名字,会自动以文件名为主,省去了 name 属性。
<template>
<SetUp></SetUp>
<set-up></set-up>
</template>
<script setup>
import SetUp from "./SetUp.vue"
</script>
而在 setup() 写的组合式 API 中,引入的组件必须在 components 内注册之后才能使用,否则无法正常引入。
3、组件数据传递
父组件给子组件传值时,需要 props 接收。setup( props, context )接收两个参数,props 接收传递的数据,使用 setup() 接收数据如下:
<template>
{{ a }} {{ b }}
</template>
<script>
import { toRefs } from "vue"
export default {
setup(props,context){
const { a,b } = toRefs(props)
return {
a,
b
}
}
}
而 script setup 语法糖接收 props 中的数据时,使用 defineProps 方法来获取,可以修改上述代码为:
<template>
{{ a }} {{ b }}
</template>
<script setup>
import { toRefs } from "vue"
const props = defineProps({
a: String,
b: String
})
const { a, b } = toRefs( props )
</script>
4、获取 attrs、slots 和 emits
setup( props, context )接收两个参数,context 上下文环境,其中包含了属性、插槽、自定义事件三部分。
setup() 内获取如下:
setup(props,context){
const { attrs, slots, emit } = context
// attrs 获取组件传递过来的属性值,
// slots 组件内的插槽
// emit 自定义事件 子组件
}
使用 script setup 语法糖时,
<script setup>
import { useAttrs, useSlots } from 'vue'
const slots = useSlots();
const attrs = useAttrs();
const emits = defineEmits(['getChild']);
</script>
import { defineComponent, onBeforeMount, onMounted, onBeforeUpdate,onUpdated,
onBeforeUnmount, onUnmounted, onErrorCaptured, onRenderTracked,
onRenderTriggered } from "vue";
export default defineComponent({
//beforeCreate和created是vue2的
beforeCreate() {
console.log("------beforeCreate-----");
},
created() {
console.log("------created-----");
},
setup() {
console.log("------setup-----");
// vue3.x生命周期写在setup中
onBeforeMount(() => {
console.log("------onBeforeMount-----");
});
onMounted(() => {
console.log("------onMounted-----");
}); // 调试哪些数据发生了变化
onRenderTriggered((event) => {
console.log("------onRenderTriggered-----",event);
})
},
});
三、Vue2.x和Vue3.0的区别
1、源码体积优化
•Vue3.0中移除了一些不常用的API,如inline-template、filter等
•Tree-shaking使得打包后的项目体积更小(vue2采用面向对象编程的思想,vue3则采用函数式编程的思想。充分利用函数式编程组合大于继承的优势,采用函数式编程更利于逻辑功能的复用,webpack打包时更有利于tree-shaking,更利于代码的压缩,更利于返回值类型校验,压缩后的文件体积更小。)
2、编译优化及重写虚拟DOM——提升了首次渲染和更新的过程
Vue2.x,在vue构建过程中,首先需要将组件的模板编译成render函数。编译的时候会编译静态根节点(需要有一个静态子节点)和静态节点,当组件状态发生变化的时候,会触发update函数从而执行虚拟DOM的patch操作,遍历所有虚拟节点,找到差异,然后再更新到真实节点上。(diff的过程中,会先对比新旧的div以及属性,然后再对比其内部子节点。)
优化:Vue2.x中,通过标记静态根节点后,在diff的时候进行跳过,从而优化了diff的过程;
Vue3中修改了虚拟dom的算法,通过标记和提升所有的静态根节点,先分层次,然后找不变化的层,最后针对变化的层进行diff,只需要对比动态节点内容,更新速度不会再受template大小的影响,而是仅由可变的内容决定。
3、响应式系统升级
(1):Vue2.x
Vue2.x中响应式系统的核心defineProperty。在初始化的时候会编译data中的所有成员,通过defineProperty把对象中的属性转化成getter和setter;
如果data中的属性又是对象的话,需要递归处理每一个子对象的属性。
注:这些都是在初始化的时候进行的,也就是说如果没有使用这个属性的时候也会把他进行响应式的处理;
(2):Vue3.0
Vue3.0中使用Proxy对象重写响应式系统,不需要再初始化的时候遍历所有的属性,如果有多层属性嵌套的话,只有访问某个属性的时候,才会递归处理下一层的属性;
• 可以监听动态新增的属性,而Vue2.x中需要手动调用vue.$set方法
• 可以监听删除的属性
• 可以监听数组索引及length属性