• 【面试题-Vue】常见问题二、组件类


    一、组件之间数据如何传递?

    props
    $emit $on(vue3废弃)
    $children(vue3废弃) $parent
    $attrs $listeners(vue3废弃)
    ref
    $root
    eventbus
    vuex

    二、Vue父子组件和兄弟组件间通信有哪几种方式?

    父子组件通信

    第一种:props和$emit()

    父组件通过自定义属性给子组件传值,子组件用props接收;
    通过组件标签进行方法的传递,子组件$emit触发方法

    <template>
      <div id="app">
        <div>父组件:{{message}}</div>
        <ChildrenComponet :message="message" @changeMsgFn="message=$event"/>
      </div>
    </template>
    
    <script>
    import ChildrenComponet from './components/ChildrenComponet.vue'
    export default {
      name: 'App',
      data(){
        return{
          message:'默认数据'
        }
      },
      components: {
        ChildrenComponet
      },
      methods:{
        changeMessage(msg){
          this.message = 'Bye';
        }
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    子组件

    <template>
      <div>
          子组件:{{message}}
          <button @click="handleClick">按钮</button>
      </div>
    </template>
    <script>
    export default {
      props:['message'],
      methods:{
        handleClick(){
          this.$emit('changeMsgFn','Bye')
        }
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    第二种、$parent 和 $children

    通过 $ parent来获取父组件的实例,从而获取父组件的属性和方法
    通过this.$ children得到的是一个子组件实例的数组

    <template>
      <div id="app">
        <div>父组件:{{message}}</div>
        <ChildrenComponet :message="message"/>
        <button @click="changeChildrenNumber">改变子number</button>
      </div>
    </template>
    <script>
    import ChildrenComponet from './components/ChildrenComponet.vue'
    export default {
      name: 'App',
      data(){
        return{
          message:'默认数据'
        }
      },
      components: {
        ChildrenComponet
      },
      methods:{
        changeChildrenNumber(){
          this.$children[0].number = 50
        }
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    子组件

    <template>
      <div>
          子组件:{{number}}
          <button @click="handleClick">按钮</button>
      </div>
      
    </template>
    
    <script>
    
    export default {
      data(){
        return {
          number:'初始number'
        }
      },
      props:['message'],
      methods:{
        handleClick(){
          this.$parent[0].message = '测试$parent,我是子组件'
        }
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    第三种,provide和inject

    父组件:

    <template>
      <div id="app">
        <ChildrenComponet/>
      </div>
    </template>
    <script>
    import ChildrenComponet from './components/ChildrenComponet.vue'
    export default {
      name: 'App',
      provide:{
        message:"hello"
      },
      components: {
        ChildrenComponet
      },
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    子组件

    <template>
      <div>
          子组件:{{message}}
      </div>
    </template>
    <script>
    export default {
      inject:['message'],
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    第四种、$attrs $listeners

    父组件

    <template>
      <div id="app">
        ------父组件------
        <div>姓名:{{ name }}</div>
        <div>年龄:{{ age }}</div>
        <ChildrenComponet :name="name" :age="age" @changeName="changeName"/>
      </div>
    </template>
    <script>
    import ChildrenComponet from './components/ChildrenComponet.vue'
    export default {
      name: 'App',
      data(){
        return{
          name:'小米',
          age: 33,
        }
      },
      components: {
        ChildrenComponet
      },
      methods:{
        changeName(){
          this.name = '小夏'
        }
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    子组件

    <template>
      <div>
          ------子组件------
          姓名:{{$attrs.name}}
          年龄:{{$attrs.age}}
          <button @click="$listeners.changeName">按钮</button>
          <GrandChild v-bind="$attrs" />
      </div>
    </template>
    <script>
    import GrandChild from './GrandChild.vue'
    export default {
      components:{
        GrandChild
      },
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    孙组件

    <template>
      <div>
          ------孙组件------
          姓名:{{$attrs.name}}
          年龄:{{$attrs.age}}
      </div>
    </template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    第五种、ref

    通过ref得到子组件的实例,进而得到子组件的方法和属性

     ------父组件------
        <ChildrenComponet ref="childComp"/>
        ...
         this.$refs.childComp.changeAge()
    
    • 1
    • 2
    • 3
    • 4
     ------子组件------
       changeAge(){
          this.age = 50
        }
    
    • 1
    • 2
    • 3
    • 4

    兄弟组件之间通信

    第一种、通过共同的父亲进行传递信息

    第二种、EventBus $emit $on

    //eventBus原理就是利用和emit 并实例化一个全局 vue 实现数据共享
    //main.js
        Vue.prototype.$bus=new Vue()
    //传值组件
        this.$bus.$emit('eventTarget','值')
    //接收组件
        this.$bus.$on('eventTarget',value=> console.log(value))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    第三种、通过PubSub通讯

    下载npm install pubsub-js --save
    兄弟组件:

    childone.vue
    ...
    <button @click="pubsubBrotherMsg">send brother msg by pubsub</button>
    ...
    //script
    import PubSub from 'pubsub-js'
    	methods: {
    	   pubsubBrotherMsg (){
    	       PubSub.subscribe('pubsubMsg',this.commonMsg)
    	   },
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    childtwo.vue
    ...
    import PubSub from 'pubsub-js'
       data(){
           return {
               pubsubMsg:''
           }
       },
     mounted() {
     	/*msg:回调函数第一个参数,必须传*/
    	  PubSub.subscribe('pubsubMsg',(msg,data) => {
    	      this.pubsubMsg = data
    	  } )
      }
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    第四种、通过Vuex

    除此之外,还有mixin,localStorage,sessionStorage等都可以实现。

    三、子组件可不可以修改父组件传递的 Prop ?说明原因

    不可以修改,
    组件化开发过程中有个单项数据流原则,不在子组件中修改父组件是个常识问题。

    所有的 prop 都使得其父子之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父组件的状态,从而导致你的应用的数据流向难以理解。另外,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器控制台中发出警告

    实际开发过程中有两个场景会想要修改一个属性:
    1.这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。在这种情况下,最好定义一个本地的 data,并将这个 prop 用作其初始值:

    const props = defineProps(['initialCounter'])
    const counter = ref(props.initialCounter)
    
    • 1
    • 2

    2.这个 prop 以一种原始的值传入且需要进行转换。在这种情况下,最好使用这个 prop 的值来定义一个计算属性:

    const props = defineProps(['size'])
    // prop变化,计算属性自动更新
    const normalizedSize = computed(() => props.size.trim().toLowerCase())
    
    • 1
    • 2
    • 3

    3.实践中如果确实想要改变父组件属性应该emit一个事件让父组件去做这个变更。注意虽然我们不能直接修改一个传入的对象或者数组类型的prop,但是我们还是能够直接改内嵌的对象或属性。

    四、父组件和子组件生命周期钩子执行顺序是什么?

    五、< keep-alive>

    < keep-alive > 包裹动态组件时,会被缓存不活动的组件实例,而不是销毁它们。
    < keep-alive > 是个抽象组件,它自身不会渲染一个DOM元素,也不会出现在组件的父组件链中。

    六、Vue中如何扩展一个组件

    逻辑扩展: mixins、extends、composition api;
    内容扩展: slots;
    常见的组件扩展方法有:mixins,slots,extends等

    混入mixins是分发 Vue组件中可复用功能的非常灵活的方式。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。

    插槽slots主要用于vue组件中的内容分发,也可以用于组件扩展。
    如果要精确分发到不同位置可以使用具名插槽,如果要使用子组件中的数据可以使用作用域插槽。

    混入的数据和方法不能明确判断来源且可能和当前组件内变量产生命名冲突,vue3中引入的composition api,可以很好解决这些问题,利用独立出来的响应式模块可以很方便的编写独立逻辑并提供响应式的数据,然后在setup选项中组合使用,增强代码的可读性和维护性。

  • 相关阅读:
    js检测一个元素是否在另一个元素内部的原生方法document.caretRangeFromPoint
    乒乓操作实例讲解-FIFO
    金属压块液压打包机比例阀放大器
    【思维构造】Sequence Master—CF1806C
    癫痫脑电信号基础知识
    Chrome Dev Tools
    线上线程池配置错误导致服务故障
    多位数按键操作(不闪烁)
    数字音频工作站FL Studio 21中文版下载及电音编曲要用乐理吗 电音编曲步骤
    好用的方法记录
  • 原文地址:https://blog.csdn.net/ZMN0057/article/details/127913043