当前位置:网站首页>A page widgetization practice
A page widgetization practice
2022-07-25 08:41:00 【Four fires】
I was working on the page reconstruction recently, and here is how I divide a page into widgets and how do they interacts in this new attempt.
Core Concepts
Page and widget: A page is composed by several widgets, and a widget is the minimum unit for reuse.
Widget controller: Accepts multiple widget data requirements and deduplicates their data types, sends Ajax request to server side, receives bound data of different types in JSON format, and deliver to each widget to render. It works as the core for page aggregation. The reason a centralized controller on the page sends request to server side rather than widgets do themselves is to reduce the Ajax request count and improve b/s interaction efficiency.
Data type, data format and data: A widget defines a way of data visualization, which requires the data in one certain data format, but in different data types. Say, a 2-dimension chart widget visualizes the data in the format of 2-d number array. Data type is a business aware concept, meaning what the data stand for.
Folder structure
ICanHaz.js
jquery.js
require.js
css.js // RequireJS plugin
text.js // RequireJS plugin
widget-controller.js
date // widget folder, contains:
-- template.html // widget template
-- widget.css // widget styles
-- widget.js // widget javascript
-- test.html // test page
-- test.js // test page javascript
-- test.json // test page dataThe widget named “date” is self-contained, specifically with its test cases included. Simple, decoupled and reusable, the whole mechanism is composed by:
controller / widget / widget styles / widget template / widget test suite
Code
The code of the controller (widget-controller.js):
/**
* Core controller for widget aggregation.
*/
define([],
function() {
return function(){
// key: data type, value: widget
var mappings = {};
var widgets = [];
var preCallback = function(){};
var postCallback = function(){};
/**
* add a widget to page
* @return this
*/
this.add = function(widget) {
widgets.push(widget);
if (widget.dataTypes) {
$.each(widget.dataTypes, function(index, dataType) {
if (!mappings[dataType])
mappings[dataType] = [];
mappings[dataType].push(widget);
});
}
return this;
};
/**
* commit data and send an Ajax request, parse and deliver responded data to each widget
* @param params page level parameters
* @return this
*/
this.commit = function(params) {
// TODO, sending request to server side, deliver the result data to widgets according to mappings, and call this.render to finalize the widget visualization
return this;
};
/**
* render widget with data, exposing this method for easier local test
* @param widget
* @param data
* @return this
*/
this.render = function(widget, data) {
widget.render.call(widget, data);
return this;
};
/**
* set page level callback when data retrieved, but before any widget rendering:
* function(data) {} // returned value will be treated as the data updated for rendering
* @param func
* @return this
*/
this.setPreCallback = function(func) {
preCallback = func;
return this;
};
/**
* set page level post callback after the rendering of all widgets, specifically for customized interactions between widgets:
* function(data) {}
* @param func
* @return this
*/
this.setPostCallback = function(func) {
postCallback = func;
return this;
};
};
}
);Test page (test.html) is the entrance for local test. Considering the legacy code, I didn’t import JQuery and ICanHaz by RequireJS:
<html>
<head>
<script type="text/javascript" src="../jquery.js"></script>
<script type="text/javascript" src="../ICanHaz.js"></script>
<script data-main="test" src="../require.js"></script>
</head>
<body>
<div>
<widget name="birth-date" />
</div>
<div>
<widget name="death-date" />
</div>
</body>
</html>Please note the local test can only be run on FireFox or Chrome because of this limitation.
Javascript for test page (test.js). Two instances (birthDateWidget and deathDateWidget) of the same widget date:
require.config({
baseUrl: '../',
paths: {
'jquery' : 'jquery',
'icanhaz' : 'ICanHaz',
'text' : 'text',
'css' : 'css',
'domReady' : 'domReady',
'widget-controller' : 'widget-controller',
'widget-date' : 'date/widget'
}
});
require(['widget-controller', 'widget-date', 'text!date/test.json'], function (WidgetController, DateWidget, json){
var controller = new WidgetController();
var birthDateWidget = new DateWidget({name : 'birth-date'});
var deathDateWidget = new DateWidget({name : 'death-date'});
controller.add(birthDateWidget).add(deathDateWidget);
//controller.commit({...}); sending ajax request
var dataObj = eval ("(" + json + ")");
controller.render(birthDateWidget, dataObj.birth).render(deathDateWidget, dataObj.death);
});Widget javascript (widget.js) loads its styles and visualize the data to actual DOMs:
define(['text!date/template.html', 'css!date/widget'],
function(template) {
ich.addTemplate('widget-date-template', template);
return function(attrs){
this.render = function(data){
var html = ich['widget-date-template'](data);
$("widget[name=" + attrs.name + "]").replaceWith(html);
};
};
}
);Widget styles (widget.css) are only be imported when the widget is actually used on the page:
div .widget-date {
margin-top: 10px;
border: 1px solid #000000;
}ICanHaz is used to decouple data and widget template, and the two are finally aggregated on a widget.
Widget template (template.html):
<div class="widget-date">
type: {{name}}, date: {{date}}
</div>Data (test.json), which is hard coded for widget test, but should be retrieved from server side in reality:
{
birth : {name: 'birth', date : '2015-02-14'},
death : {name: 'death', date : '2015-03-14'}
}The prototype code can be download here: prototype.zip.
====================================================================
[2/17/2015] Updated: create “template controller” to move the template logic out of widget.
Template (template-controller.js):
/**
* Template controller.
* @module
*/
define([],
function() {
/**
* Template controller constructor.
* @class
* @param name, template controller name, used as the key for compiled template storage
* @param template
*/
return function(name, template) {
// template should be compiled only once
ich.addTemplate(name, template);
/**
* Render the data on widget.
* @param attrs, widget level attributes, specifically, attrs.id should be the exactly same as the attribute id of that widget DOM
* @param data, mutable business aware data, data has higher priority than attrs when they have the same key
*/
this.render = function(attrs, data) {
// merge objects, deep copy
var merged = {};
$.extend(true, merged, attrs, data);
var html = ich[name](merged);
$("widget[name=" + attrs.id + "]").replaceWith(html);
};
};
}
);So the widget (widget.js) javascript is much simpler now:
/**
* DateWidget module.
* @module
*/
define(['template-controller', 'text!date/template.html', 'css!date/widget'], // template and css
function(TemplateController, template) {
var templateController = new TemplateController('widget-date', template);
/**
* Class DateWidget constructor. Method render is mandatory for any widget.
* @class
* @param attrs, widget level attributes, specifically, attrs.id should be the exactly same as the attribute id of that widget DOM
* @return the concrete widget class
*/
return function(attrs) {
/**
* Render the widget.
* @param data, attrs will be merged into data and sent to template controller to finalize the rendering
*/
this.render = function(data) {
templateController.render(attrs, data);
};
};
}
);New code download link: widgets.zip.
The articles are all original without special indication , It shall not be used for any commercial purpose without permission , Please keep the integrity of reprint and indicate the source link 《 Four fire's nagging 》
边栏推荐
- [dark horse programmer] redis learning notes 003: redis transactions
- Idea2021 failed to start. Could not find main class com/intellij/idea/main
- Mongodb database
- IP command usage details
- Wechat applet ordering system graduation design of applet completion works (8) graduation design thesis template
- serialization and deserialization
- @Use of Autowired
- JS pop up picture Lightbox light box plug-in spotlight.js
- Intelligent operation and maintenance scenario analysis: how to detect abnormal business system status through exception detection
- Chapter 3 business function development (realize the real-time response of the select all button)
猜你喜欢

