探索Vue的组件世界-组件复用

目录

Mixin【混入】

缺陷

HOC(higher order component)【高阶组件】

相比较Mixin的优点:

不足:

Renderless组件【函数式组件,无渲染组件,Vue社区使用比较多的一种业务复用模式】

优点:


  1. Mixins:混入 (mixins): 是一种分发 Vue 组件中可复用功能的非常灵活的方式。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。
  2. HOC(higher order component)【高阶组件】:高阶组件(HOC)是React中用于复用组件逻辑的一种高级技巧。HOC自身并不是React API的一部分,它是一种基于React的组合特性而形成的设计模式。高阶组件听起来挺唬人的,只看名字恐怕不是那么容易明白究竟是何物,而且通常来讲高阶组件并不是组件,而是接受组件作为参数,并且返回组件的函数。
  3. Renderless组件:函数式组件,无渲染组件

Mixin【混入】

<template>
    <div>
    	<input type="text" @blur="blur" />
     {{ errmsg }}
    </div>
</template>
<script>
import validateMixin from "./mixin";
export default {
    mixins: [validateMixin],// 之影响这一个页面,单个页面混入
    data: () => ({ errmsg: "" }),
    methods: {
        blur() {
            this.validate();        
        }    
    }
}
</scrpit>

 validateMixin

export default {
    methods: {
        validate() {
            /**
             * 校验逻辑
             */
            return true;                               	        
        }    
    }
}
  • 同名钩子函数将合并为一个数组,混入对象的钩子将在组件自身钩子之前调用。
  • 二者的methods、components和directives【自定义指令】,将被合并为同一个对象。若对象键名冲突时,取组件对象的键值对(mixin里面的同名【键名】会丢失)

缺陷

  • 打破了原有组件的封装
  • 增加组件复杂度
  • 可能会出现命名冲突的问题
  • 仅仅只是对逻辑的复用,模板不能复用(假如什么示例中errmsg由minxin中的validate返回,那就需要在每个用到的页面写模板)

HOC(higher order component)【高阶组件】

高阶函数的应用,装饰者模式的一种实现

HOC:函数接收一个组件作为参数,并返回一个新组件;可复用的逻辑在函数中实现

 

 App.vue文件

<template>
  <div id="app">
    <img width="25%" src="./assets/logo.png">
    <validate-input :rules="rules"/>
  </div>
</template>
<script>
import CustomInput from "./components/CustomInput";
import ValidateHoc from "./components/hoc.js";
const ValidateInput = ValidateHoc(CustomInput);
export default {
  name: "App",
  data() {
    return {
      rules: [
        {
          test: function(value) {
            return /\d+/.test(value);
          },
          message: "请输入一个数字"
        }
      ]
    };
  },
  components: {
    ValidateInput
  }
};
</script>
<style>
#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

CustomInput.vue文件

<template>
  <input type="text" @blur="$emit('blur', value)" v-model="value">
</template>
<script>
export default {
  props: ["initValue"],
  data() {
    return {
      value: this.initValue
    };
  }
};
</script>

hoc.js文件

const ValidateHoc = Component => ({
  name: `hoc-${Component.name}`,
  props: ["rules"],
  data() {
    return {
      errMsg: "",
      value: ""
    };
  },
  methods: {
    validate(value) {
      this.value = value;
      let validate = this.rules.reduce((pre, cur) => {
        let check = cur && cur.test && cur.test(this.value);
        this.errMsg = check ? "" : cur.message;
        return pre && check;
      }, true);
      return validate;
    }
  },
  render() {
    console.log(this.value);
    return (
      <div>
        <Component on-blur={this.validate} initValue={this.value} />
        {this.errMsg || ""}
      </div>
    );
  }
});
export default ValidateHoc;

相比较Mixin的优点:

  • 模板可复用
  • 不会出现命名冲突(本质上是HOC是套了一层父组件)

不足:

  • 组件复杂度高,多层嵌套,调试会很痛苦

Renderless组件【函数式组件,无渲染组件,Vue社区使用比较多的一种业务复用模式】

  • 复用的逻辑沉淀在包含slot插槽的组件
  • 接口由插槽Prop来暴露

左面子组件,右面是复用逻辑

 SBody.vue文件【子组件】

<template>
  <div>
  // 暴露出插槽Prop方法【validate】
    <s-validate #default="{ validate }" :value="value" :rules="rules">
      // 调用暴露出插槽Prop方法【validate】
      <input type="text" @blur="validate" v-model="value" />
    </s-validate>
    <s-validate #default="{ validate }" :value="text" :rules="textRules">
      <textarea type="text" @blur="validate" v-model="text" />
    </s-validate>
  </div>
</template>
<script>
import SValidate from "./SValidate";
export default {
  data: () => ({
    value: "hi",
    text: "hi",
    rules: [
      {
        test: function(value) {
          return /\d+/.test(value);
        },
        message: "请输入一个数字"
      }
    ],
    textRules: [
      {
        test: function(value) {
          return value;
        },
        message: "请输入一个非空的值"
      }
    ]
  }),
  components: {
    SValidate
  }
};
</script>

SValidate.vue【复用逻辑】

<template>
  <div>
    <slot :validate="validate"></slot>
    {{ errMsg }}
  </div>
</template>
<script>
export default {
  props: ["value", "rules"],
  data() {
    return { errMsg: "" };
  },
  methods: {
    validate() {
      let validate = this.rules.reduce((pre, cur) => {
        let check = cur && cur.test && cur.test(this.value);
        this.errMsg = check ? "" : cur.message;
        return pre && check;
      }, true);
      return validate;
    }
  }
};
</script>

优点:

  • 模板可复用
  • 不会出现命名冲突
  • 符合依赖倒置原则
  • 复用的接口来源清晰
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值