demand

If there are multiple devices on the same interface, you need to click to view details, and you can open multiple div details boxes at the same time to compare and view details data.

The effect

thinking

Initially, the implementation was considered through El-Dialog, but no matter how you try to set the properties, you can only pop up one layer at a time. Despite the mask layer, it is difficult to set the hierarchical relationship of divs, and it is impossible to pop up multiple dialog boxes at the same time to switch to use.

Finally, the dynamic rendering of div is realized by v-for control.

The key code

Click the device button and div to dynamically render the section

<div class="just-click" @click="clickRect('101')" style="left:200px; top:300px;" >101</div> <div class="just-click" @click="clickRect('102')" style="left:400px; top:300px;" >102</div> <div class="just-click" @click="clickRect('103')" style="left:600px; top:300px;" >103</div> <! <div v-for="devOne in devDialogs" :key=" devone. devCode" class="multi-dialog" :id=" devone. box" :style="{left: devOne.left, top: devOne.top}"> <div class="multi-dialog-title" :id="devOne.title"> <span>{{ devOne.devCode }}</span> <button type="button" aria-label="Close" class="el-dialog__headerbtn" @click="closeDialog(devOne)"> <i class="el-dialog__close el-icon el-icon-close"></i> </button> </div> <div class="multi-dialog-content"> <! - < combined - KZMB > < / combined - KZMB > -- > suppose here have content < / div > < / div >Copy the code

Style Setting section

.just-click { cursor: pointer; width: 100px; height: 40px; position: fixed; background: white; color: black; line-height: 40px; text-align: center; } .multi-dialog { position: fixed; width: 580px; Background: rgba (0,93,172,0.75); Box-shadow: 0px 12px rgba(0,186,255,0.5); top: 20px; left: 20px; z-index: 10; font-size: 14px; } .multi-dialog-title { padding: 20px; Border: 1 px solid rgba (0,93,172,0.75); Border - top: 2 px solid rgba (127255255); cursor: move; font-size: 18px; } .multi-dialog-content { padding: 10px; }Copy the code

Js dynamic control part

data () { return { devDialogs: Let exist = false this.devDialogs.forEach(element => {if (val === =) element.devCode) { exist = true } }) if (! exist) { let devOne = { devCode: val, box: 'box' + val, title: 'title' + val, left: '20px', top: '20px' } this.devDialogs.push(devOne) this.$nextTick(() => { this.divMove(devOne.title, devOne.box) }) } }, // closeDialog (devOne) {this.devdialogs. forEach(function (item, index, Arr) {if (item.devcode === devone.devcode) {arr.splice(index, 1)}})}, // divMove (titleId, BoxId) {let title = document.getelementById (titleId) let box = document.getelementById (boxId) // Let divX = 0 let divY = 0 let divY = 0 let divY = 0 let divY = 0 let divY = 0 let divY = 0 let divY = 0 let divY = 0 The self = this / / to bind the mouse click event the title element at the top title. The onmousedown = function (e) {let el = e | | window. The event/divX = / get the mouse position DivY = el.clienty - box.offsetTop divY = el.clienty - box.offsetTop divY = el.clienty - box.offsetTop Set to true can move said the document. The onmousemove = function (e) {/ / for mobile state if (isDrop) {let el = e | | window. The event let leftX = El. clientx-divx // Select * from the top of the window where you can drag the box to the bottom of the window let maxX = Document. The documentElement. ClientWidth - box. OffsetWidth / / window width - the width of box let maxY = document. The documentElement. ClientHeight - // When moving to the leftmost top, leftmost < 0, leftY < 0, the box left margin, the top margin 0 // When moving to the leftmost bottom, the box left margin 0 LeftX > maxX, leftY > maxY, MaxX, maxY leftX = math.min (maxX, math.max (0, leftX)) leftY = math.min (maxY, math.max (0, maxY)) LeftY)) box.style.left = leftX + 'px' box.style.top = leftY + 'px'}} document.onmouseup = function () { The next div moves over to the last div, Self.devdialogs.foreach (function (item) {if (item.box === boxId) {item.left = box.style.left item.top = box.style.top } }) isDrop = false document.onmousemove = null document.onmouseup = null } } }Copy the code

Pay attention to the point

1. Location of onMousemove and onMouseup

If you write onMousemove and onMouseup outside of onMouseDown, the following div will overwrite the preceding one, and isDrop is just the isDrop flag of the last pop-up.

2. Z-index processing

In fact, there is no additional processing of z-index to solve the needs, at the beginning of the z-index is very annoying how to control ah very troublesome ah, the result can not control.

3. Multi-dialog style Settings

Multi-dialog set position to absolute will be limited in the upper layer below the move, if you want to jump out of the limit to the whole window, just set position: fixed; Can.

4, dynamic rendering div key binding is very important!!

The binding in question:

<div v-for="(devOne, index) in devDialogs" :key="index" class="multi-dialog" :id="devOne.box" :style="{left: devOne.left, top: devOne.top}">
Copy the code

At first glance, everything seems to work fine. Binding keys through the index of an array is indeed unique, and there are no errors.

But!!!!! Because we add or delete the devDialogs array, vue renders according to the index.

This leads to a phenomenon:

Click 101 and 102, close the popup of 101, click 101 and move 102 again, and find that 101 moves with it. The reason is that when you move 102, you get the ID of 101, and then both popup moves at the same time. Div (key=index); div (devDialogs array); I don’t know, because I don’t know why, but that’s the reason, change to the following binding key value.

Correct binding:

<div v-for="devOne in devDialogs" :key="devOne.devCode" class="multi-dialog" :id="devOne.box" :style="{left: devOne.left, top: devOne.top}">
Copy the code

Conclusion: It is important to bind keys strictly according to the unique identifier of the div!!