保姆级别Vue2组件通信(面试常问)

在面试过程中,经常会被面试官问的鸦雀无言,但是如果我们日常积累些知识点,等到被面试的时候,就可以和面试官来交流技术。

父子组件通信

绝大部分vue本身提供的通信方式,都是父子组件通信

prop

最常见的组件通信方式之一,由父组件传递到子组件

父组件

<template>
  <div id="app">
    <HelloWorld
      msg="Welcome to Your Vue.js App"
    />
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";

export default {
  components: {
    HelloWorld,
  },
};
</script>
复制代码

子组件

<template>
  <div>
    <h1>{{msg}}</h1>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  props: {
    msg: String,
  },
  created(){
      console.log(this.msg) // 打印出父组件给子组件传递的值 Welcome to Your Vue.js App
  }
};
</script>
复制代码

event(emit)

最常见的组件通信方式之一,当子组件发生了某些事,可以通过event通知父组件

父组件

<template>
  <div id="app" 
:style="{fontSize: postFontSize + 'em'}">
    <HelloWorld
      msg="Welcome to Your Vue.js App"
      @enlarge-text="postFontSize += 0.1"
    />
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";

export default {
  components: {
    HelloWorld,
  },
  data(){
      return {
        postFontSize: 1
      }
  }
};
</script>
复制代码

子组件

<template>
  <div>
    <h1>{{msg}}</h1>
    // 点击按钮后,子组件会触发事件,传递到父组件中,放大字体
   <button @click="$emit('enlarge-text')">放大字号</button>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  props: {
    msg: String,
  },
  
};
</script>
复制代码

styleclass

父组件可以向子组件传递styleclass,它们会合并到子组件的根元素中

示例

父组件

<template>
  <div id="app">
    <HelloWorld
      style="color:red"
      class="hello"
      msg="Welcome to Your Vue.js App"
    />
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";

export default {
  components: {
    HelloWorld,
  },
};
</script>
复制代码

子组件

<template>
  <div class="world" style="text-align:center">
    <h1>{{msg}}</h1>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  props: {
    msg: String,
  },
};
</script>
复制代码

渲染结果:

<div id="app">
  <div class="hello world" style="color:red; text-aling:center">
    <h1>Welcome to Your Vue.js App</h1>
  </div>
</div>
复制代码

attribute

如果父组件传递了一些属性到子组件,但子组件并没有声明这些属性,则它们称之为attribute,这些属性会直接附着在子组件的根元素上

不包括styleclass,它们会被特殊处理

示例

父组件

<template>
  <div id="app">
    <!-- 除 msg 外,其他均为 attribute -->
    <HelloWorld
      data-a="1"
      data-b="2"
      msg="Welcome to Your Vue.js App"
    />
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";

export default {
  components: {
    HelloWorld,
  },
};
</script>
复制代码

子组件

<template>
  <div>
    <h1>{{msg}}</h1>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  props: {
    msg: String,
  },
  created() {
    console.log(this.$attrs); // 得到: { "data-a": "1", "data-b": "2" }
  },
};
</script>
复制代码

渲染结果:

<div id="app">
  <div data-a="1" data-b="2">
    <h1>Welcome to Your Vue.js App</h1>
  </div>
</div>
复制代码

子组件可以通过inheritAttrs: false配置,禁止将attribute附着在子组件的根元素上,但不影响通过$attrs获取

natvie修饰符

在注册事件时,父组件可以使用native修饰符,将事件注册到子组件的根元素上

示例

父组件

<template>
  <div id="app">
    <HelloWorld @click.native="handleClick" />
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";

export default {
  components: {
    HelloWorld,
  },
  methods: {
    handleClick() {
      console.log(1);
    },
  },
};
</script>
复制代码

子组件

<template>
  <div>
    <h1>Hello World</h1>
  </div>
</template>
复制代码

渲染结果

<div id="app">
  <!-- 点击该 div,会输出 1 -->
  <div>
    <h1>Hello World</h1>
  </div>
</div>
复制代码

$listeners

子组件可以通过$listeners获取父组件传递过来的所有事件处理函数, 爷爷组件

<template>
    <div class="father-page">
        <div>这是父组件</div>
        <child-1 @child2Info="getInfo"></child-1>
    </div>
</template>
 
<script>
    import child1 from './Child1'
    export default {
        name: 'Father',
        components:{child1},
        methods: {
            getInfo:function(data){
                console.log(data)
                //这是子组件1-1-1发送的信息
            }
        }
    }
</script>
复制代码

父亲组件 child-1

<template>
    <div class="child1-page">
        <div>这是子组件-1</div>
        <child-2 v-on="$listeners"></child-2>
    </div>
</template>
 
<script>
    import child2 from "./Child2"
    export default {
        name: 'Child1',
        components:{child2},
    }
</script>
复制代码

孙子组件

<template>
    <div>这是子组件1-1</div>
</template>
<script>
    export default {
        mounted: function() {
            this.$emit("child2Info","这是子组件1-1-1发送的信息")
        }
    };
</script>
复制代码

可以在子孙组件中执行祖先组件的函数,从而实现数据传递。 demo或小型项目可以使用listeners进行数据传递,中大型项目不推荐,数据流会变的难于理解。‘listeners进行数据传递,中大型项目不推荐,数据流会变的难于理解。 `listeners`的真正目的是将所有的事件监听器指向这个组件的某个特定的子元素。

