// 注册全局组件
import HelloWorld from '@/components/HelloWorld.vue'
const app = createApp(App)
//全局挂载属性和方法
// 方法一:
app.config.globalProperties.$Test = () => {
return '全局挂载属性和方法'
}
// 方法二:提供/注入 后续详细介绍
// app.provide('$Test', 'hi')
app.use(store).use(router).component('HelloWorld', HelloWorld).provide('$Test', 'hi').mount('#app')
// .vue文件
setup(){
// 接收方法一
const { ctx } = getCurrentInstance()
let test1 = ctx.$Test
// 接收方法二
let test2 = inject('$Test')
}
setup:
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png" />
<div @click="plusOne">{{ name }}-{{ age }}</div>
<Child />
<HelloWorld msg="Welcome to Your Vue.js App" />
</div>
</template>
setup(props, context)
// props是一个形参, 组件接收的props数据可以访问到
// context上下文对象,可以通过context来访问vue的实例this
// Attribute (非响应式对象)
// console.log(context.attrs)
// 插槽 (非响应式对象)
// console.log(context.slots)
// 触发事件 (方法)
// console.log(context.emit)
// 也可写成setup(props, { attrs, slots, emit })
{
/**
1、setup函数处于生命周期beforeCreate和Created两个钩子函数之间,无法使用data和methods的数据和方法,this为undefined
2、setup函数是 Composition API(组合API)的入口
3、方法和变量需要return出去,不然无法使用
**/
const { ctx } = getCurrentInstance()
// ref将setup函数声明变为响应式,包含且仅有一个value属性
let name = ref("xxx");
let age = ref(18);
// reactive 为引用类型添加响应式
let r = reactive({a:1, b: {c:2}})
function plusOne() {
age.value ++
}
// 使用watch
watch(age, (newVal, oldVal) => {
// console.log(newVal, oldVal)
})
// 使用computed
const counter = ref(0)
const twiceTheCounter = computed(() => counter.value * 2)
counter.value++
// console.log(counter.value) // 1
// console.log(twiceTheCounter.value) // 2
// 返回的内容整个组件内都可以直接使用
return {
name,
age,
r,
plusOne
};
onBeforeMount(() => {});
onMounted(() => {});
onBeforeUpdate(() => {});
onUpdated(() => {});
onBeforeUnmount(() => {});
onUnmounted(() => {});
onRenderTracked((key, target, type) =>{
// console.log({ key, target, type });
})
// 可监听到数据改变
onRenderTriggered(({ key, target, type }) => {
// console.log({ key, target, type });
})
},
provide 和 inject
grdFather.vue
import father from '@/components/father'
import { provide } from 'vue'
export default {
name: 'grdFather',
components: {father},
setup(){
let grdFather = ref('comefrom grafather')
// readonly包裹后可以在组件内引用时不被改变
provide('grdFather', grdFather)
// provide('grdFather', readonly(grdFather))
}
}
father.vue
import son from '@/components/son'
import { inject } from 'vue'
export default {
name: 'father',
components: {son},
setup(){
let value= inject('grdFather')
console.log(1, value)
return {
val
}
}
}
son.vue
import { inject } from 'vue'
export default {
name: 'father',
setup(){
let value= inject('grdFather')
console.log(2, value)
return {
val
}
}
}
vue3和vue2的比较
Vue3使用Proxy替代了defineProperty
Object.defineProperty(obj,prop,descriptor) 的问题主要有三个:
obj
要定义属性的对象。
prop
要定义或修改的属性的名称或 Symbol 。
descriptor
要定义或修改的属性描述符。
let myobj = {};
Object.defineProperty(myobj,"name",{
configurable:true,//configurable 给的说明是 如果为 false , 那么对象属性不可以修改, 不可以删除. true则相反
/*enumerable可枚举;
设置为true后可以用这4种方式去操作属性
1.
for(let i in myobj){
console.log(i);
}
2.
Object.keys();
3.
JSON.stringify
4.
Object.assign
*/
enumerable:true,
get(){//当获取属性的时候会进入get方法,可以对获取的值进行修改操作后返回 (必须返回值)或者获取的就是 undefined
//value 内置属性 获取对象属性值
return value;
},
set(newValue){//set方法监听设置的值 newValue参数获取要改变的值
//value 内置属性 可以对对象属性的做更改
//value="dd";
value = newValue;
}
})
- 不能监听数组的变化
- 只能劫持对象的属性,从而需要对每个对象,每个属性进行遍历
- 必须深层遍历嵌套的对象
Proxy(target, handler)的特点:
let myobj = {};
//Proxy必须实例化 返回新的对象
//用起来比较方便 主要传入要劫持的对象,不用每个属性设置劫持
let obj = new Proxy(myobj,{
get(target,key){//target 表示当前实例的对象 key 表示获取属性名
console.log("get..")
return target[key];
},
set(target,key,value){//target 表示当前实例的对象 key 表示获取属性名 value获取当前属性的值
target[key] = value;
}
})
- 针对对象:针对整个对象,而不是对象的某个属性,所以也就不需要对keys进行遍历
- 支持数组:Proxy不需要对数组的方法进行重载
- Proxy的第二个参数有13种拦截方法
diff算法
vue2中diff算法思路:
diff算法采用两端比较的算法,同时从新旧VNode的两端开始进行比较,借助key值找到可复用的节点,再进行相关操作。
vue3中diff算法思路:
在创建VNode时就确定其类型,以及在mount/patch的过程中采用位运算来判断一个VNode的类型,在这个基础上再配合核心的diff算法。在创建虚拟dom树的时候,会添加一个PatchFlags(静态标记),进行对比的时候就直接对比带有静态标记的节点。
静态提升
不参与更新的内容节点做静态提升,渲染时直接复用
Tree-shaking友好
常用的API value、computed、watch等都是从vue中使用import引进来的,所以支持tree-shaking。即如果没有使用这些api,那么这些相应的代码就不会被打包,缩小了文件大小。