专栏首页女程序员的日常_LinVue.js的组件、组件间通信

Vue.js的组件、组件间通信

目录:

  1. 组件的种类:vue-router产生的每个页面、基础组件、业务组件
  2. Vue.js组件的三个API:prop、event、slot
  3. Vue.js组件的通信方式:
    • ref:给元素或组件注册引用信息;
    • parent/children:访问父 / 子实例。
    • provide/inject
    • 运用$emit实现dispatch和broadcast
    • 找到任意组件实例---findComponents 系列方法

组件的种类

  • 由vue-router产生的每个页面,本质上也是一个组件(.vue),主要承载当前页面的HTML结构,包括数据获取、整理……。一般不会有props选项和自定义事件,因为它作为路由的渲染、不会被复用,因此也不会对外提供接口。
  • 不包含业务,独立、具体功能的基本组件,比如日期选择器、模态框。
  • 业务组件。在业务中被多个页面复用,在当前项目中会用到,不具有通用性。

Vue.js组件的三个API:prop、event、slot

props

props定义了这个组件有哪些可配置的属性,props最好用对象的写法,这样可以针对每个属性设置类型、默认值或自定义校验属性的值。

下面封装一个组件

<template>
  <button :class="'i-button-size' + size" :disabled="disabled"></button>
</template>
<script>
  export default{
    props:{
      size:{
        default: 'default',
        validator(value){
          return oneOf(value,['small','large','default'])
        }
      },
      disabled:{
        type: Boolean,
        default: false
      }
    }
  }
</script>

组件里定义的props,都是单向数据流,只能通过父级修改,组件自己不能修改props的值,只能修改定义在data里的数据,非要修改需要通过自定义事件通知父级。

在使用组建时也可以传入一些标准的html特性,如id 、class

<i-button id="btn1" class="btn-submit"></i-button>

这些html特性,组件中的button元素会继承,不需要通过props属性传递。这个属性是默认支持的,如果不期望开启,在组件选项中设置 inheritAttrs : false。

slot插槽

如果要给上面的<i-button>添加文字,就要用到插槽slot,它可以分发组件的内容。

<template>
  <button :class="'i-button-size' + size" :disabled="disabled">
    <slot></slot>
  </button>
</template>
<i-button>按钮 1</i-button>
<i-button>
  <strong>按钮 2</strong>
</i-button>

当需要多个插槽时,可以设置具名插槽

<template>
  <button :class="'i-button-size' + size" :disabled="disabled">
    <slot name="icon"></slot>
    <slot></slot>
  </button>
</template>
<i-button>
  <i-icon slot="icon" type="checkmark"></i-icon>
  按钮 1
</i-button>

在slot中也可以设置默认内容,当父级没有任何slot时,会展示如下:

<slot>提交</slot>

Event事件

绑定事件:

<template>
  <button @click="clickBtn"></button>
</template>
<script>
  export default{
    methods:{
      clickBtn(){
        this.$emit('on-click','params')
      }
    }
  }
</script>

使用

<i-button @on-click="clickComponent"></i-button>

或者写成

<i-button @click.native="clickComponent"></i-button>

.native 修饰符,为了区别原生的click和自定义click事件。在组件内调用了on-click方法,如果不使用.native修饰符就不能调用原生click事件。

Vue.js组件的通信(基本)

Vue内置的通信手段一般有两种

  • ref:给元素或组件注册引用信息;
  • parent/children:访问父 / 子实例。

Vue.js组件的通信(其他)

一、provide/inject(主要解决子组件获取上级组件的状态,主动提供与依赖注入的关系)

Vue.js 2.2.0版本后新增的API。这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在上下游关系成立的时间里始终生效。

provide和inject主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。

用法:

// A.vue
export default {
  provide: {
    name: 'Aresn'  // 将name属性提供给所有子组件
  }
}

// B.vue
export default {
  inject: ['name'], // 注入从A组件中提供的name变量
  mounted () {
    console.log(this.name);  // Aresn
  }
}

provide、inject绑定并不是可响应的。

二、运用$emit实现dispatch和broadcast

dispatch和broadcast的功能:

  • 在子组件调用 dispatch 方法,向上级指定的组件实例(最近的)上触发自定义事件,并传递数据,且该上级组件已预先通过$on 监听了这个事件;
  • 相反,在父组件调用 broadcast 方法,向下级指定的组件实例(最近的)上触发自定义事件,并传递数据,且该下级组件已预先通过 $on 监听了这个事件。
// 部分代码省略
import Emitter from '../mixins/emitter.js'

export default {
  mixins: [ Emitter ],
  methods: {
    handleDispatch () {
      this.dispatch();  
    },
    handleBroadcast () {
      this.broadcast();  
    }
  }
}
function broadcast(componentName, eventName, params) {
  this.$children.forEach(child => {
    const name = child.$options.name;
    if (name === componentName) {
      child.$emit.apply(child, [eventName].concat(params));
    } else {
      broadcast.apply(child, [componentName, eventName].concat([params]));
    }
  });
}
export default {
  methods: {
    dispatch(componentName, eventName, params) {
      let parent = this.$parent || this.$root;
      let name = parent.$options.name;

      while (parent && (!name || name !== componentName)) {
        parent = parent.$parent;

        if (parent) {
          name = parent.$options.name;
        }
      }
      if (parent) {
        parent.$emit.apply(parent, [eventName].concat(params));
      }
    },
    broadcast(componentName, eventName, params) {
      broadcast.call(this, componentName, eventName, params);
    }
  }
};

