Vue.js HOC

by BogdanL

HTML

<script src="https://unpkg.com/[email protected]"></script>
<div id="demo">

    <h3>baseComponent</h3>
    <base-component foo="bar" @hello="hello" @click.native="native">
        ⑤ default-slot
        <h4 slot="test">③ test-slot</h4>
    </base-component>
    <hr/>

<!--
    <h3>HOC01</h3>
    <enhanced-component1 foo="bar" @hello="hello" @click.native="native">
        ⑤ default-slot
        <h4 slot="test">③ test-slot</h4>
    </enhanced-component1>
    <hr/>

    <h3>HOC02</h3>
    <enhanced-component2 foo="bar" @hello="hello" @click.native="native">
        ⑤ default-slot
        <h4 slot="test">③ test-slot</h4>
    </enhanced-component2>
    <hr/>

    <h3>HOC03</h3>
    <enhanced-component3 foo="bar" @hello="hello" @click.native="native">
        ⑤ default-slot
        <h4 slot="test">③ test-slot</h4>
    </enhanced-component3>
    <hr/>
-->

    <h3>HOC04</h3>
    <enhanced-component4 foo="bar" @hello="hello" @click.native="native">
        ⑤ default-slot
        <h4 slot="test">③ test-slot</h4>
    </enhanced-component4>
    <hr/>

    <!-- <h3>HOC05</h3>
    <enhanced-component5 foo="bar" @hello="hello" @click.native="native">
        ⑤ default-slot
        <h4 slot="test">③ test-slot</h4>
    </enhanced-component5> -->
</div>

CSS

#demo {
  padding: 20px 80px 50px;
}

h3 {
  color: red;
}

h4 {
  background-color: yellow;
}

h5 {
  background-color: #ff4200;
  color: white;
}

p {
  background-color: #00cc66;
}

code {
  display: block;
  background-color: #ff9933;
  font-size: 15px;
}

hr {
  background-color: transparent;
  border: none;
  height: 100px;
}

JavaScript

const BaseComponent = {
    props: ['foo'],
    template: `
    <div>
      <h5 @click="emitHello">① emit event (must be alert twice time)</h5>
      <code>② props:{{JSON.stringify(this.$props)}}</code>
      <slot name="test"></slot>
      <p>④ between slots</p>
      <slot></slot>
    </div>
    `,
    methods: {
    	emitHello () {
      	this.$emit('hello');
      }
    }
}

/*const HOC01 = WrappedComponent => ({
     render (h) {
        return h(WrappedComponent, {props: this.$props});
     }
});

const HOC02 = WrappedComponent => ({
     props: WrappedComponent.props,
     render (h) {
        return h(WrappedComponent, { props: this.$props });
     }
});

const HOC03 = WrappedComponent => ({
    functional: true,
    render (h, c) {
        return h(WrappedComponent, c.data, c.children);
     }
}); */

const HOC04 = WrappedComponent => ({
		props: typeof WrappedComponent === 'function' 
    	? WrappedComponent.options.props 
      : WrappedComponent.props,
    mounted () {
    	console.log('mounted!');
    },
    render (h) {
        return h(WrappedComponent, {
        	attrs: this.$attrs,
          props: this.$props,
          on: this.$listeners,
          scopedSlots: {
          	default: () => this.$slots.default,
            test: () => this.$slots.test,
        	}
        });
     }
});

/*
const HOC05 = WrappedComponent => ({
    template: `<wrapped v-on="$listeners" v-bind="$attrs"><slot/></wrapped>`,
    components: {
        'wrapped': WrappedComponent,
    },
});
*/

//console.log(typeof Vue.extend({}),Vue.extend({}))

new Vue({
    el: '#demo',
    methods: {
        hello () {
            alert('Hello!!');
        },
        native () {
            alert('Native!!');
        }
    },
    components: {
        BaseComponent,
//        EnhancedComponent1: HOC01(BaseComponent),
//        EnhancedComponent2: HOC02(BaseComponent),
//        EnhancedComponent3: HOC03(BaseComponent),
        EnhancedComponent4: HOC04(BaseComponent),
//       ...