仿elementUI,实现一个form表单组件(带校验)(下)(this.$parent的弊端)

你觉得Vue中的this.$parentthis.$children好用吗?

好用,为什么不好用,我通过this.$parent可以直接拿到父组件的实例,从而拿到里面的值,我也可以调用里面的方法,简直太香。

这种说法是没错,在写自己项目的时候所有的组件都是你自己设计的,怎么用,怎么传值,你自己一清二楚,但是你想想,如果你在写一个组件库的时候,你使用了this.$parent或者this.$children,会造成组件间的依赖,违反设计原则:高内聚,低耦合,你不能限制用户用你组件的方式。

比如

这篇文章的(上)传送门,封装了一个带校验的form组件,这篇文章我就用到了this$parent,去通知KFormItem组件去校验,没用我接下来说的这种方式进行处理,(建议看完上一篇,再来看这一篇),下面会告诉你会有什么问题。

这样写避免了什么问题

如果是这样用,当然没问题

<KForm>
  <KFormItem>
    <KInput></KInput>
  </KFormItem>
</KForm>

那如果用户非要在中间加一层自定义组件呢

<KForm>
  <KFormItem>
    <Comp>
      <KInput></KInput>
    </Comp>
  </KFormItem>
</KForm>

此时你KInput组件的this.$parent.emit()方法,还有用吗,此时的$parent变成了comp组件,所以基于这个问题,我们封装了一个mixins

开始

我们封装一个混入方法

emiter.js文件中

export default {
  methods: {
    dispatch (componentName, func) {
      var parent = this.$parent || this.$root;//获取当前组件的parent
      var name = parent.$options.componentName;//获取parent组件的componentName,这个componentName是自己定义的,目的就是标识这个组件
      while (parent && name != componentName) {
        parent = parent.$parent;
        if (parent.$options.componentName) {
          name = componentName;
        }
      }
      if (parent) {
        parent.$emit (func);
      }
    },
  },
};

页面中引用

<template>
  <div>
    <input type="text" :value="value" @input="onInput" />
  </div>
</template>

<script>
import emitter from "../../utils/emitter.js";
export default {
  name: "KInput",
  mixins: [emitter],
  props: {
    value: {
      type: String,
      default: "",
    },
  },
  data() {
    return {};
  },
  methods: {
    onInput(e) {
      this.$emit("input", e.target.value);
      // 值发生变化的时候,父组件派发事件,父组件监听事件

      // dispatch方式
      this.dispatch("KFormItem", "validate" );
    },
  },
};
</script>

推荐阅读更多精彩内容