Home > Article > Web Front-end > Introduction to JavaScript framework (xmlplus) components (8) DividedBox
xmlplus is a JavaScript framework for rapid development of front-end and back-end projects. This article mainly introduces the dividing box of the xmlplus layout component, which has certain reference value. Interested friends can refer to
Separating box (pidedBox) is a layout Class components can be divided into two categories, one is called horizontal separation box (HpidedBox), and the other is called vertical separation box (VpidedBox). A horizontal divider box divides its children into two columns, while a vertical divider box divides its children into two rows. There is generally a separator bar between columns and rows that can be dragged to change the size of child components. The following only uses vertical separation boxes as an example to introduce how such components are designed and implemented.
Finished component use case
According to past design experience, we can first write out the imaginary finished component use case, which will help us in the subsequent Further design and implementation. Since the vertical separation box is a component of the layout class, it must also be a container, which contains the three sub-level components we mentioned above. For ease of use, we should not write the separation box into it. The separation box should be implemented internally in the component. After analysis, we get the following application example:
Example1: { css: "#example p { width: 80%; height: 80%; background: #AAA; }", xml: `<VpidedBox id="example"> <p id='top'/> <p id='bottom'/> </VpidedBox>` }
This example consists of a vertical separation box component wrapping two p elements. Here, the width and height of the two p elements are set to 80% of the parent, and their background color is set to gray. This is just for the convenience of testing. In addition, we also need to consider the initial proportion allocation of a sub-frame. We can set the default ratio to 50:50. It is best to specify the ratio statically when the component is instantiated, while providing a dynamic interface for ratio setting. So we have the following improved use case.
Example2: { css: "#example p { width: 80%; height: 80%; background: #AAA; }", xml: `<VpidedBox id="example" percent='30'> <p id='top'/> <p id='bottom'/> </VpidedBox>`, fun: function (sys, items, opts) { sys.top.on("click", e => sys.example.percent = 50); } }
This use case sets the initial ratio distribution of the sub-boxes to 30:70 when the vertical separation box is initialized. When the user clicks on the first sub-box, the ratio distribution is restored to 50:50. Note, however, that these ratios refer to the ratio of the remaining space after excluding the space taken up by the divider bar.
Design and Implementation
Now let’s turn our attention to the internals of the component. Let's first roughly determine the basic composition of the component. Intuitively, the vertical divider frame display contains three component parts: the upper sub-frame part, the divider bar, and the lower sub-frame part. So we can temporarily get the following view item part:
VpidedBox: { xml: `<p id='hbox'> <p id='top'/> <p id='handle'/> <p id='bottom'/> </p>` }
Next, make sure that the child part of the vertical divider box component instance is correctly mapped to the upper sub-box top and the lower sub-box bottom. The method is to first add all child element objects to the upper sub-box top, and then add the lower child elements to the lower sub-box bottom in the function item.
VpidedBox: { xml: `<p id='hbox'> <p id='top'/> <p id='handle'/> <p id='bottom'/> </p>`, map: {appendTo: "top" }, fun: function (sys, items, opts) { sys.bottom.elem().appendChild(this.last().elem()); } }
Now let us consider the style of the view item. For the top-level p element, we set its positioning method to relative positioning. The three child elements are set to absolute positioning. Also, set the divider height to 5px.
VpidedBox: { css: `#hbox { position:relative; width:100%; height:100%; box-sizing: border-box; } #top { top: 0; height: 30%; } #bottom { bottom: 0; height: calc(70% - 5px); } #top,#bottom { left: 0; right: 0; position: absolute; } #handle { height: 5px; width: 100%; position:absolute; left:0; top: 30%; z-index:11; cursor:row-resize; }`, xml: `<p id='hbox'> <p id='top'/> <p id='handle'/> <p id='bottom'/> </p>`, map: {appendTo: "top" }, fun: function (sys, items, opts) { sys.bottom.elem().appendChild(this.last().elem()); } }
Finally, let's see how to respond to the drag event of the divider bar to change the allocation ratio of the subboxes. We need to define a function that changes the proportion of the subbox and listens for the drag event of the separator bar. Below is one of our implementations.
VpidedBox: { // 视图项同上 map: { format: {"int": "percent"}, appendTo: "top" }, fun: function (sys, items, opts) { var percent = 50; sys.handle.on("dragstart", function (e) { sys.hbox.on("dragover", dragover); }); sys.hbox.on("dragend", function (e) { e.stopPropagation(); sys.hbox.off("dragover", dragover); }); function dragover(e) { e.preventDefault(); setPercent((e.pageY - sys.hbox.offset().top) / sys.hbox.height() * 100); } function setPercent(value) { sys.handle.css("top", value + "%"); sys.top.css("height", value + "%"); sys.bottom.css("height", "calc(" + (100 - value) + "% - 5px)"); } setPercent(opts.percent || percent); sys.bottom.elem().appendChild(this.last().elem()); return Object.defineProperty({}, "percent", {get: () => {return percent}, set: setPercent}); } }
There is a setting for percent format in the mapping item of the above code, which ensures that percent is an integer. In addition, the calc calculation function of CSS3 is used to set the proportion of the sub-box in the function item. The modified function can still work when the browser form changes size. If you want to be compatible with more browsers, you need to do more work. Also note that in order to ensure good performance of the component, the dragover event will only be listened to when the user starts dragging.
Further improvements
Let us now do a small test and write an application example of a vertical separator box containing two text fields as children. Drag the divider bar and see what happens.
Example3: { css: `#example textarea { width: 80%; height: 80%; }`, xml: `<VpidedBox id="example"> <textarea id='top'/> <textarea id='bottom'/> </VpidedBox>` }
In this example, sometimes the separator bar will fail, and the sub-box proportions will no longer change with the position of the separator bar. The problem is that the text field hijacks the drag event, causing our component to not receive any response events. We need to make some patches.
VpidedBox: { css: "#hbox { position:relative; width:100%; height:100%; box-sizing: border-box; }\ #top { top: 0; height: 30%; } #bottom { bottom: 0; height: calc(70% - 5px); }\ #top,#bottom { left: 0; right: 0; position: absolute; }\ #handle { height: 5px; width: 100%; position:absolute; left:0; top: 30%; z-index:11; cursor:row-resize; }\ #mask { width: 100%; height: 100%; position: absolute; display: none; z-index: 10; }", xml: "<p id='hbox'>\ <p id='top'/>\ <p id='handle' draggable='true'/>\ <p id='bottom'/>\ <p id='mask'/>\ </p>", map: { format: {"int": "percent"}, appendTo: "top" }, fun: function (sys, items, opts) { var percent = 50; sys.handle.on("dragstart", function (e) { sys.mask.show(); sys.hbox.on("dragover", dragover); }); sys.hbox.on("dragend", function (e) { sys.mask.hide(); e.stopPropagation(); sys.hbox.off("dragover", dragover); }); function dragover(e) { e.preventDefault(); setPercent((e.pageY - sys.hbox.offset().top) / sys.hbox.height() * 100); } function setPercent(value) { sys.handle.css("top", value + "%"); sys.top.css("height", value + "%"); sys.bottom.css("height", "calc(" + (100 - value) + "% - 5px)"); } setPercent(opts.percent || percent); sys.bottom.elem().appendChild(this.last().elem()); return Object.defineProperty({}, "percent", {get: () => {return percent}, set: setPercent}); } }
In order to solve the problem, we referenced an additional p element object mask in the component. This element is not displayed by default. When dragging starts, it covers the subbox and separator bar, and when dragging ends, it hides again. This avoids the text field from hijacking drag events.
Used in combination with horizontal dividing frames
We have the design experience of the above vertical dividing frames, so it is not difficult to create a horizontal dividing frame. Here It won’t be listed. Here we mainly give an example of using horizontal separation boxes and vertical separation boxes comprehensively. Of course, at the beginning of the design, we didn't think of using it in this way.
Example4: { css: `#example p { width: 100%; height: 100%; }`, xml: `<HpidedBox id='example'> <VpidedBox percent='30'> <p/><p/> </VpidedBox> <VpidedBox percent='30'> <p/><p/> </VpidedBox> </HpidedBox>` }
This example is mainly used to show the performance when the separator boxes are nested. This example contains a horizontal separation box, which in turn contains two vertical separation boxes. This layout is very common in many editors, and we have implemented it here simply and efficiently.
This series of articles is based on the xmlplus framework. If you don’t know much about xmlplus, you can visit www.xmlplus.cn. Detailed getting started documentation is available here.
【Related recommendations】
1. Free js online video tutorial
2. JavaScript Chinese Reference Manual
3. php.cn Dugu Jiujian (3) - JavaScript video tutorial
The above is the detailed content of Introduction to JavaScript framework (xmlplus) components (8) DividedBox. For more information, please follow other related articles on the PHP Chinese website!