qq临时会话组件
组件模型是任何编程平台的重要组成部分,因为它们提供了一组标准的UI元素和用于构建更多组件的基础结构。
HTML5是一项相对较年轻的技术,具有一组甚至更年轻的规范,旨在规范HTML5组件的实现及其与其他组件的集成。 HTML5组件模型当前由三个规范定义:
- “ Web组件简介”
- “阴影DOM”
- “ HTML模板”
这三个规范中的功能包括封装组件DOM树(Shadow DOM),为页面作者可以在其HTML页面中使用的组件创建自定义标签(自定义HTML元素),以及声明性地指定Shadow DOM和插入点(HTML模板)。 (有关更多详细信息,请参见“ HTML5组件规范 ”侧栏。)
但是首先要实现组件,您需要一套完全不同的技能,包括创建吸引人的图形,支持有趣的交互HTML元素层以及支持事件侦听器的能力。 本系列涵盖HTML5组件开发的所有这些方面:
- 临时组件
- Shadow DOM,模板和自定义元素
- Mozilla的X-Tag
在本文和该系列的下一篇文章中,将了解如何在没有新规范的任何支持的情况下从头实现临时HTML5组件。 以后的文章将探索规范,并向您展示如何将Shadow DOM,自定义元素和模板合并到HTML5组件构建库中。
更具体地说,在本文中,学习如何:
- 实施临时HTML5组件
- 使用
canvas
元素绘制吸引人的图形 - 对画布元素进行分层以实现特殊效果
- 实现HTML元素的实时拖动
从多个组件中构建一个HTML5组件
图1显示了由其他更通用的组件构建的图像处理组件:图标,工具栏,滑块和图像显示区域。
图1.图像处理组件
工具栏中的三个图标(调整大小,旋转和亮度)与滑块相关联。 当您单击其中一个图标时,图像处理组件将在工具栏下方显示一个滑块和几个相关的按钮。 图1的顶部屏幕快照说明了调整大小滑块的用法。 底部屏幕截图显示了使用旋转滑块旋转后的图像。
滑块组件
滑块由导轨和旋钮组成; 您可以通过沿轨道移动旋钮来更改滑块的值。 旋钮的位置确定滑块的值(如果以编程方式设置该值并重新绘制滑块,则反之亦然)。 该值(介于0.0到1.0之间的数字)表示位于旋钮左侧的导轨的百分比。 例如,当滑轨的四分之三位于旋钮的左侧时,滑块的值为0.75。
图2显示了一个简单的应用程序,该应用程序说明了如何使用滑块。 除了滑块之外,该应用程序还包含两个按钮,用于将滑块的旋钮逐渐移至右侧(+)或左侧(-)。 该应用程序还在滑块下方提供一个读数,以显示滑块的当前值。 请参阅相关信息的链接,运行应用程序; 您还可以下载源代码。
图2.一个滑块
用户可以通过三种方式移动滑块的旋钮:
- 单击其中一个按钮可将滑块的值增加(+)或减少(-)10%。
- 拖动旋钮。
- 在旋钮外部的滑轨中单击,以将旋钮的中心移至单击位置。
通过编程方式设置滑块的值时(在您激活加号(+)或减号(-)或启用单击旋钮外的滑块轨道时就是这种情况),旋钮的移动通过CSS过渡轻松实现了动画效果-输出功能,可在接近最终目的地时减慢旋钮的速度。 滑块组件在JavaScript中设置过渡的属性。
要使用滑块,请实例化一个并将其附加到现有DOM元素上,如清单1所示。
清单1.创建一个滑块
var slider = new COREHTML5.Slider( // All of the following arguments are optional
'navy', // Stroke color
'cornflowerblue', // Fill color
0.5, // Initial slider value
500); // Knob animation duration in milliseconds
...
slider.appendTo('someDiv'); // Appends the slider to a DOM element with the ID someDiv
滑块的appendTo()
方法将调整滑块的大小,以使其扩展或缩小以适合滑块所连接的元素。
滑块的功能是:
- 使用
appendTo()
方法附加到DOM元素 - 自动调整大小以填充与滑块连接的DOM元素
- 使用
addChangeListener()
方法注册更改事件侦听器 - 滑动旋钮移动时触发更改事件以更改侦听器
- 当用户单击滑轨时,使用CSS过渡对旋钮进行动画处理
滑块是COREHTML5.Slider
实例,可以避免名称空间冲突。 想象有人用一个更明显的名称实现一个滑块(如Slider
,可以用相同的名称替换任何现有的全局对象,这并非难事。 但是,不太可能有人会自己提出COREHTML5.Slider
。
COREHTML5.Slider
构造函数的参数都是可选的。 所有值都有合理的默认值。 表1列出了关键的COREHTML5.Slider
方法。
表1.关键滑块方法
方法 | 描述 |
---|---|
appendTo(elementId) | 将滑块的DOM元素追加到其ID与传递给该方法的值匹配的元素上。 |
addChangeListener(listenerFunction) | 将更改侦听器功能添加到滑块。 当滑块的旋钮更改位置时,滑块会向其所有更改侦听器触发一个事件。 |
draw() | 绘制滑块的轨道和旋钮。 |
erase() | 擦除滑块。 |
redraw() | 擦除然后绘制滑块。 |
表1仅列出了开发人员用来操纵滑块的外部方法。 COREHTML5.Slider
对象还具有内部使用的许多方法,例如initializeStrokeAndFillStyles()
和createKnobCanvas()
。
开发人员可以通过其knobPercent
属性访问滑块的值。
使用滑杆
清单2显示了图2所示的应用程序HTML。
清单2.滑块示例HTML
<!DOCTYPE html>
<html>
<head>
<title>Ad hoc components</title>
<style>
body {
background: rgb(240,240,240);
}
#title {
font: 18px Arial;
}
#slider-component {
width: 400px;
text-align: center;
}
#buttons {
display: inline;
font: 14px Arial;
}
#readout {
margin-left: 25%;
color: blue;
font: 18px Arial;
text-shadow: 2px 2px 2px rgb(255,255,255);
}
#slider {
width: 75%;
height: 30px;
float: right;
}
.slider-button {
background: rgba(100, 100, 100, 0.2);
font: 24px Arial;
font-weight: 1;
border-radius: 4px;
border: 1px solid rgba(100, 100, 180, 0.7);
background: rgba(255, 255, 0, 0.2);
box-shadow: 1px 1px 2px rgba(0,0,0,0.5);
cursor: pointer;
margin: 0px;
}
</style>
</head>
<body>
<div id='title'>A custom slider</div>
<p>
<div id='slider-component'>
<div id='controls'>
<div id='buttons'>
<input type='button' class='slider-button'
id='minus-button' value='–'/>
<input type='button' class='slider-button'
id='plus-button' value='+'/>
</div>
<div id='slider'></div>
</div>
<div id='readout'>0</div>
</div>
</p>
</body>
<script type="text/javascript" src="lib/slider.js"></script>
<script type="text/javascript" src="sliderExample.js"></script>
</html>
清单2中HTML创建了如图3所示的DOM树。
图3.滑块示例的DOM树
Listing 2
HTML和CSS很简单。 HTML引用了两个脚本,一个用于滑块,另一个用于应用程序本身。 清单3中显示了该应用程序的脚本。
清单3.滑块示例JavaScript
var slider = new COREHTML5.Slider('black', 'cornflowerblue', 0),
readoutElement = document.getElementById('readout');
document.getElementById('minus-button').onclick = function (e) {
slider.knobPercent -= 0.1;
slider.redraw();
updateReadout();
}
document.getElementById('plus-button').onclick = function (e) {
slider.knobPercent += 0.1;
slider.redraw();
updateReadout();
}
function updateReadout() {
if (readoutElement)
readoutElement.innerHTML = slider.knobPercent.toFixed(2);
}
slider.addChangeListener(updateReadout);
slider.appendTo('slider');
slider.draw();
在清单3中 JavaScript的顶部,该应用程序创建具有黑色笔触样式,矢车菊蓝色填充样式和初始值为零的滑块。 在JavaScript的底部,应用程序将滑块添加到ID为slider
的DOM元素上。 在这两者之间,JavaScript定义了三个事件处理程序,用于响应按钮的单击和滑块值的更改。
该应用程序将onclick
事件处理程序添加到加号(+)和减号(-)按钮,这些按钮可调整滑块的值( knobPercent
),重新绘制滑块并更新读数。
该应用程序还向滑块添加了一个更改侦听器,以更新应用程序的读数以反映滑块的新值。 组件通常提供一种注册事件侦听器并向这些侦听器触发事件的机制,并且滑块组件也不例外。
现在,您已经了解了如何使用滑块,让我们看一下滑块组件的实现。
创建和初始化滑块
清单4显示了滑块的构造函数JavaScript代码。
清单4.滑块的构造函数
COREHTML5 = COREHTML5 || {};
COREHTML5.Slider = function(strokeStyle, fillStyle,
knobPercent, knobAnimationDuration) {
knobPercent = knobPercent || 0;
knobAnimationDuration = knobAnimationDuration || 1000; // milliseconds
this.railCanvas = document.createElement('canvas');
this.railContext = this.railCanvas.getContext('2d');
this.changeEventListeners = [];
this.initializeConstants();
this.initializeStrokeAndFillStyles(strokeStyle, fillStyle);
this.initializeKnob(knobPercent, knobAnimationDuration);
this.createDOMTree();
this.addMouseListeners();
this.addKnobTransitionListeners();
return this;
}
清单4的第一行使用通用JavaScript习惯用法来确保存在一个全局对象(在本例中为COREHTML5
)。 (如果存在,则将其分配给自身;否则,将其分配给空对象。)
COREHTML5.Slider
构造函数使用四个可选参数:笔触颜色,填充颜色,初始滑块值和旋钮动画持续时间(以毫秒为单位)。 knobPercent
表示滑块的值。
构造函数创建一个画布— railCanvas
—包含滑块的轨道。 它还使用createKnobCanvas()
(如清单5所示createKnobCanvas()
创建了第二个画布— knobCanvas
(清单5中所示),由initializeKnob()
在清单4中调用。 最后,构造函数创建滑块的DOM树并将侦听器添加到滑块。
清单5显示了由滑块的构造函数调用的前三个滑块方法— initializeConstants()
, initializeStrokeAndFillStyles()
和initializeKnob()
。
清单5.滑块的初始化方法
COREHTML5.Slider.prototype = {
initializeConstants: function () {
this.SHADOW_COLOR = 'rgba(100, 100, 100, 0.4)';
this.SHADOW_OFFSET_X = 3;
this.SHADOW_OFFSET_Y = 3;
this.SHADOW_BLUR = 4;
this.KNOB_SHADOW_COLOR = 'rgba(255,255,0,0.8)';
this.KNOB_SHADOW_OFFSET_X = 1;
this.KNOB_SHADOW_OFFSET_Y = 1;
this.KNOB_SHADOW_BLUR = 0;
this.KNOB_FILL_STYLE = 'rgba(255, 255, 255, 0.45)';
this.KNOB_STROKE_STYLE = 'rgb(0, 0, 80)';
this.HORIZONTAL_MARGIN = 2.5 * this.SHADOW_OFFSET_X;
this.VERTICAL_MARGIN = 2.5 * this.SHADOW_OFFSET_Y;
this.DEFAULT_STROKE_STYLE = 'gray';
this.DEFAULT_FILL_STYLE = 'skyblue';
},
initializeStrokeAndFillStyles: function(strokeStyle, fillStyle) {
this.strokeStyle = strokeStyle ? strokeStyle : this.DEFAULT_STROKE_STYLE;
this.fillStyle = fillStyle ? fillStyle : this.DEFAULT_FILL_STYLE;
},
initializeKnob: function (knobPercent, knobAnimationDuration) {
this.animatingKnob = false;
this.draggingKnob = false;
this.knobPercent = knobPercent;
this.knobAnimationDuration = knobAnimationDuration;
this.createKnobCanvas();
},
createKnobCanvas: function() {
this.knobCanvas = document.createElement('canvas');
this.knobContext = this.knobCanvas.getContext('2d');
this.knobCanvas.style.position = "absolute";
this.knobCanvas.style.marginLeft = "0px";
this.knobCanvas.style.marginTop = "1px";
this.knobCanvas.style.zIndex = "1";
this.knobCanvas.style.cursor = "crosshair";
...
},
...
};
initializeConstants()
方法为所有滑块常量创建变量,包括未指定值时initializeStrokeAndFillStyles()
使用的笔触和填充样式的默认值。
清单5中最有趣的方法是initializeKnob()
,该方法在调用createKnobCanvas()
为滑块的旋钮创建单独的画布之前设置一些变量。 createKnobCanvas()
创建一个canvas元素并设置其style属性,以便该画布位于其封闭的画布的上方和左上方。
现在,您已经了解了如何初始化滑轨和旋钮的画布,让我们看一下如何使用它们绘制滑块。
绘制滑块
清单6中显示了滑块组件的draw()
和erase()
方法。
清单6.绘制和擦除滑块
COREHTML5.Slider.prototype = {
...
erase: function() {
this.railContext.clearRect(
this.left - this.knobRadius, 0 - this.knobRadius,
this.railCanvas.width + 4*this.knobRadius,
this.railCanvas.height + 3*this.knobRadius);
this.knobContext.clearRect(0, 0, this.knobCanvas.width,
this.knobCanvas.height);
},
draw: function (percent) {
this.drawRail();
this.drawKnob(percent ? percent : this.knobPercent );
},
};
erase()
方法将擦除两个滑块画布,一个用于导轨,另一个用于旋钮。 相反, draw()
方法绘制轨道和旋钮。 您可以将旋钮percent
(滑块的值)传递给draw()
方法,也可以不带任何参数调用它,在这种情况下,它将使用滑块的现有值。
绘制导轨
在清单7中,滑块组件分两步绘制轨道。
清单7.绘制导轨
COREHTML5.Slider.prototype = {
...
drawRail: function () {
var radius = (this.bottom - this.top) / 2;
this.railContext.save();
this.railContext.shadowColor = this.SHADOW_COLOR;
this.railContext.shadowOffsetX = this.SHADOW_OFFSET_X;
this.railContext.shadowOffsetY = this.SHADOW_OFFSET_Y;
this.railContext.shadowBlur = this.SHADOW_BLUR;
this.railContext.beginPath();
this.railContext.moveTo(this.left + radius, this.top);
this.railContext.arcTo(this.right, this.top, this.right, this.bottom, radius);
this.railContext.arcTo(this.right, this.bottom, this.left, this.bottom, radius);
this.railContext.arcTo(this.left, this.bottom, this.left, this.top, radius);
this.railContext.arcTo(this.left, this.top, this.right, this.top, radius);
this.railContext.closePath();
this.railContext.fillStyle = this.fillStyle;
this.railContext.fill();
this.railContext.shadowColor = undefined;
this.railContext.restore();
this.overlayRailGradient();
this.railContext.restore();
},
overlayRailGradient: function () {
var gradient =
this.railContext.createLinearGradient(this.left, this.top,
this.left, this.bottom);
gradient.addColorStop(0, 'rgba(255,255,255,0.4)');
gradient.addColorStop(0.2, 'rgba(255,255,255,0.6)');
gradient.addColorStop(0.25, 'rgba(255,255,255,0.7)');
gradient.addColorStop(0.3, 'rgba(255,255,255,0.9)');
gradient.addColorStop(0.40, 'rgba(255,255,255,0.7)');
gradient.addColorStop(0.45, 'rgba(255,255,255,0.6)');
gradient.addColorStop(0.60, 'rgba(255,255,255,0.4)');
gradient.addColorStop(1, 'rgba(255,255,255,0.1)');
this.railContext.fillStyle = gradient;
this.railContext.fill();
this.railContext.lineWidth = 0.4;
this.railContext.strokeStyle = this.strokeStyle;
this.railContext.stroke();
},
...
};
首先,滑块的drawRail()
方法用纯色填充滑轨,如图4所示。
图4.滑块底座
接下来, drawRail()
覆盖白色渐变,如图5所示。
图5.滑块叠加
结果如图6所示,使轨道具有一定深度,并使其看起来好像从顶部照在上面。
图6.滑块组合
滑块的overlayRailGradient()
方法使用HTML5画布的createLinearGradient()
方法来创建梯度。 随后, overlayRailGradient()
在沿渐变线的点处添加色标。 每个色标均为纯白色,具有不同程度的不透明度。 最后, overlayRailGradient()
使用渐变填充滑块并overlayRailGradient()
其轮廓。
绘制旋钮
滑块在单独的画布上绘制的旋钮如图7所示。
图7.旋钮画布
回想一下清单5 ,滑块使用对document.createElement()
的调用来创建旋钮的画布。 如清单8所示,滑块的fillKnob()
和strokeKnob()
方法在该画布中绘制。
清单8.绘制旋钮
COREHTML5.Slider.prototype = {
...
drawKnob: function (percent) {
if (percent < 0) percent = 0;
if (percent > 1) percent = 1;
this.knobPercent = percent;
this.moveKnob(this.knobPercentToPosition(percent));
this.fillKnob();
this.strokeKnob();
},
fillKnob: function () {
this.knobContext.shadowColor = this.KNOB_SHADOW_COLOR;
this.knobContext.shadowOffsetX = this.KNOB_SHADOW_OFFSET_X;
this.knobContext.shadowOffsetY = this.KNOB_SHADOW_OFFSET_Y;
this.knobContext.shadowBlur = this.KNOB_SHADOW_BLUR;
this.knobContext.beginPath();
this.knobContext.arc(this.knobCanvas.width/2, this.knobCanvas.height/2,
this.knobCanvas.width/2-2, 0, Math.PI*2, false);
this.knobContext.clip();
this.knobContext.fillStyle = this.KNOB_FILL_STYLE;
this.knobContext.fill();
},
strokeKnob: function () {
this.knobContext.lineWidth = 1;
this.knobContext.strokeStyle = this.KNOB_STROKE_STYLE;
this.knobContext.stroke();
},
...
};
drawKnob()
方法采用一个percent
,它表示滑块的位置。 该方法设置滑块的值并相应地移动旋钮,随后填充并抚摸旋钮。
fillKnob()
方法用半透明的黄色填充旋钮,该旋钮使下方的导轨可以fillKnob()
并看起来好像旋钮已被点亮。 strokeKnob()
方法用纯色描边旋钮的轮廓。
拖动旋钮
清单9显示了用于拖动旋钮的滑块代码。
清单9.拖动旋钮
COREHTML5.Slider.prototype = {
...
addMouseListeners: function () {
var slider = this; // Let event handlers access this object
this.knobCanvas.addEventListener('mousedown', function(e) {
slider.draggingKnob = true;
e.preventDefault();
};
this.knobCanvas.addEventListener('mousemove', function(e) {
var mouse = null,
percent = null;
e.preventDefault();
if (slider.draggingKnob) {
mouse = slider.windowToCanvas(e.clientX, e.clientY);
percent = slider.knobPositionToPercent(mouse.x);
if (percent >= 0 && percent <= 1.0) {
slider.erase();
slider.draw(percent);
}
}
}, false);
this.knobCanvas.addEventListener('mouseup', function(e) {
e.preventDefault();
slider.draggingKnob = false;
};
},
windowToCanvas: function(x, y) {
var bbox = this.railCanvas.getBoundingClientRect();
return {
x: x - bbox.left * (this.railCanvas.width / bbox.width),
y: y - bbox.top * (this.railCanvas.height / bbox.height)
};
},
knobPositionToPercent: function(position) {
var railWidth = this.right - this.left - 2*this.knobRadius;
percent = (position - this.left - this.knobRadius) / railWidth;
percent = percent > 1.0 ? 1.0 : percent;
percent = percent < 0 ? 0 : percent;
return percent;
},
...
};
回想一下清单4 ,滑块的构造函数调用清单9所示的addMouseListeners()
方法。 该方法将鼠标下移,鼠标移动和鼠标上移事件处理程序添加到控制旋钮画布拖动的旋钮画布。 两种帮助程序方法( windowToCanvas()
和knobPositionToPercent()
使这些事件处理程序易于理解。
下次
在本文中,您已经了解了如何实现即席HTML5组件。 本系列的下一篇文章将继续探索滑块组件,向您展示如何支持更改侦听器,如何以编程方式使用CSS过渡为滑块的旋钮设置动画以及如何将滑块组件添加到任何DOM树中。 下次见。
翻译自: https://www.ibm.com/developerworks/web/library/wa-html5components1/index.html
qq临时会话组件