Fork me on GitHub

vue3(四)(生命周期,父子组件传参,动态组件)

组件的生命周期

简单来说就是一个组件从创建 到 销毁的 过程 成为生命周期

 

 

在我们使用Vue3 组合式Api是没有 beforeCreate 和 created 这两个生命周期的,用setup函数代替,但setup又是在beforeCreate和created之前执行。

<template>
   <div>
     <input type="text" v-model="message">
   </div>
</template>
 
<script setup lang="ts">
import { ref ,onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted} from 'vue'
  let message = ref<string>('hello')
  console.log('setup')
  onBeforeMount(()=>{
    console.log('创建之前') //在组件DOM实际渲染安装之前调用。在这一步中,根元素还不存在。
  })
  onMounted(()=>{
    console.log('创建完成') //在组件的第一次渲染后调用,该元素现在可用,允许直接DOM访问
  })
  onBeforeUpdate(()=>{
    console.log('更新之前') //数据更新时调用,发生在虚拟 DOM 打补丁之前
  })
  onUpdated(()=>{
    console.log('更新完成') //DOM更新后,updated的方法即会调用。
  })
  onBeforeUnmount(()=>{
    console.log('销毁之前') //在卸载组件实例之前调用。在这个阶段,实例仍然是完全正常的。
  })
  onUnmounted(()=>{
    console.log('销毁完成') //卸载组件实例后调用。调用此钩子时,组件实例的所有指令都被解除绑定,所有事件侦听器都被移除,所有子组件实例被卸载
  })

</script>
 
<style>
</style>

setup函数在script标签上写是语法糖,还可以写成函数形式,但是要return出来

<template>
  <div class="about">
    <h1>{{ msg }}</h1>
  </div>
</template>

<script>
import {reactive} from 'vue'
export default {
  setup() {
    let msg=reactive({name:'hello'})
    return {msg}
  },
}
</script>

  

父子组件传参

方案一

vue3中,新增了 defineComponent ,它并没有实现任何的逻辑,只是把接收的 Object 直接返回,它的存在是完全让传入的整个对象获得对应的类型,它的存在就是完全为了服务 TypeScript 而存在的

普通的组件就是一个普通的对象,既然是一个普通的对象,那自然就不会获得自动的提示,加上 defineComponent() 之后,就完全不一样了,可以获得自动提示,vue2、vue3的自动提示都有

父组件

<template>
  <div class="about">
    <h1>{{ msg }}</h1>
    <HelloWorld title="我是标题"> </HelloWorld>
  </div>
</template>

<script>
import HelloWorld from '../components/HelloWorld.vue'
import {reactive,defineComponent} from 'vue'
export default defineComponent({
  name:"AboutView",
  components:{
    HelloWorld
  },
  setup() {
    let msg=reactive({name:'hello'})
    return {msg}
  },
})
</script>

  

子组件

<template>
  <div class="hello">
    <h1>{{ title }}</h1>
    <h3>这是HelloWorld组件</h3>  
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';

export default defineComponent({
  name: 'HelloWorld',
  props: {
    title: String,
  },
  setup(props){
    console.log(props.title)
  }
});
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="less">
h3 {
  margin: 40px 0 0;
}
</style>

 

方案二

子组件通过defineProps接受传过来的值  

如果defineProps报错,找到eslint.js文件,在env处添加代码  'vue/setup-compiler-macros': true,重启即可解决,如图

 

 

父组件

<template>
   <div>
     <input type="text" v-model="message">
     <HelloWorld title='我是标题' :data="data"> </HelloWorld>
   </div>
</template>
 
<script setup lang="ts">
import HelloWorld from '../components/HelloWorld.vue'
import { ref ,reactive} from 'vue'
  let message = ref<string>('hello')
 
  const data = reactive<number[]>([1, 2, 3])

</script>
 
<style>
</style>

  

子组件

<template>
    <div class="HelloWorld">
       子组件
        <h1>{{ title }}</h1> 
        <div>{{ data }}</div>
    </div>
</template>
 
<script setup lang="ts">
defineProps<{
    title:string,
    data:number[]
}>()
</script>

  

如果你使用的不是TS

