9

10 年前,我用 C++ 编写了一个 GUI 布局引擎,我很好奇它的功能如何在浏览器中得到最好的近似。

1.C++

在较旧的 GUI 库(如Microsoft Windows)中,小部件的位置和大小通常由四个数字给出:left、top、widthheight。我的引擎不同之处在于这些数字中的每一个都加倍,因此您必须指定八个数字:相对左侧,绝对左侧;相对顶部,绝对顶部;相对宽度,绝对宽度;相对高度绝对高度相对值应以父窗口小部件的宽度或高度的百分比给出,绝对值像素为单位. 在顶级窗口的情况下,“父窗口小部件”是桌面。

例子:

a) 400 x 300 px 窗口,以屏幕为中心:

const int WINDOW_WIDTH = 400;
const int WINDOW_HEIGHT = 300;
CWindow mainWindow;
mainWindow.setPosition(0.5, -WINDOW_WIDTH / 2, 0.5, -WINDOW_HEIGHT / 2); 
mainWindow.setSize(0.0, WINDOW_WIDTH, 0.0, WINDOW_HEIGHT);

b) 主窗口右侧边缘的 150 px 宽按钮容器面板:

const int PANEL_WIDTH = 150;
CPanel buttonPanel(mainWindow);
buttonPanel.setPosition(1.0, -PANEL_WIDTH, 0.0, 0); 
buttonPanel.setSize(0.0, PANEL_WIDTH, 1.0, 0);

c) 容器面板顶部的三个按钮(新建、打开、保存)和底部的一个按钮(退出):

const int BUTTON_HEIGHT = 30;
CButton newButton(buttonPanel, "New");
newButton.setPosition(0.0, 0, 0.0, 0 * BUTTON_HEIGHT);
newButton.setSize(1.0, 0, 0.0, BUTTON_HEIGHT);
CButton openButton(buttonPanel, "Open");
openButton.setPosition(0.0, 0, 0.0, 1 * BUTTON_HEIGHT);
openButton.setSize(1.0, 0, 0.0, BUTTON_HEIGHT);
CButton saveButton(buttonPanel, "Save");
saveButton.setPosition(0.0, 0, 0.0, 2 * BUTTON_HEIGHT);
saveButton.setSize(1.0, 0, 0.0, BUTTON_HEIGHT);
CButton exitButton(buttonPanel, "Exit");
exitButton.setPosition(0.0, 0, 1.0, -1 * BUTTON_HEIGHT);
exitButton.setSize(1.0, 0, 0.0, BUTTON_HEIGHT);

当您不熟悉这种布局代码时,手动编写这样的布局代码可能会感觉很尴尬,但是一旦您掌握了它的窍门,就很容易了。

2. HTML、CSS、JavaScript

到目前为止,这是我能够一起破解的内容:

a) 主窗口、按钮面板和按钮的层次结构在 HTML 中给出:

<div id="mainWindow">
    <div id="buttonPanel">
        <div id="newButton" class="button"></div>
        <div id="openButton" class="button"></div>
        <div id="saveButton" class="button"></div>
        <div id="exitButton" class="button"></div>
    </div>
</div>

b) div 的位置在 CSS 中设置为绝对:

* {
    -webkit-box-sizing: border-box; 
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}
body { margin: 0; color: yellow; }
#mainWindow { position: absolute; background: red; }
#buttonPanel { position: absolute; background: green; }
.button { border: 1px solid cyan; }
#newButton { position: absolute; background: blue; }
#openButton { position: absolute; background: blue; }
#saveButton { position: absolute; background: blue; }
#exitButton { position: absolute; background: blue; }

c) 布局功能在 JavaScript 中使用 jQuery 实现:

function setPosition(widget, relLeft, absLeft, relTop, absTop) {
    $(widget)
        .css('left', relLeft * 100 + '%').css('left', '+=' + absLeft + 'px')
        .css('top', relTop * 100 + '%').css('top', '+=' + absTop + 'px');
}

function setSize(widget, relWidth, absWidth, relHeight, absHeight) {
    $(widget)
        .css('width', relWidth * 100 + '%').css('width', '+=' + absWidth + 'px')
        .css('height', relHeight * 100 + '%').css('height', '+=' + absHeight + 'px');
}

function setButtonText(button, text, height) {
    $(button)
        .text(text)
        .css('text-align', 'center')
        .css('vertical-align', 'middle')
        .css('line-height', height + 'px');
}

window.onresize = function () {
    var WINDOW_WIDTH = 400,
        WINDOW_HEIGHT = 300,
        PANEL_WIDTH = 150,
        BUTTON_HEIGHT = 30;

    setPosition('#mainWindow', 0.5, -WINDOW_WIDTH / 2, 0.5, -WINDOW_HEIGHT / 2);
    setSize('#mainWindow', 0.0, WINDOW_WIDTH, 0.0, WINDOW_HEIGHT);
    setPosition('#buttonPanel', 1.0, -PANEL_WIDTH, 0.0, 0);
    setSize('#buttonPanel', 0.0, PANEL_WIDTH, 1.0, 0);
    setButtonText('#newButton', "New", BUTTON_HEIGHT);
    setPosition('#newButton', 0.0, 0, 0.0, 0 * BUTTON_HEIGHT);
    setSize('#newButton', 1.0, 0, 0.0, BUTTON_HEIGHT);
    setButtonText('#openButton', "Open", BUTTON_HEIGHT);
    setPosition('#openButton', 0.0, 0, 0.0, 1 * BUTTON_HEIGHT);
    setSize('#openButton', 1.0, 0, 0.0, BUTTON_HEIGHT);
    setButtonText('#saveButton', "Save", BUTTON_HEIGHT);
    setPosition('#saveButton', 0.0, 0, 0.0, 2 * BUTTON_HEIGHT);
    setSize('#saveButton', 1.0, 0, 0.0, BUTTON_HEIGHT);
    setButtonText('#exitButton', "Exit", BUTTON_HEIGHT);
    setPosition('#exitButton', 0.0, 0, 1.0, -1 * BUTTON_HEIGHT);
    setSize('#exitButton', 1.0, 0, 0.0, BUTTON_HEIGHT);
};