v-model

v-model 实际上是vue给表单做单的一个双向数据绑定

<input v-model="aaa" />
复制代码

等价于

<input
  :value="aaa"
  @input="aaa = $event.target.value"
>
复制代码

sync修饰符

v-model的作用类似,用于双向绑定,不同点在于v-model只能针对一个数据进行双向绑定,而sync修饰符没有限制

示例

子组件

<template>
  <div>
    <p>
      <button @click="$emit(`update:num1`, num1 - 1)">-</button>
      {{ num1 }}
      <button @click="$emit(`update:num1`, num1 + 1)">+</button>
    </p>
    <p>
      <button @click="$emit(`update:num2`, num2 - 1)">-</button>
      {{ num2 }}
      <button @click="$emit(`update:num2`, num2 + 1)">+</button>
    </p>
  </div>
</template>

<script>
export default {
  props: ["num1", "num2"],
};
</script>
复制代码

父组件

<template>
  <div id="app">
    <Numbers :num1.sync="n1" :num2.sync="n2" />
    <!-- 等同于 -->
    <Numbers
      :num1="n1"
      @update:num1="n1 = $event"
      :num2="n2"
      @update:num2="n2 = $event"
    />
  </div>
</template>

<script>
import Numbers from "./components/Numbers.vue";

export default {
  components: {
    Numbers,
  },
  data() {
    return {
      n1: 0,
      n2: 0,
    };
  },
};
</script>
复制代码

v-model VS .sync

先明确一件事情,在 vue 1.x 时,就已经支持 .sync 语法,但是此时的 .sync 可以完全在子组件中修改父组件的状态,造成整个状态的变换很难追溯,所以官方在2.0时移除了这个特性。然后在 vue2.3时,.sync又回归了,跟以往不同的是,现在的.sync完完全全就是一个语法糖的作用,跟v-model的实现原理是一样的,也不容易破环院有的数据模型,所以使用上更安全也更方便。

  • 两者都是用于实现双向数据传递的,实现方式都是语法糖,最终通过 prop + 事件 来达成目的。
  • vue 1.x 的 .sync 和 v-model 是完全两个东西,vue 2.3 之后可以理解为一类特性,使用场景略微有区别
  • 当一个组件对外只暴露一个受控的状态,切都符合统一标准的时候,我们会使用v-model来处理。.sync则更为灵活,凡是需要双向数据传递时,都可以去使用。

$parent$children

在组件内部,可以通过$parent$children属性,分别得到当前组件的父组件和子组件实例

$slots 插槽

Vue.compopnent('my-cmp', {
  template: `
    <div class="container">
      <header>
        <slot name="header"></slot>
      </header>
      <main>
        <slot></slot>
      </main>
      <footer>
        <slot name="footer"></slot>
      </footer>
    </div>
  `
})
复制代码

使用时

<my-cmp>
  <template v-slot:header>
    <h1>头部</h1>
  </template>

  <p>内容</p>
  <p>内容</p>

  <template v-slot:footer>
    <p>底部</p>
  </template>
</my-cmp>
复制代码

ref

父组件可以通过ref获取到子组件的实例

$parent

可以在子组件中访问实例的数据。

对于 demo 或非常小型的有少量组件的应用来说这是很方便的。中大型项目不适用。会使应用难于调试和理解。

$children

可以在父组件中访问实例的数据。

对于 demo 或非常小型的有少量组件的应用来说这是很方便的。中大型项目不适用。会使应用难于调试和理解

跨组件通信

ProvideInject

示例

// 父级组件提供 'foo'
var Provider = {
  provide: {
    foo: 'bar'
  },
  // ...
}

// 组件注入 'foo'
var Child = {
  inject: ['foo'],
  created () {
    console.log(this.foo) // => "bar"
  }
  // ...
}
复制代码

详见:cn.vuejs.org/v2/api/?#pr…

router

如果一个组件改变了地址栏,所有监听地址栏的组件都会做出相应反应

最常见的场景就是通过点击router-link组件改变了地址,router-view组件就渲染其他内容

vuex

适用于大型项目的数据仓库

store模式

适用于中小型项目的数据仓库

// store.js
const store = {
  loginUser: ...,
  setting: ...
}

// compA
const compA = {
  data(){
    return {
      loginUser: store.loginUser
    }
  }
}

// compB
const compB = {
  data(){
    return {
      setting: store.setting,
      loginUser: store.loginUser
    }
  }
}
复制代码

eventbus

组件通知事件总线发生了某件事,事件总线通知其他监听该事件的所有组件运行某个函数

Vue.prototype.$bus = new Vue();
复制代码

Vue.component(‘cmp-a’, {
data () {
return {
a: ‘a’
}
},
methods: {
onClick () {
this. b u s . bus. bus.on(‘click’, this.a)
}
},
template: <div> <button @click="onClick">点击</button> </div>,
})
复制代码

Vue.component('cmp-a', {
  mounted () {
    this.$bus.$on('click', data => {
      console.log(data);  // 拿到a的数据
    })
  },
  template: `
    <div>b</div>
  `,
})
复制代码
```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

twinkle||cll

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值