defineProps({
    title:{
        default:"",
        type:String
    },
    data:Array
})

 

TS 特有的默认值方式

withDefaults是个函数也是无须引入开箱即用接受一个props函数第二个参数是一个对象设置默认值

type Props = {
    title?: string,
    data?: number[]
}
withDefaults(defineProps<Props>(), {
    title: "张三",
    data: () => [1, 2, 3]
})

  

子组件给父组件传参

是通过defineEmits派发一个事件

子组件

<template>
    <div class="HelloWorld">
        <button @click="clickTap">派发给父组件</button>
    </div>
</template>
 
<script setup lang="ts">
import { reactive } from 'vue'
const list = reactive<number[]>([4, 5, 6])
 
const emit = defineEmits(['on-click'])
const clickTap = () => {
    emit('on-click', list)
}
</script>

  

父组件

<template>
   <div>
     <HelloWorld @on-click="getList"> </HelloWorld>
   </div>
</template>
 
<script setup lang="ts">
import HelloWorld from '../components/HelloWorld.vue'
import { reactive } from 'vue';
 
const data = reactive<number[]>([1, 2, 3])
 
const getList = (list: number[]) => {
    console.log(list,'父组件接受子组件');

}
</script>
 
<style>
</style>

  

子组件暴露给父组件内部属性

通过defineExpose

我们从父组件获取子组件实例通过ref

子组件  

<template>
    <div class="HelloWorld">
        <button @click="clickTap">派发给父组件</button>
    </div>
</template>
 
<script setup lang="ts">
import { reactive } from 'vue'
const list = reactive<number[]>([4, 5, 6])
 
const emit = defineEmits(['on-click'])
const clickTap = () => {
    emit('on-click', list)
}
 
 //子组件暴露给父组件内部属性
defineExpose({
    list
})
</script>

  

父组件

<template>
   <div>
     <HelloWorld ref="helloRef" @on-click="getList"> </HelloWorld>
   </div>
</template>
 
<script setup lang="ts">
import HelloWorld from '../components/HelloWorld.vue'
import { reactive,ref } from 'vue';
 
const helloRef = ref(null)
const data = reactive<number[]>([1, 2, 3])
 
const getList = (list: number[]) => {
    console.log(list,'父组件接受子组件');
    console.log(helloRef.value)
}
</script>
 
<style>
</style>

 

动态组件

什么是动态组件 就是:让多个组件使用同一个挂载点,并动态切换,这就是动态组件。

在挂载点使用component标签,然后使用v-bind:is=”组件”

使用场景

tab切换 居多

注意事项

1.在Vue2 的时候is 是通过组件名称切换的 在Vue3 setup 是通过组件实例切换的

2.如果你把组件实例放到Reactive Vue会给你一个警告runtime-core.esm-bundler.js:38 [Vue warn]: Vue received a Component which was made a reactive object. This can lead to unnecessary performance overhead, and should be avoided by marking the component with `markRaw` or using `shallowRef` instead of `ref`.
Component that was made reactive:

这是因为reactive 会进行proxy 代理 而我们组件代理之后毫无用处 节省性能开销 推荐我们使用shallowRef 或者 markRaw 跳过proxy 代理

修改如下

<template>
  <div class="about">
    <button v-for="item in tab" :key="item.name" @click="onchange(item)">
      {{ item.name }}
    </button>
    <component :is="current.comName"></component>
  </div>
</template>

<script setup lang="ts">
import { reactive, markRaw } from "vue";
import ComA from "../components/ComA.vue";
import ComB from "../components/ComB.vue";
type Tabs = {
  name: string;
  comName: any;
};
const tab = reactive<Tabs[]>([
  {
    name: "A组件",
    comName: markRaw(ComA),
  },
  {
    name: "B组件",
    comName: markRaw(ComB),
  },
]);
let current = reactive({
  comName: tab[0].comName,
});
const onchange = (val) => {
  current.comName = val.comName;
};
</script>

 

————————————————
版权声明:本文为CSDN博主「小满zs」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq1195566313/article/details/122850170

 

posted @ 2022-11-02 12:02  小白不白10  阅读(2174)  评论(0编辑  收藏  举报