onresize();

请注意,JavaScript 代码与上面显示的 C++ 代码非常相似!

我的问题

这种基于 JavaScript 的布局是否可以用于构建“真正的”Web 应用程序,或者我应该使用 CSS 代替吗?由于我基本上是桌面应用程序开发人员,因此我需要专家网络开发人员的意见。谢谢!

=== 更新 ===

是一个纯 HTML+CSS 的解决方案。我使用了@Christoph 建议的负边距技巧。我唯一的问题是相同的常量被复制到 CSS 中的很多地方。例如,九个地方使用了按钮高度(30px),这使得维护变得更加困难。

4

4 回答 4

4

一般来说,内联 css(通过 css 附加style="")被认为是一个糟糕的选择。由于您通过脚本动态生成它可能是可以接受的。

但是,存在一些问题:

  1. 通常,应尽量少用绝对定位。
  2. 绝对没有必要改变window.onresize. 应极其谨慎地使用此事件。正如您在小提琴中看到的,您的示例 UI 相当小,但在调整窗口大小时已经变得无响应。(无论如何,您示例中的这些值都是静态的)

所以我的提示是:

  1. 使用某种init()方法进行初始布局
  2. 避免window.onresize或至少使用一些超时机制来减少那些绘制事件的触发(减少对 .resize 和 .scroll 方法的调用次数
  3. 也许代替 jQuery 的调用,在单独的 stylesheetcss()中为您的元素编写 css 。
  4. 最佳解决方案:在服务器端生成 html 和 css 标记并将最终的 html+css 提供给浏览器。优点:更快的渲染 + 可维护 + 你得到一个可缓存的样式表和 html
于 2013-07-01T11:42:23.630 回答
2

简短的回答:

这是不好的 !永远不要那样做。

长答案:

这不是网络应该工作的方式。您的应用程序不会很好地执行,因为 css 规则将等待 js 被下载和解释;但这不是这里的主要问题。主要关心的是你。

您将永远无法维护这样的代码。当您构建一个简单的应用程序时,您可以轻松地访问数千个 css 规则。如果以这种方式组织,则无法阅读。我什至没有提到媒体查询的东西。以这种方式构建应用程序的复杂性太高了。

如果你想上网,你必须拥抱网络;不要尝试旧的桌面应用程序开发技巧(这些技巧非常适合桌面应用程序)。例如,如果你想在右上角放一些东西,你可以选择 : right: 0。不WINDOW_WIDTH; 如果你的蚂蚁以某事为中心,你有很多方法可以做到这一点;但你不会为这个职位做数学。永远不要那样做。


作为一名网络应用程序开发人员,我的建议是:

去使用指南针:http ://compass-style.org/

实际上没有,去使用 Yeoman :http: //yeoman.io/

这些工具有点复杂,无法完全理解;但它非常值得。


顺便说一句,永远不要绑定这样的onresize事件。你必须添加一个,debounce否则你会遇到严重的表演麻烦。

于 2013-07-01T12:22:07.560 回答
2

使用 CSS设置初始值总是更容易,性能方面也更快。将所有内容设置为绝对可以工作,但根据应用程序,可能会成为布局的噩梦,因为绝对定位的元素会从正常流程中删除。

虽然我知道您来自哪里,曾经为桌面编写过图形应用程序,但您会发现它不适用于 Web,除非您期望布局性能不重要的固定布局。

但是,我正在考虑当今世界的布局线,您需要适应各种形状和尺寸的大量设备。一方面,使用 javascript 可以更容易地控制所有这些,而且很多时候它是最好的方法,但是,otoh,CSS 可以通过媒体查询来处理很多这样的事情,从而减轻你和你的编码的负担。

需要考虑很多。

于 2013-07-01T11:36:37.980 回答
1

我绝对不是专家,但这是我的 2 美分:

在您的设计中使用 JavaScript 一直都很好。但为了做到这一点,你还需要一些静态 CSS,对于所有没有启用 JavaScript 的人,用于可访问性等问题。

Javascript 设计一直是关于增强您的 Web 应用程序,而不是替换它。你绝对应该看看这个关于Unobtrusive JavaScript的 Wikipedia 页面。

回到您的问题,为什么不让您的按钮默认具有固定大小,并让您的 JavaScript 功能在可用时替换它?

另外,我在您的 Web 应用程序中没有得到的是,在这里,一切都可以在 CSS 中完成,而且速度更快。它会有更好的性能,你甚至不必担心 JavaScript。

于 2013-07-01T11:36:39.540 回答