Composition API也称为组合式API,实现代码的共享以及重用
Vue3.0 暴露变量必须 return 出来,template中才能使用;
Vue3.2 中 只需要在 script 标签上加上 setup 属性,组件在编译的过程中代码运行的上下文是在 setup() 函数中,无需return,template可直接使用
新的 setup 组件选项在创建组件之前执行,一旦 props 被解析,并充当合成 API 的入口点
由于在执行 setup 时尚未创建组件实例,因此在 setup 选项中没有 this。
这意味着,除了props 之外,将无法访问组件中声明的任何属性——本地状态、计算属性或方法。
setup()接收两个参数 props 和 context
props是响应的 当传入的props更新时会同步更新
但是因为 props 是响应式的,所以不能使用 ES6 解构,因为它会消除 prop 的响应性。
如果需要解构 prop,可以通过使用 setup 函数中的 toRefs 来安全地完成
export default {
props: {
title: String
},
setup(props) {
console.log(props.title)
}
}
context暴露三个属性
export default {
setup(props, context) {
// Attribute (非响应式对象)
// 可以读取所有除了在props当中声明的自定属性以外传递的 自定义属性的值 this.$attrs
// 即所有从父组件传递过来的属性 除去使用props中声明过的
console.log(context.attrs)
// 插槽 (非响应式对象)
console.log(context.slots)
// 触发事件 (方法)
// 用于触发绑定的自定义事件 this.$emit
console.log(context.emit)
}
}
执行 setup 时组件实例尚未被创建。因此只能访问props,attrs,slots,emit属性
用来定义响应式的 字符串、 数值、 数组、Bool类型
对于ref对象而言,读写它的值都需要通过它的value属性
但在模板中使用时不需要.value属性,模板会自行的对于它的结构进行解包
export default {
data() {
return {
}
},
setup() {
let msg = ref("这是setup中的msg");
let list = ref(["1", "2", "3"])
let updateMsg = () => {
alert("触发方法");
msg.value = "改变后的值"
}
return {
msg,
list,
updateMsg
}
},
}
用来定义响应式的对象
export default {
data() {
return {
}
},
setup() {
let msg = ref("这是setup中的msg");
let setupData = reactive({
title: "reactive定义响应式数据的title",
userinfo: {
username: "张三",
age: 20
}
})
let updateMsg = () => {
alert("触发方法");
msg.value = "改变后的值"
}
let updateTitle = () => {
alert("触发方法");
setupData.title = "我是改变后的title"
}
return {
msg,
setupData,
updateMsg,
updateTitle
}
},
}
要改变ref定义的属性名称需要通过 属性名称.value来修改
要改变reactive中定义的对象名称可以直接修改
在响应式地跟踪其依赖项时立即运行一个函数,并在更改依赖项时重新运行它。
与侦听器watch类似 不过在组件创建时会默认执行一次
export default {
name: "WatchEffect",
setup() {
const data = reactive({
count: 1,
num: 1
});
const stop = watchEffect(() => console.log(`侦听器:${data.count}`));
// data.count变化时才会执行
setInterval(() => {
data.count++;
}, 1000);
return {
data,
stop
};
},
};
与原先的侦听器类似,接收三个参数,第一个时要监听的状态,第二个是处理函数,第三个是配置项
对比watchEffect,watch允许我们:
懒执行,也就是说仅在侦听的源变更时才执行回调;
更明确哪些状态的改变会触发侦听器重新运行;
访问侦听状态变化前后的值
export default {
name: "Watch",
setup() {
const a = ref('cc')
const data = reactive({
count1: 0,
count2: 0
});
// 侦听单个数据源
// 不能直接侦听data.count1
let stop1 = watch(data, () =>
console.log("watch1", data.count1, data.count2)
);
// 如果需要监听data.count1 则需要函数返回值的形式
stop1 = watch(() => data.count1, (value, oldValue, onCleanup) =>
console.log("watch1", data.count1, data.count2)
);
// 监听ref属性且进行配置
watch(a, (value, oldValue, onCleanup) => {
console.log(d.value)
}, {
immediate: true
})
// 侦听多个数据源
let stop2 = watch([data], () => {
console.log("watch2", data.count1, data.count2);
});
// 同样需要监听多个对象的值时也需要函数返回值
// 当监听多个数据组成的数组时,在第二个参数的回调函数的参数中对应接收多个数组 每一个对应一个监听的值
stop2 = watch(() => [data.count1, data.count2], ([newCount1, oldCount1], [newCount2, oldCount2]) => {
console.log("watch2", data.count1, data.count2);
});
setInterval(() => {
data.count1++;
}, 1000);
return {
data,
stopAll: () => {
stop1();
stop2();
},
};
},
};
当需要停止对数据的监听时,调用watch的返回值即可
stop()
stop2()
// 当我们使用watch回调无法停止监听时也可以通过设置flag实现
无论watch
还是watchEffect
,在回调函数中获取dom
元素都是更新前的,如果要获取更新后的dom
,需要设置配置项flush: 'post'
watch(source, callback, {
flush: 'post'
})
watchEffect(callback, {
flush: 'post'
})
// 或者直接使用vue3新增的另一个hooks
watchPostEffect(() => {
/* 在 Vue 更新后执行 */
})
与原先的计算属性相同
export default {
name: "解构响应式对象数据",
setup() {
const user = reactive({
firstName: "",
lastName: "",
});
const fullName = computed(() => {
return user.firstName + " " + user.lastName
})
return {
...toRefs(user),
fullName
};
},
};
解构响应式对象数据而不丢失响应性
响应式对象数据如果通过es6…运算符解构就会消除响应性
把一个响应式对象转换成普通对象,该普通对象的每个 property 都是一个 ref ,和响应式对象 property 一一对应
export default {
name: "解构响应式对象数据",
setup() {
const user = reactive({
username: "张三",
age: 10000,
});
return {
...toRefs(user)
};
},
};
传入一个对象(响应式或普通)或ref,返回一个原始对象的只读代理。一个只读的代理是“深层的”
对象内部任何嵌套的属性也都是只读的
export default {
name: "Readonly",
setup() {
const original = reactive({ count: 0 });
const copy = readonly(original);
setInterval(() => {
original.count++;
copy.count++;
// 报警告,Set operation on key "count" failed: target is readonly. Proxy {count: 1}
}, 1000);
return { original, copy };
},
};
defineProps
是一个仅 中可用的编译宏命令,并不需要显式地导入。
在vue3的非语法糖setup
和在vue2
中的写法是 props
, 父组件通过将值传递给子组件,子组件通过defineProps
进行接收。
注意:defineProps()
宏中的参数不可以访问 中定义的其他变量,因为在编译时整个表达式都会被移到外部的函数中。
const props = defineProps<{
foo: String,
bar?: Number
}>()
defineEmits
和 defineProps
一样也是仅用于 ,并且不需要导入。
在vue3的非语法糖setup
中的写法是 emits
,用于子组件触发父组件的的事件,并且进行传值。
defineEmits
的不同点在于,组件要触发的事件可以显式地通过 defineEmits()
宏来声明。
注意:如果一个原生事件的名字 (例如 click
) 被定义在 emits
选项中,则监听器只会监听组件触发的 click
事件而不会再响应原生的 click
事件。
const emit = defineEmits<{
(e: 'submit', num: number): void
}>()
在使用 的时候,组件的实例是默认关闭的不能够通过模板引用或者
$parent
进行被访问的。
通过 defineExpose
可宏来显式指定在 组件中要暴露出去的属性。
const isShow = ref<boolean>(false)
defineExpose({ // 宏来显示指定组件中属性暴露出去
isShow,
});
选项式 API | Hook inside setup |
---|---|
beforeCreate | Not needed* |
created | Not needed* |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeUnmount | onBeforeUnmount |
unmounted | onUnmounted |
errorCaptured | onErrorCaptured |
renderTracked | onRenderTracked |
renderTriggered | onRenderTriggered |
因为 setup 是围绕 beforeCreate 和 created 生命周期钩子运行的,所以不需要显式地定义它们。
换句话说,在这些钩子中编写的任何代码都应该直接在 setup 函数中编写。
export default {
setup() {
// mounted
onMounted(() => {
console.log('Component is mounted!')
})
}
}
provide 和 inject 对父组件可以作为其所有子组件的依赖项提供程序,而不管组件层次结构有多深。
父组件有一个 provide 选项来提供数据,子组件有一个 inject 选项来开始使用这个数据
在非组合式api中
可以传值 但子组件的值改变不能同步到父组件
<!-- src/components/MyMap.vue -->
<template>
<MyMarker />
</template>
<script>
import MyMarker from './MyMarker.vue'
export default {
components: {
MyMarker
},
provide: {
location: 'North Pole',
geolocation: {
longitude: 90,
latitude: 135
}
}
}
</script>
<!-- src/components/MyMarker.vue -->
<script>
export default {
inject: ['location', 'geolocation']
}
</script>
组合式api中
可以传值 且子组件的值改变可以同步到父组件
provide 函数允许通过两个参数定义 property:
property 的 name ( 类型)
property 的 value
<!-- src/components/MyMap.vue -->
<template>
<MyMarker />
</template>
<script>
import { provide } from 'vue'
import MyMarker from './MyMarker.vue
export default {
components: {
MyMarker
},
setup() {
provide('location', 'North Pole')
provide('geolocation', {
longitude: 90,
latitude: 135
})
}
}
</script>
inject 函数有两个参数:
要注入的 property 的名称,一个默认的值 (可选)
<!-- src/components/MyMarker.vue -->
<script>
import { inject } from 'vue'
export default {
setup() {
const userLocation = inject('location', 'The Universe') // 缺省值(默认值):The Universe
const userGeolocation = inject('geolocation')
return {
userLocation,
userGeolocation
}
}
}
</script>
你可能感兴趣的:(Vue,vue.js)