Source code: address

I wrote it some time agoVue.extend Login registration modal boxIs based on Vue 2.xVue.extendVersion to do



During this period, I learned Vue 3.0 and reconstructed the project completely. I recorded the process and thinking of reconstruction under learning.

component

The components are still the same, not much needs to be changed, just changed to Vue 3 form



sigin.vue ε’Œ register.vueComponent modification separately

// sigin.vue
<template>
  <div>
    <button @click="onClick">The login confirmation</button>
  </div>
</template>

<script>
export default {
  name: "Sigin".emits: ['sigin'].setup(props, { emit }) {
    const onClick = () = > {
      emit("sigin")}return {
      onClick
    }
  }
};
</script>

// register.vue
<template>
  <button @click="onClick">Registration confirmation</button>
</template>

<script>
export default {
  name: "Register".emits: ['register'].setup(props, { emit }) {
    const onClick = () = > {
      emit("register")}return {
      onClick
    }
  }
};
</script>

Copy the code

The index. The vue components

<template>
  <div v-show="show">
    <Sigin v-if="type === 'sigin'" @sigin="loginCallback" />
    <Register v-if="type === 'register'" @register="loginCallback" />
  </div>
</template>

<script>
import Sigin from "./sigin.vue";
import Register from "./register.vue";
import { ref } from 'vue';
export default {
  components: {
    Register,
    Sigin
  },
  props: {
    visible: Boolean.type: String.close: [Function.Boolean]},emits: ['destroy'].setup(props, { emit }) {
    const show = ref(props.visible);
    const doClose = () = > {
      show.value = false;
      emit('destroy');
    }

    const loginCallback = () = > {
      if(! props.close)return;
      props.close().then(valid= > {
        if(valid) { doClose(); }}); }return {
      show,
      doClose,
      loginCallback
    }
  }
};
</script>

Copy the code

A subclass

Since Vue. Extend is deprecated, Vue 3 uses h and render functions here. Let’s take a look at the introduction of these two functions

  • hFunction parameters:
    • typeIts type can be an HTML tag name, a component, or an asynchronous component
    • propsIs an object that corresponds to our template component insideattribute,propAnd events
  • renderThe render function takes a component and a container

Modified index. Js

import { render, h } from "vue";
import ModalCops from "./index.vue"; 

let instance;

const ModalBox = ({type, ok}) = > {
  if (instance) {
    instance.component.proxy.doClose();
  }

  // The component receives props
  let _opt = {
    visible: true,
    type,
    close: () = > {
      return new Promise(resolve= > {
        const before = ok ? ok() : false;

        if (before && before.then) {
          before.then(
            () = > resolve(true),
            () = > {
              console.log("reject"); }); }else if (typeof before === "boolean"&& before ! = =false) {
          resolve(true); }}); }}; instance = h(ModalCops, _opt);/ / component

  const container = document.createElement('div');

  // When the component is destroyed
  instance.props.onDestroy = () = > {
    render(null, container);
  }

  // Render component
  render(instance, container);
  
  // Add the modal box to the body
  document.body.appendChild(container.firstElementChild);

};

ModalBox.sigin = ok= > {
  return ModalBox({
    type: "sigin",
    ok
  });
};

ModalBox.register = ok= > {
  return ModalBox({
    type: "register",
    ok
  });
};

ModalBox.close = () = > {
  instance.component.proxy.doClose();
  instance.component.proxy.show = false;
};

export default {
  install(app){ app.config.globalProperties.$loginer = ModalBox; }};Copy the code

Finally, mount it globally

import { createApp } from 'vue'
import Login from './Login.vue'
import LoginModal from "./LoginModal/index.js";
createApp(Login).use(LoginModal).mount('#app')
Copy the code

Used in the login. vue component

import { ref, getCurrentInstance } from "vue";
export default {
  setup(props) {
    const { proxy } = getCurrentInstance();

    const isOk = ref(true);

    const onLogin = (type) = > {
      const funcs = {
        sigin: () = > {
          console.log("Login Request");
        },
        register: () = > {
          console.log("Registration Request"); }}; proxy.$loginer({ type,ok: () = > {
          return new Promise((resolve, reject) = > {
            if (isOk.value) {
              funcs[type]();
              resolve();
            } else{ reject(); }}); }}); };return{ isOk, onLogin, }; }};Copy the code

And finally, let me show you the effect

Pay attention to

There are a few things to be aware of when modifying parts of the code

  • Global mount

Vue 3 still provides the use function to use our plug-in, but the properties that need to be mounted have changed. Instead of being mounted directly on vue. prototype, we need to add them to the config.GlobalProperties object of the global instance

  install(app) {
    app.config.globalProperties.$loginer = ModalBox;
  }
Copy the code
  • When the component is destroyedonDestroyThe event

This event corresponds toindex.vueIn the template componentemitOut of thedestroyEvent, this is due toVueIn the sourcepackages\runtime-core\src\componentEmits.ts δΈ­emitFunction gives us the event added automaticallyonThe prefix



conclusion

Learn it and use it. This is after learning Vue3 in the project comprehensive use, which also encountered a lot of need to avoid pit, also try to read part of the source, harvest full 😁

This article is participating in the “Nuggets 2021 Spring Recruitment Campaign”, click to see the details of the campaign