最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • vue组件间传值的8种方式

    正文概述 掘金(橘猫走江湖)   2020-12-04   857

    组件间传值问题

    一、A→B→C祖孙传值类型

    A→B→C传值方式是工作中最常见的传值方式,依次是组件的包含顺序。

    1、props/$emit

    当然,我们可以利用两次props接收参数,直到参数从A传到C,这种方式不再赘述。

    2、vuex

    还有通过vuex,不过有点大材小用,引起state维护的参数过多等,这种方式也不赘述了。

    3、provide、inject传值

    provice/inject传值的方式,适合所有的向下传值类型,层级可以很深,多用于组件开发。业务开发中很少用到。

    A组件

    // provide作为一个属性使用,和data,methods等统级,将要传递给子孙的属性放在里面
    provide() {
        return {
          toSon: 'this is to my son'
        }
    },
    

    B、C等子孙组件

    // inject是一个对象
    inject: {
        toSon: {
          default: '' // 设置接收属性的默认值
        }
     },
     
     // inject也可以是一个数组
     inject:['toSon']
    

    4、attrattr、attr、listeners传值

    *这两个属性都是绑在组件B上面的,组件B起到一个承上启下的作用。
    attr用于将A组件传递过来的属性,下传给C组件<br/>attr用于将A组件传递过来的属性,下传给C组件<br />attr用于将A组件传递过来的属性,下传给C组件<br/>listeners用于将C组件发射的数据,上传给A组件
    inheritAttrs用于设置属性,当设置为false时候,dom上则不会出现属性。

    尚不明确的点inheritAttrs

    A组件

    <component-b
          :pagination="pagination" // 将属性传递给B和C
          v-on:propToComponentA="listenComponentC" // 监听c组件的事件
     />
     
     methods: {
     	listenComponentC(data) {
      
      }
     }
    

    B组件

    <component-c  v-bind="$attrs" v-on="$listeners"/>
    inheritAttrs: false
    

    C组件

    	inheritAttrs: false,
      async created() {
       console.log(this.$attrs)
       输出可以发现$attrs对象是A组件传递过来的属性
      },
      methods: {
        propToComponentA() {
          const data = {
            name: '古天乐'
          }
          // b组件,c组件都可以监听事件propToComponentA
          this.$emit('propToComponentA',data)
        }
      },
    

    这种方式比vuex轻量,而且很方便。

    5、childrenchildren、children、parent

    有时候也有人用这种方式进行组件传值,我几乎不用。
    欧尔父组件调用子组件事件时候,为了少些代码,直接一个this.refs.childrenName.childrenField完事。<br/>childrenNameref指向的子组件名称<br/>childrenField是子组件中的事件或者参数<br/>闲话少说,还是来说说refs.childrenName.childrenField 完事。<br />childrenName 是ref指向的子组件名称<br />childrenField 是子组件中的事件或者参数<br />闲话少说,还是来说说refs.childrenName.childrenField完事。<br/>childrenName是ref指向的子组件名称<br/>childrenField是子组件中的事件或者参数<br/>闲话少说,还是来说说children、$parent

    $children

    在父组件中,通过children可以获得所有无序的子组件组成的数组。<br/>注意,当你想用children可以获得所有无序的子组件组成的数组。<br />注意,当你想用children可以获得所有无序的子组件组成的数组。<br/>注意,当你想用children调用儿子组件中的方法或者参数时候,一定是需要等挂在完毕,在mounted中调用,或者是$nextTick

    $parent

    子组件可以通过this.$parent获取父组件实例。同样的,打点调用父组件的方法。

    6、中央事件总线 emit/emit/emit/on

    这个其实是一种思路,eventBus
    就是创建一个全局的eventBus,然后将你需要的变量、事件等都挂载在上面。需要的时候去获取。
    现在vue开发很少有人用这种方法了,有了vuex,谁还会去用呢。
    下面简单介绍一下。

    创建全局响应式变量

    一般在main.js中定义一个全局变量,挂在到window下

    import Vue from 'vue'
    window.eventBus = new Vue()
    // 也可以挂载到vue原型链上,二选其一
    Vue.prototype.$eventBus = new Vue();
    

    从这里可以看出eventBus就是一个vue实例,但是是个很奇怪的实例,因为没有router,没有挂载app等,当然,这个实例肯定是响应式,这就是它的作用。
    接下来,要做的就是将开发中的兄弟组件之间需要传递的变量挂载到上面。

    事件挂载到eventBus

    C组件

    // c组件发射了一名为dataFrom的事件,并挂载了数据this.dataA
    this.$eventBus.$emit('dataFrom', this.dataA);
    

    接收eventBus的事件

    因为$eventBus是全局,且响应式的,任何一个组件都可以进行接收

    this.$eventBus.$on('dataFrom',  function (data) {
         // handle data code
    });
    


    如果想接收一次事件后移除,就用$once

    this.$eventBus.$once('dataFrom',  function (data) {
         // handle data code
    });
    



    7、组件v-modle传值,子传父B→A

    有一种开发中的特殊情况,大家在封装属于自己的表单组件或者对element-ui的表单进行二次封装是时候一定遇到过。

    举个栗子:

    功能要求:我们要对el-input进行二次封装,功能为只能输入数字,,小数点最多保留两位。当尝试输入其他格式,或者尝试三位小数点时候给出 el-form-item__error 的提示。

    解决思路:封装一个组件,正则校验只能输入数字。这里涉及到一个问题,如何给父组件传值,组件报错,同时,父组件如何给子组件绑定v-model ?

    代码地址:github.com/taoorange/l…

    我们的做法如下:

    子组件

    在子组件的props定义变量value,用来接收父组件绑定的v-model
    在子组件中,通过  this.$emit('input', val)将子组件处理好的父组件传递过来的数据,再回传绑定给父组件在子组件绑定的v-modle属性上。
    这其实是一个同时改变子父组件的逻辑。

    子组件代码:

    <template>
      <div>
        <el-input
          :disabled="disabled"
          :readonly="readonly"
          :value="value"
          :size="size"
          :positive="positive"
          :integerOnly="integerOnly"
          :placeholder="placeholder"
          :remain="remain"
          :max="max"
          @input="changeInput($event)"
        >
          <template v-if="slotName" :slot="slotType">{{ slotName }}</template>
        </el-input>
        <div v-if="errorMessage" class="el-form-item__error">{{ errorMessage }}</div>
      </div>
    </template>
    <script>
    // 对</el-input>做二次封装,主要用来处理数字输入的小数点保留问题
    export default {
      name: 'NumberInput',
      props: {
        slotType: {
          type: String,
          default: 'append',
        },
        slotName: {
          type: String,
          default: null,
        },
        value: {
          type: [Number, String],
          default: null,
        },
        size: {
          type: String,
          default: 'small',
        },
        disabled: {
          type: Boolean,
          default: false,
        },
        readonly: {
          type: Boolean,
          default: false,
        },
        placeholder: {
          type: String,
          defalut: '请输入',
        },
        remain: {
          type: [Number, String],
          default: 2, // 默认保留2位小数
        },
        // 限制是否只能输入为正整数
        integerOnly: {
          type: Boolean,
          defalut: false,
        },
        min: {
          type: Number,
          default: -999999999999,
        },
        max: {
          type: Number,
          default: 99999999999999,
        },
        // 限制是否只能为正数
        positive: {
          type: Boolean,
          defalut: false,
        },
      },
      data() {
        return {
          errorMessage: '',
        }
      },
      methods: {
        changeInput(value) {
          let val
          if (!this.integerOnly) {
            // 限制输入框只能为数字和小数点,限制可输入数字的位数
            // 限制只能为正数
            if (this.positive) {
              val = value.replace(/[^\d.]/g, '')
            } else {
              val = value.replace(/[^\d.-]/g, '')
              // val = value.replace(/[^\-?][\d][\.?][\d]/g, '')
            }
    
            // 校验小数点位数
            if (val.toString().indexOf('.') > -1) {
              const a = val.toString().split('.')
              if (a[1].length > this.remain) {
                val = parseFloat(val).toFixed(this.remain)
                this.errorMessage = `仅支持${this.remain}位小数输入`
              } else {
                this.errorMessage = null
              }
            }
          } else {
            // 限制输入框只能为正整数
            val = value.replace(/[^\d]/g, '')
          }
          if (val > this.max) {
            val = this.max
          }
          if (val && val < this.min) {
            val = this.min
          }
          this.$emit('input', val)
        },
      },
    }
    </script>
    <style lang="scss" scoped>
      /deep/.el-input-group__append {
        padding: 0 5px;
        font-size: 13px;
      }
    </style>
    
    

    父组件


    在父组件中,我们通过v-model给子组件绑定值(子组件通过props中的value接收)。

    // 设置了支持保留4位小数
    <number-input :remain="4" v-model="numberMoney"></number-input>
    


    起源地下载网 » vue组件间传值的8种方式

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元