在 dispatch 里,通过 while 语句,不断向上遍历更新当前组件(即上下文为当前调用该方法的组件)的父组件实例(变量 parent 即为父组件实例),直到匹配到定义的 componentName 与某个上级组件的 name 选项一致时,结束循环,并在找到的组件实例上,调用 $emit 方法来触发自定义事件 eventName。broadcast 方法与之类似,只不过是向下遍历寻找。

二、找到任意组件实例---findComponents 系列方法

findComponents 系列方法最终都是返回组件的实例,进而读取或调用该组件的数据和方法。

适用场景

  • 由一个组件,向上找到最近的指定组件
  • 由一个组件,向上找到所有的指定组件
  • 由一个组件,向下找到最近的指定组件
  • 由一个组件,向下找到所有的指定组件
  • 由一个组件,找到指定组件的兄弟组件

5个函数的原理,都是通过递归、遍历,找到指定组件的name选项匹配的组件实例并返回。

向上找到最近的指定组件-findComponentUpward

// 由一个组件,向上找到最近的指定组件
// context 当前上下午,一般都是基于当前的组件,即传入this
// componentNam 是要找的组件的name
function findComponentUpward (context, componentName) {
  let parent = context.$parent;
  let name = parent.$options.name;
  // 判断组件的name与传入的componentName是否一致,直到最近的一个组件为止
  while (parent && (!name || [componentName].indexOf(name) < 0)) {
    parent = parent.$parent;
    if (parent) name = parent.$options.name;
  }
  // 与dispatch不同的是,findComponentUpward是直接拿到组件的实例,
  // 而非通过事件通知组件
  return parent;  
}
export { findComponentUpward };

其他函数与此方法大同小异

参考:https://juejin.im/book/5bc844166fb9a05cd676ebca/section/5bc844166fb9a05cf52af65f

本文分享自微信公众号 - 女程序员的日常(gh_df41d619fb70),作者:凛

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-05-13

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • vue.js组件间通信

    组件间需要能相互通信才价值,通信包括数据的传递,方法的调用。这样才能将不同组件结合起来搭建页面

    章鱼喵
  • 解密传统组件间通信与React组件间通信

    在React中最小的逻辑单元是组件,组件之间如果有耦合关系就会进行通信,本文将会介绍React中的组件通信的不同方式

    前端迷
  • Vue.js 父子组件之间通信的十种方式

    这篇文章介绍了Vue.js 父子组件之间通信的十种方式,不管是初学者还是已经在用 Vue 的开发者都会有所收获。无可否认,现在无论大厂还是小厂都已经用上了 Vu...

    用户6973020
  • react组件间的通信

    在使用react过程中,不可避免的需要组件间的数据通信,数据通信一般情况有一下几种情况:

    OECOM
  • React -- 组件间通信

    分为三种类型的通信关系: 1、父组件向子组件通信 2、子组件向父组件通信 3、没有嵌套关系的组件之间的通信 父组件向子组件通信 父组件通过子组件的prop...

    前朝楚水
  • vue2.0组件间通信

    大象无痕
  • cssjshtml vue.js自定义事件组件通信

    葫芦
  • VUE组件之间的通信

    1.父子组件通信 父传子 (1)通过在父组件v-model绑定数据,在子组件进行用props进行数据的接收 父组件

    ZEHAN
  • 【Vue.js】Vue.js中的事件处理、过滤器、过渡和动画、组件的生命周期及组件之间的通信

    魏晓蕾
  • 时间轴组件 by Vue.js

    在公司的项目开发中,涉及到了移动端H5页面的时间轴展示效果。现有的轮子比如ElementUI、iView中,都没有专门的时间轴组件,于是就萌生了自己封装一个的想...

    司想君
  • 【Vuejs】339- Vue.js 组件通信精髓归纳

    由 vue-router 产生的每个页面,它本质上也是一个组件( .vue),主要承载当前页面的 HTML 结构,会包含数据获取、数据整理、数据可视化等常规业务...

    pingan8787
  • Vue组件间通信方式

      当前组件接收到的 props 对象。Vue 实例代理了对其 props 对象属性的访问。在父组件中使用子组件,本质通过v-bind绑定属性传入子组件,子组件...

    TimothyJia
  • 【Vue课堂】Vue.js 父子组件之间通信的十种方式

    这篇文章介绍了Vue.js 父子组件之间通信的十种方式,不管是初学者还是已经在用 Vue 的开发者都会有所收获。无可否认,现在无论大厂还是小厂都已经用上了 Vu...

    用户4962466
  • Vue.js组件

    组件: 顾名思义, 也就是组成的部件, 即整体的组成部分 这个组成部分是可以缺少的,但是其存在的意义是无可替代的 这个组成部分也是可以复用的 全局方法一:...

    河湾欢儿
  • Vue.js 组件

    组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树:

    陈不成i
  • Vue基础:组件--组件及组件通信

    组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以是原生 HTML...

    奋飛
  • vuejs中的组件以及父子组件间通信传值

    您将在本文当中了解到,往网页中添加数据,从传统的dom操作过渡到数据层操作,实现同一个目标,两种不同的方式.以及什么是组件,如何定义和使用组件,父子组件之间如何...

    itclanCoder
  • Vue---父子组件之间的通信

      在vue组件通信中其中最常见通信方式就是父子组件之中的通信,而父子组件的设定方式在不同情况下又各有不同。最常见的就是父组件为控制组件子组件为视图组件。父组件...

    半指温柔乐
  • VUE父子组件之间的通信

    在写组件嵌套过程中,必然涉及到父子组件之间的通信问题,父组件向子组件传递很简单,可以通过props来实现。

    OECOM

扫码关注云+社区

领取腾讯云代金券