【万字长文】使用 LSM-Tree 思想基于.Net 6.0 C# 实现 KV 数据库(案例版)

华为设备远程登录(Telnet、SSH)配置

Redis best practices

JS typewriter animation JS special effect plug-in autotyperjs
![RTOS series (13): assembly LDR instruction, LDR pseudo instruction, [rn] register indirect reference detailed analysis](/img/87/d116e729c771fcf3ce95958a45d85f.png)
RTOS series (13): assembly LDR instruction, LDR pseudo instruction, [rn] register indirect reference detailed analysis

Intel apologized to the winners of Xe HPG treasure hunt game for product delay and announced the appearance of the prize

Wechat reservation of completed works of applet graduation project (4) opening report

Redis最佳实践

Brush the title "sword finger offer" day01

Numpy learning
随机推荐
JVM specification Oracle official website
@Feignclient annotated interface. You may not get instances with @autowired
Wechat reservation of the completed works of the applet graduation project (6) opening defense ppt
Swift初始化器及可选链
华为设备远程登录(Telnet、SSH)配置
技术面②Mysql中的索引(index)类型有哪些并简要介绍一下?什么时候需要创建索引?什么时候不需要创建索引?为什么创建索引后查询速度会提高?
Redis fragment cluster
Redis best practices
Data warehouse ODS, DWD floor, 220616, HM,
@Use of data annotation (instead of get and set methods in entity classes)
Numpy learning
[shader realizes shadow projection effect _shader effect Chapter 8]
Foundation 32: page element positioning method XPath --- axis positioning method
Sun Tzu's art of war
Redis分片集群
[dark horse programmer] redis learning notes 005: enterprise level solutions
【无标题】
Force buckle - 1046. Weight of the last stone
Tips for improving code sustainability, take connectto method as an example.
Technical aspect ② what are the index types in MySQL and briefly introduce them? When do I need to create an index? When is it not necessary to create an index? Why does the query speed increase after