<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<script type="importmap">
{
"imports": {
"vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.js"
}
}
</script>
<div id="app">
<h1>父组件:</h1>
{{list}}
<h1>子组件:</h1>
<component-a v-model:list="list"></component-a>
</div>
<script type="module">
import {
createApp,
ref,
reactive,
toRaw,
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted
} from 'vue'
//定义B组件
const ComponentA = {
props: {
a: console.log("======props======",this),
list:Array
},
emits:{
d:console.log("======emits======",this),
"update:list":Array
},
setup() {
console.log("======setup======",this)
onBeforeMount(() => {
console.log("======onBeforeMount======",this);
});
onMounted(() => {
console.log("======onMounted======");
});
onBeforeUpdate(() => {
console.log("======onBeforeUpdate======");
});
onUpdated(() => {
console.log("======onUpdated======");
});
onBeforeUnmount(() => {
console.log("======onBeforeUnmount======");
});
onUnmounted(() => {
console.log("======onUnmounted======");
});
return {
}
},
beforeCreate() {
console.log("======beforeCreate======",this)
},
data() {
console.log("======data======")
return {
arr: this.list,
}
},
created() {
console.log("======created======")
},
computed: {
newList() {
console.log("======computed======");
return this.list.length;
}
},
beforeMount(){
console.log("======beforeMount======")
},
mounted(){
console.log("======mounted======")
},
beforeUpdate(){
console.log("======beforeUpdate======")
},
updated(){
console.log("======updated======")
},
beforeDestroy(){
console.log("======beforeDestroy======")
},
destroyed(){
console.log("======destroyed======")
},
watch:{
list:{
handler(oldVal,newVal){
console.log("======watch======")
},
immediate: true
}
},
methods:{
handleEmit(){
console.clear()
this.$emit("update:list",this.list.slice(1))
},
handleSplice(){
console.clear()
this.list.shift()
}
},
template: `
<h1>数组个数:{{newList}}</h1>
<a href="https://cn.vuejs.org/guide/components/props.html#one-way-data-flow">更改对象 / 数组等引用类型的 props</a>
<div style="margin-top:20px">子组件通过emit抛出一个事件来通知父组件做出改变</div>
<button @click="handleEmit">从头删1个数据</button>
<div>子组件直接修改父组件引用数据(避免使用这种方式!!, 引用类型是传地址,所以不像基本数据类型,控制台会告警,使监听事件失效等)</div>
<button @click="handleSplice">从头删1个数据</button>
`
}
const app = createApp({
components: {
ComponentA,
},
setup() {
const list = ref([{
id: 1,
title: 'My journey with Vue'
},
{
id: 2,
title: 'Blogging with Vue'
},
{
id: 3,
title: 'Why Vue is so fun'
}
])
return {
list,
}
}
})
app.mount('#app')
</script>
</body>
</html>
子组件通过emit抛出一个事件来通知父组件做出改变,执行顺序是
子组件直接修改父组件引用数据,执行顺序是
更改对象 / 数组类型的 props
当直接修改对象或数组时,vue不告警,但是应避免这样做,会造成watch和更新的执行顺序问题。
当对象或数组作为 props 被传入时,虽然子组件无法更改 props 绑定,但仍然可以更改对象或数组内部的值。这是因为 JavaScript 的对象和数组是按引用传递,而对 Vue 来说,禁止这样的改动,虽然可能生效,但有很大的性能损耗,比较得不偿失。