The fastest way is to use an excellent component library, such as elder-UI el-Dialog. It is also very convenient to use. There are probably several ways to do this:

Method one: Put dialog and Content-body together

child.vue

<el-dialog
  title="Tip"
  :visible.sync="visible"
  width="30%"
  :before-close="handleClose">
  <span>This is a piece of information</span>
  <span slot="footer" class="dialog-footer">
    <el-button @click="dialogVisible = false">Take away</el-button>
    <el-button type="primary" @click="dialogVisible = false">determine</el-button>
  </span>
</el-dialog>
Copy the code

parent.vue

<child 
    :visible="visible" 
    :otherData="otherData"/>
Copy the code

At the same time, you need to write Visible to the current page and clear the data when closed. (PS: because of the prop passed in from the outer layer, it cannot be modified internally. If it needs to be modified, it should emit to the parent level for synchronous update)

<child 
+   :visible.sync="visible" 
    :otherData="otherData"/>
close() {
    this.$emit('update:visible'.false);
}
Copy the code

Method 2: Place the outer dialog in parent and import the abstract Content-Body content as a component

child.vue

<span>This is a paragraph</span>
Copy the code

parent.vue

<el-dialog
  title="Tip"
  :visible.sync="visible"
  width="30%"
  :before-close="handleClose">
  <child />
  <span slot="footer" class="dialog-footer">
    <el-button @click="dialogVisible = false">Take away</el-button>
    <el-button type="primary" @click="dialogVisible = false">determine</el-button>
  </span>
</el-dialog>
Copy the code

The parent component needs to define the visible property and clear the data when closed

child.vue

resetFields() {
    // Clear the child data
    Object.assign(this.$data,this.$options.data())
}
Copy the code

parent.vue

handleClose() {
    this.visible = false;
    this.$refs['child'].resetFields();
}
Copy the code

Method 3: Combine Vuex state management, so that you do not need to passattrsorpropsIncoming communication, global maintenance of a state

child.js

const viewmodel = {
    state: {
        visible: false
    },
    mutations: {
        setVisible(state, payload){ state.visible = payload; }}}Copy the code
<el-dialog
  title="Tip"
  :visible.sync="visible"
  width="30%"
  :before-close="handleClose">
  <child />
  <span slot="footer" class="dialog-footer">
    <el-button @click="dialogVisible = false">Take away</el-button>
    <el-button type="primary" @click="dialogVisible = false">determine</el-button>
  </span></el-dialog> ... mapState('child'['visible'])
...mapMutation('child'['setVisible'])
Copy the code

Some of the ideas above make people feel more redundant, can be used, but not recommended. If a page has multiple pop-ups, it doesn’t feel elegant, so some wrapping is needed.

First of all, a dialog component needs visible to control show/hide, title to control the popbox title, Content to represent the content area, and close to represent the outer call to close the popbox.

props: {
    title: {
        type: String.default: ' '
    },
    component: {
        type: Function.default: () = >{}},close: {
        type: Function.default: () = >{}}}methods: {
    closeDialog() {
      // Clear the popbox data
      Object.assign(this.$data, this.$options.data());
      // Call the close method in props to empty the data
      this.close();
      // Destroy the component and remove the Watcher listener
      this.$refs.component.$destroy(); }}Copy the code

We define a customDialog component that internally defines the data property Visible.

  1. We use extend to generate a new sub method, point sub to the parent prototype chain, merge the incoming properties into options under sub, inherit the parent prototype method, and merge the subsuperPoint to the parent object.
  2. The method is then new, essentially generating a new vUE instance through a series of init operations.
  3. The vUE instance is then applied$mountOperation, the essence is to carry out virtual DOM patch operation, return EL object
  4. Finally, append the EL object to the body and complete the rendering of the popbox component
const DialogConstructor = Vue.extend(CustomDialog);
inst = new DialogConstructor();
inst.visible = true;
inst.$mount();
document.body.appendChild(inst.$el);
Copy the code

Question 1: How can I change the properties of the inner frame from the outer layer

By passing in the propsData property

+ const createDialog = propsData= > {
    const DialogConstructor = Vue.extend(CustomDialog);
    inst = new DialogConstructor({
+       propsData
    });
    inst.visible = true;
    inst.$mount();
    document.body.appendChild(inst.$el); +}Copy the code

This allows us to construct different popboxes by createDialog({title: XXX})

Fault 2: A pop-up frame that has been opened needs to be constructed again when opened again

The opened subrack instances are saved to a map and obtained by setting a unique UID value

const createDialog = () = >{+const instance = {};
    return propsData= > {
        const uid = propsData.id || propsData.title;
        let inst = instance[uid];
        if (inst) {
+           inst.visible = true;
        } else{... + instance[uid] = inst; } +returninst; }}Copy the code

In addition, if the current instance propsData has been updated, the instance needs to be updated

const createDialog = () = > {
    return propsData= > {
        const instance = {};
        if(inst) {
            inst.visible = true;
+           const originPropsData = mapValues(
+               inst.$options.props,
+               value= > value.default
+           );
+           Object.assign(inst.$props, originPropsData, propsData); }}}Copy the code

Question 3: How do I close the pop-up correctly in the opening sequence

Open instance objects can be stored on a stack. Every time I open it, I’m actually pushing the instance onto the stack; Every time you close it, you’re actually pushing the instance off the stack. Set a $closeDialog method attached to the Vue prototype chain. The main task is to get the current instance, call the close method of the current instance, and push the current instance off the stack.

const createDialog = () = > {
    const instance = {};
+   const openedDialogQueue = [];
    return propsData= > {
        const uid = propsData.id || propsData.title;
        let inst = instance[uid];
+       Vue.prototype.$closeDialog = () = >{+constcurrentInst = openedDialogQueue.pop(); + currentInst && currentInst.closeDialog(); +};if (inst) {
          inst.visible = true;
          // NOTE:Update props
          const originPropsData = mapValues(
            inst.$options.props,
            value= > value.default
          );
          Object.assign(inst.$props, originPropsData, propsData);
          // NOTE:It mainly deals with the sequence of opening and closing multiple bullet frames
+         openedDialogQueue.push(inst);
        } else {
          const DialogConstructor = Vue.extend(CustomDialog);
          inst = new DialogConstructor({
            propsData
          });
          inst.visible = true;
          inst.$mount();
          document.body.appendChild(inst.$el);
          openedDialogQueue.push(inst);
          instance[uid] = inst;
        }

        return inst;
    };
}
Copy the code

Such a simple box to achieve, after each use only need to write a short few lines of code can be done

this.$dialog({
    id: 'key'.title: 'play box'.component: () = > <div>Hello, world!</div>,})Copy the code

conclusion

Above is oneself study net big guy after sum up some experience, improved development efficiency to a certain extent. Life and work need to summarize, write this article, on the one hand to record their own thoughts, on the other hand to share with you to study together, if there is anything wrong, hope to get your correction, thank you very much!

custom-dialog