当你自己封装Vue组件库时会用到的知识点

源码在 https://github.com/xiaodun/sf-feed

函数式组件

<TagConvert tag="span" age="9" sex="man">12312</TagConvert>

生成的DOM如下

<span age="9" sex="man">12312</span>

内部实现是这样的,用到自定义组件上,意义就大了


<script>
export default {
  functional: true,
  name: "TagConvert_vue",
  props: {
    tag: {
      type: String,
      default: "div"
    }
  },
  render(createElement, context) {
    return createElement(context.props.tag, context.data, context.children);
  }
};
</script>

v-bind="$attrs"

批量绑定父组件传递过来的属性
看一下iview官网上,表单验证的模板代码

handleSubmit(name) {
      this.$refs[name].validate((valid) => {
                    if (valid) {
                        this.$Message.success('Success!');
                    } else {
                        this.$Message.error('Fail!');
                    }
                })
            }

name 对应的是<Form ref="formInline">
现在我想封装一个专门用来提交的<Submit> 组件,只有在验证成功的时候触发回调

<Submit @submit="onSubmit">
    <Button 
        width="100%"
          :status="submitStatus"
        class="login-btn"
        height="36px"
     >{{$t('login')}}</Button>
</Submit>

上述这样会多一层无用的DOM嵌套,我希望是这样的

 <Submit
     width="100%"
     :status="submitStatus"
     class="login-btn"
     height="36px"
     @submit="onSubmit"
    >{{$t('login')}}</Submit>

<Submit> 内部实现结合了<TagConvert>v-bind="$attrs"

<template>

  <TagConvert
    v-if="tag[0].charCodeAt(0)<=90"
    :tag="tag"
    v-bind="$attrs"
    @click.native="onSubmit"
  >
    <slot></slot>
  </TagConvert>
  <!-- 原生组件 -->
  <TagConvert
    v-else
    :tag="tag"
    v-bind="$attrs"
    @click="onSubmit"
  >
    <slot></slot>
  </TagConvert>

</template>

<script>
import { findParentComponent } from "../../find";
export default {
  name: "Submit_vue",
  props: {
    tag: {
      type: String,
      default: "Button"
    }
  },
  methods: {
    onSubmit($event) {
      $event.preventDefault();
      //查找
      let validInfo = this.submitComponent.onValidator();
      if (validInfo.status) {
        this.$emit("submit", validInfo.passValues);
      }
    }
  },
  mounted() {
    let findInfo = findParentComponent(this, "FormItem");
    if (!findInfo.status) {
      findInfo = findParentComponent(this, "Form");
    }
    if (findInfo.status) {
      this.submitComponent = findInfo.component;
    } else {
      console.error("没有找到Form或FormItem");
    }
  }
};
</script>

findParentComponent 是基于Vue自身节点构造,可以通过$parent追溯父元素,$children遍历子元素

provide 与 inject

这种适合<Form><FormItem>这种父子组件
<Form>

export default {
  name: "Form_vue",
  props: {
    labelWidth: String
  },
  provide() {
    return {
      Form: this
    };
  }
}

<FormItem>

export default {
  name: "FormItem_vue",
  inject: ["Form"],
}

<FormItem> 可以 this.Form 访问
如果<FormItem> 没有得到<Form>的引用会报错哦

动态挂载HTML

render 的动态再需要通过JS触发时,是乏力的,比如一个类似于iview 的<Notice>组件,需要如下手段

import Notification from "./Notification";
import Vue from 'vue';

const NotificationInstance = (() => {
    let instance = new Vue({
        render(createElement) {
            return createElement(Notification)
        }
    })
    const component = instance.$mount();
    document.body.appendChild(component.$el);
    const notification = instance.$children[0];
    return notification;
})();
Vue.prototype.$Notice = {
    show(argOptions) {
        NotificationInstance.add(argOptions);
    }
}

可以this.$Notice.show来触发

上述可发现,React可以做到的,Vue也可以做到,可有千秋。

但是Vue更贴近开发者和业务场景,React的抽象层次更高,具体的落实需要开发者去做,更适合研究琢磨,这么看来,React会走的更远。

人生苦短,我用Vue。

推荐阅读更多精彩内容