
Irgendwie wollte ich versuchen, eine kleine Client-Server-Anwendung zu implementieren. Die Implementierung in der Idee war folgende: Auf der Clientseite zeichnen wir Fenster mit einer Art JS-Framework, auf der Serverseite verarbeiten wir Aufrufe vom Client mithilfe einer kompilierten Anwendung, die beispielsweise in Go geschrieben wurde.
Ich fing an, ein Framework aufzunehmen, das eine deklarative Schnittstelle bietet. Meiner Ansicht nach sollte es die Beschreibung des Formularinhalts so einfach wie möglich erhalten (z. B. im Format YAML, JSON, BEMJSON , XML oder sogar INF) und bei der Ausgabe ein schönes Formular im Browser mit funktionierenden Steuerelementen zeichnen.
Beruflich bin ich nicht in die Webentwicklung involviert und hatte daher nicht erwartet, dass ich zu diesem Zeitpunkt lange stecken bleiben würde.
Und ich wollte keinen Artikel schreiben, aber dann dachte ich, dass eine neue Außenansicht moderner Webtechnologien, selbst für Anfänger, für die Community interessant sein könnte. Eine Gelegenheit, wieder Feedback zu bekommen ...
HTML- und CSS-Vorlagen
Alles, was ich fand, funktionierte nicht wie ich wollte. Ich möchte nichts über Layout und Stile wissen. Ich möchte auch nicht den HTML-Code ausfüllen, wie dies beim Anwenden von Frameworks wie Bootstrap , Skeleton , MDL usw. geschieht.
Beispielcode mit Bootstrap:
<div class="input-group mb-3"> <div class="input-group-prepend"> <div class="input-group-text"> <input type="checkbox" aria-label="Checkbox for following text input"> </div> </div> <input type="text" class="form-control" aria-label="Text input with checkbox"> </div> <button type="button" class="btn btn-primary btn-lg btn-block">Block level button</button>
Alles, was ich auf die Eingabe anwenden möchte, sollte ungefähr so aussehen:
{ "main": { "prop":{}, "elements": [ { "type":"checkbox", "name":" -", "style":"classic", "checked": true }, { "type":"button", "name":"", "style":"outline", "onclick":"btnsave_onclick" } } }
Nun, damit es möglich ist, Elemente in Gruppen zu kombinieren und anzugeben, wie Elemente innerhalb der Gruppe angeordnet werden sollen: vertikal oder horizontal. Was das Design dort sein wird, ist für mich nicht besonders wichtig. Ich hatte erwartet, sogar eine Art visuellen Fenstereditor zu finden, aber nicht.
Technologiemontage
Dann habe ich versucht, nach einigen Technologiebaugruppen zu suchen - jemand muss lange und mehr als einmal einen langen Weg geebnet haben.
Und ich habe etwas Ähnliches gefunden, das ich brauche: Eine Website von Grund auf auf einem vollständigen Stapel von BEM-Technologien .
BEMJSON Beispiel:
({ block: 'page', title: 'Hello, World!', styles: [ { elem: 'css', url: 'index.min.css' } ], scripts: [ { elem: 'js', url: 'index.min.js' } ], content: [ 'Hello, World!' ] })
Als ich durch den 20. Bildschirm des Textes gescrollt habe und der Schieberegler immer noch oben war, dachte ich, dass dieser kurze Weg irgendwie lang war. Es wird nicht funktionieren.
Übrigens habe ich über dieses BEM gelesen - ich mochte die Essenz und sie wurde gut und gut beschrieben. Es gibt verschiedene Spickzettel, zum Beispiel hat mir dieser gefallen. Ich habe auch nach Informationen gesucht und festgestellt, dass nicht jeder die Technologie mag (zum Beispiel hier und hier ). Und hier wird meiner Meinung nach das Wesentliche kontroverser Punkte dargelegt.
Das Interessante ist, dass ich mit der Suche, abgesehen von BEM, lange Zeit keine alternativen Technologien mehr finden konnte. Dies sind jedoch: OOCS (ähnlich wie das gleiche BEM, nur einfacher), SMACSS , AtomicCSS , CSSinJS ( hier zu finden ).
Node.js
Ich dachte dann, ok, Sie können die ursprüngliche Idee aufgeben und den Serverteil in einer Skriptsprache implementieren, dh einfach nodejs verwenden. Es ist nicht nur modisch, stilvoll, jugendlich, es ist auch eine Gelegenheit, auf allen Ebenen in einer Sprache zu schreiben. Wieder viele Artikel (mir hat dieser Artikel über den Schnellstart gefallen). Wenn ich das richtig verstehe, sind unzählige NPM-Pakete für fast jede Aufgabe dafür geschrieben. Es gibt immer noch so etwas Ernstes wie Electron in diesem Geschäft.
Beispielseitencode mit Electron:
<head> <meta charset="utf-8"> <link rel="stylesheet" href="assets/css/variables.css"> <link rel="import" href="sections/about.html"> </head> <body> <nav class="nav js-nav"> <header class="nav-header"> <h1 class="nav-title">Electron <strong>API Demos</strong></h1> </header> <div class="nav-item u-category-windows"> </div> <footer class="nav-footer"> <button type="button" id="button-about" data-modal="about" class="nav-footer-button">About</button> </footer> </nav> <main class="content js-content"></main> <script> require('./assets/normalize-shortcuts') </script> </body> </html>
Die einzigen Minusknoten, mit denen man mit Go produktiver schreiben kann.
Angenommen, ich möchte nodejs verwenden. Es gibt einen Katalog mit NPM-Paketen, damit Sie sich etwas Passendes aussuchen können.
Es gibt ein Paket namens Formulare . Hier ist ein Beispielcode:
var forms = require('forms'); var fields = forms.fields; var validators = forms.validators; var reg_form = forms.create({ username: fields.string({ required: true }), password: fields.password({ required: validators.required('You definitely want a password') }), confirm: fields.password({ required: validators.required('don\'t you know your own password?'), validators: [validators.matchField('password')] }), email: fields.email() });
Dies wird durch den Befehl reg_form.toHTML();
in das Formular reg_form.toHTML();
. Eine interessante Option, aber das nicht.
Es gibt auch Element , Riot , TotalJS und iView . Dies kann der Liste von Bootstrap, MDL usw. hinzugefügt werden.
Beispiel für einen Seitencode mit Element:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"> </head> <body> <div id="app"> <el-button @click="visible = true">Button</el-button> <el-dialog :visible.sync="visible" title="Hello world"> <p>Try Element</p> </el-dialog> </div> </body> <script src="https://unpkg.com/vue/dist/vue.js"></script> <script src="https://unpkg.com/element-ui/lib/index.js"></script> <script> new Vue({ el: '#app', data: function() { return { visible: false } } }) </script> </html>
Es gibt auch Blueprintsjs . Dies ist vielleicht das ähnlichste, wonach ich gesucht habe. Es ist möglich, die Steuerelemente getrennt voneinander zu konfigurieren.
Der Code sieht ungefähr so aus:
Viel Code mit Blaupausen import * as React from "react"; import { FormGroup, H5, InputGroup, Intent, Switch } from "@blueprintjs/core"; import { Example, handleBooleanChange, handleStringChange, IExampleProps } from "@blueprintjs/docs-theme"; import { IntentSelect } from "./common/intentSelect"; export interface IFormGroupExampleState { disabled: boolean; helperText: boolean; inline: boolean; intent: Intent; label: boolean; requiredLabel: boolean; } export class FormGroupExample extends React.PureComponent<IExampleProps, IFormGroupExampleState> { public state: IFormGroupExampleState = { disabled: false, helperText: false, inline: false, intent: Intent.NONE, label: true, requiredLabel: true, }; private handleDisabledChange = handleBooleanChange(disabled => this.setState({ disabled })); private handleHelperTextChange = handleBooleanChange(helperText => this.setState({ helperText })); private handleInlineChange = handleBooleanChange(inline => this.setState({ inline })); private handleLabelChange = handleBooleanChange(label => this.setState({ label })); private handleRequiredLabelChange = handleBooleanChange(requiredLabel => this.setState({ requiredLabel })); private handleIntentChange = handleStringChange((intent: Intent) => this.setState({ intent })); public render() { const { disabled, helperText, inline, intent, label, requiredLabel } = this.state; const options = ( <> <H5>Props</H5> <Switch label="Disabled" checked={disabled} onChange={this.handleDisabledChange} /> <Switch label="Inline" checked={inline} onChange={this.handleInlineChange} /> <Switch label="Show helper text" checked={helperText} onChange= {this.handleHelperTextChange} /> <Switch label="Show label" checked={label} onChange={this.handleLabelChange} /> <Switch label="Show label info" checked={requiredLabel} onChange= {this.handleRequiredLabelChange} /> <IntentSelect intent={intent} onChange={this.handleIntentChange} /> </> ); return ( <Example options={options} {...this.props}> <FormGroup disabled={disabled} helperText={helperText && "Helper text with details..."} inline={inline} intent={intent} label={label && "Label"} labelFor="text-input" labelInfo={requiredLabel && "(required)"} > <InputGroup id="text-input" placeholder="Placeholder text" disabled={disabled} intent={intent} /> </FormGroup> <FormGroup disabled={disabled} helperText={helperText && "Helper text with details..."} inline={inline} intent={intent} label={label && "Label"} labelFor="text-input" labelInfo={requiredLabel && "(required)"} > <Switch id="text-input" label="Engage the hyperdrive" disabled={disabled} /> <Switch id="text-input" label="Initiate thrusters" disabled={disabled} /> </FormGroup> </Example> ); } }
Das Ergebnis sieht folgendermaßen aus:

Auch wenn wir nur den letzten Teil berücksichtigen: Trotzdem ist es irgendwie nicht sehr prägnant.
Ich habe auch eine interessante Sache im Web gefunden: metadatajs . Ein schneller Start ist da . Diese Bibliothek verfügt über redundante Funktionen, und in dem Artikel ist meiner Meinung nach das Wichtigste nicht - die Beschreibung der Bibliothek selbst. Es ist hier .
Es wird uns angeboten, das Formular wie folgt zu beschreiben:
Beschreibung des Formulars mit metadata.js { "enm": {}, "cat": { "": { "form": { "selection": { "fields": [ "is_folder", "id", "", "_t_.name as presentation", "`cat_`.name as ``", "`cat_`.name as ``" ], "cols": [ {"id": "id", "width": "120", "type": "ro", "align": "left", "sort": "server", "caption": ""}, {"id": "", "width": "150", "type": "ro", "align": "left", "sort": "server", "caption": ""}, {"id": "presentation", "width": "*", "type": "ro", "align": "left", "sort": "server", "caption": ""}, {"id": "", "width": "70", "type": "ro", "align": "left", "sort": "server", "caption": ""}, {"id": "", "width": "170", "type": "ro", "align": "left", "sort": "server", "caption": " "} ] } } }, "": { "form": { "selection": { "fields": [ "is_folder", "id", "_t_.name as presentation", "`enm_`.synonym as ``", "`cat_`.name as ``" ], "cols": [ {"id": "presentation", "width": "*", "type": "ro", "align": "left", "sort": "server", "caption": ""}, {"id": "", "width": "150", "type": "ro", "align": "left", "sort": "server", "caption": " "}, {"id": "", "width": "150", "type": "ro", "align": "left", "sort": "server", "caption": ""} ] } } } }, "doc": { "": { "form": { "selection": { "fields": [ "date", "number_doc", "", "", "posted", "", "" ], "cols": [ {"id": "date", "width": "120", "type": "ro", "align": "left", "sort": "server", "caption": ""}, {"id": "number_doc", "width": "120", "type": "ro", "align": "left", "sort": "server", "caption": ""}, {"id": "", "width": "170", "type": "ro", "align": "left", "sort": "server", "caption": ""}, {"id": "", "width": "120", "type": "ron", "align": "right", "sort": "server", "caption": ""}, {"id": "", "width": "100", "type": "ro", "align": "left", "sort": "server", "caption": ""}, {"id": "", "width": "*", "type": "ro", "align": "left", "sort": "server", "caption": ""} ] }, "obj": { "head": { " ": ["number_doc", "date", "", "", "", ""], "": ["", "", ""], "": ["", "", "", "", "", "", "", {"id": "", "path": "o.", "synonym": " ", "type": "ro"} ] }, "tabular_sections": { "": { "fields": ["row","","","","","","","","","","","","",""], "headers": "№,,,.,,,% ,,% ,,,.,,", "widths": "40,*,*,70,50,70,70,70,70,70,70,70,70,80", "min_widths": "40,200,140,70,50,70,70,70,70,70,70,70,70,80", "aligns": "", "sortings": "na,na,na,na,na,na,na,na,na,na,na,na,na,na", "types": "cntr,ref,ref,calck,refc,calck,calck,ron,refc,ron,ron,dhxCalendar,ref,txt" } } } } } }, "ireg": {}, "areg": {}, "dp": {}, "rep": {}, "cch": {}, "cacc": {} }
Dies ist sehr ähnlich zu dem, was Sie brauchen. Es stellen sich jedoch Fragen: Scheint der Schaltflächensatz standardmäßig eingestellt zu sein? Kann ich es ändern? Wo ist die Syntaxbeschreibung (was ist "enm", "cat" usw.)?
Es ist zu sehen, dass viel Aufwand in das Projekt gesteckt wurde, aber die Bibliothek ist immer noch feucht.
Fazit
Spekulieren wir. Formulare können auf dem Server vorgezeichnet, kompiliert und an den clientseitigen HTML / CSS / JS-Code gesendet werden. In diesem Fall müssen Sie nach etwas völlig anderem suchen. Wenn wir jedoch möchten, dass der Benutzer in einem Browserfenster mit uns zusammenarbeitet und in diesem Fenster die untergeordneten Fenster der Webanwendung sieht, ist es nicht logisch, den CSS / JS-Code auf dem Client zwischenzuspeichern, der kurze Befehle vom Server mit einer Beschreibung des nächsten Formulars erhält und werden sie auf Kosten der Kundenressourcen gezogen?
Kollegen, wo verstecken Sie das deklarative Schnittstellen-Framework? )
Er muss sein! Warum kann ich ihn nicht finden?