react复合组件
HTML5显然是软件开发中的下一件大事。 HTML5最初被称为Web应用程序,最终将桌面应用程序的功能(包括拖放,画布,视频和音频等功能)带给浏览器。 HTML5是技术(特别是规范)的集合,这些技术形成了功能强大的API,涵盖了HTML,JavaScript和级联样式表(CSS)。 以下是HTML5的亮点:
- 帆布
- 拖放
- 地理位置*
- 内联编辑
- 网络工作者*
- 网络存储*
- 讯息传递
- 离线应用
- 视频和音频*
- 网络插座*
注意前瞻性功能,例如地理位置和离线应用程序。 (功能我用星号标记不是HTML5规范的技术部分,但这个词HTML5用于口语涵盖所有我已经列出的。请参阅相关主题以获取更多信息。)
在某些方面,HTML5是下一个Java。 在1990年代后期,Java语言变得非常流行,这在很大程度上要归功于它的一次写入,可在任何地方运行的功能,使开发人员不必在Windows®,Mac或Linux®中进行选择(或移植)。 HTML5允许您编写一次,并在任何(现代)浏览器中运行 ,因此您不必在iOS,Android和Chrome中进行选择。
进入Java技术
HTML5可能是下一个Java,但不会替代它。 Java技术为服务器端编程提供了丰富的生态系统。 而且,JSF最初是基于HTML的,它使您可以像迄今为止使用JSFHTML4一样轻松地使用HTML5。 除了HTML5之外,您还可以获得所有强大的JSF功能,例如facelets模板,复合组件和内置的Ajax。
在本文中,您将学习如何使用JSF2创建HTML5复合组件。 在下一篇JSF 2 fu文章中,我将向您展示如何创建HTML5组件库。
HTML5入门
实际上,使用HTML5涉及JavaScript比HTML多得多。 这意味着您需要一个好JavaScript调试器。 我建议使用Google Chrome内置的开发人员工具随附的工具(请参阅参考资料 ),如图1所示:
图1.使用Chrome Developer Tools调试JavaScript
在图1所示的Chrome调试器中,包含JavaScript代码的面板出现在显示的画布组件下方。
现在您已经有了一个不错JavaScript调试器,您只需要一个具有HTML5功能的浏览器即可。 较流行的浏览器的大多数最新版本都很好地支持HTML5。 (Microsoft在即将发布的Internet Explorer 9中似乎具有良好HTML5支持。)
使用HTML5画布
HTML5画布是成熟的2D绘图表面,其功能足以支持诸如植物大战僵尸和雷神之锤II之类的游戏 。 我对HTML5画布的使用(如图2所示)可能不那么引人注目,但足以满足指导目的:
图2.一个简单HTML5 canvas示例
我已经在HTML5画布中添加了一些JavaScript,以实现图2所示的简单绘画应用程序。 移动鼠标时,画布左上角的读数将显示鼠标坐标。 在画布上拖动鼠标时,将使用蓝色画笔进行绘制。
图2中显示的应用程序是一个JSF应用程序。 图3显示了其目录结构:
图3. canvas示例的目录结构
该应用程序的单独方面在web / WEB-INF / index.xhtml中定义,而该应用程序JavaScript在web / resources / application / paintingCanvas.js中。 清单1显示了index.xhtml:
清单1.使用<canvas>
标记(WEB-INF / index.xhtml)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>#{msgs.windowTitle}</title>
</h:head>
<h:body style="background: #fefeef">
<h:outputScript library="application" name="paintingCanvas.js"
target="head" />
<h3>#{msgs.heading}</h3>
<canvas width="400px" height="400px" id="paintingCanvas">
Canvas not supported.
</canvas>
</h:body>
</html>
清单1中的index.xhtml文件被称为HTML5 多语言文档 (请参阅参考资料 ),因为它具有HTML5 doctype / namespace和格式良好的XHTML语法—正是我所设计的facelets和HTML5所需要的。
我使用<h:outputScript>
标记导入相应JavaScript。 最后,我深入探讨并使用HTML5 canvas元素。 如果浏览器不理解<canvas>
标记,它将显示不支持Canvas的消息。 <canvas>
标签没有用。 所有有趣的代码都在相应JavaScript中,如清单2所示:
清单2.绘画画布JavaScript(resources / application / paintingCanvas.js)
window.addEventListener("load", function() {
var canvas, context, painting;
function init() {
canvas = document.getElementById("paintingCanvas");
if (canvas == null) return;
context = canvas.getContext("2d");
if (context == null) return;
painting = false;
context.strokeStyle = "#00f";
context.lineWidth = 3;
context.font = "15px Helvetica";
}
init();
canvas.addEventListener("mousedown", function(ev) {
painting = true;
context.beginPath();
context.moveTo(ev.offsetX, ev.offsetY);
}, false);
canvas.addEventListener("mousemove", function(ev) {
updateReadout(ev.offsetX, ev.offsetY);
if (painting) {
paint(ev.offsetX, ev.offsetY);
}
function updateReadout(x, y) {
context.clearRect(0, 0, 100, 20);
context.fillText("x: " + x + ", y: " + y, 5, 15);
}
function paint(x, y) {
context.lineTo(ev.offsetX, ev.offsetY);
context.stroke();
}
}, false);
canvas.addEventListener("mouseup", function() {
painting = false;
context.closePath();
}, false);
}, false);
清单2通过鼠标光标读数实现了简单绘制, 如图2所示。 页面加载时,我使用document.getElementById()
获得了对画布的引用。 从画布上,可以得到对画布上下文的引用。 我在随后的事件处理程序中使用该上下文,该事件处理程序是使用JavaScript闭包实现的,或者是Java开发人员将其称为匿名内部类的实现。
如果您使用了Abstract Window Toolkit(AWT),则画布的上下文将立即让人联想到AWT的图形上下文。 毕竟,只有两种方法可以在二维上绘制形状,图像和文本。 在清单2中 ,我使用蓝色的笔触样式初始化上下文,并设置线宽和字体。 从那时起,仅当鼠标分别向下,拖动和向上移动时,才需要移动,抚摸,重复。
现在您已经掌握了HTML5画布的基础知识,我将向您展示如何创建JSF 2 HTML5复合组件。
JSF 2 HTML5 canvas组件
接下来,我将实现一个使用HTML5画布的JSF 2复合组件。 我需要复合组件来满足以下要求:
- 具有可配置的(通过标签属性)宽度,高度,笔颜色,线宽和CSS样式
- 将component标签的主体用作画布不受支持的消息
- 自动包含画布JavaScript
- 在单个页面中支持多个画布组件
图4显示了使用canvas复合组件的应用程序:
图4.运行中的canvas复合组件
图4所示的应用程序具有三个画布组件,每个组件具有不同的配置。 从左开始,前两个是绘画画布,类似于图2所示。 最右边的画布只是画一个笑脸。
清单3显示了图4所示页面的标记:
清单3.使用画布组合组件(WEB-INF / index.xhtml)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:h5="http://java.sun.com/jsf/composite/html5">
<h:head>
<meta charset="UTF-8" />
<title>#{msgs.windowTitle}</title>
</h:head>
<h:body style="background: #fefeef">
<h3>#{msgs.heading}</h3>
<h5:canvas id="paintingCanvas" width="300px" height="300px"
penColor="#7F7" lineWidth="7">
#{msgs.canvasUnsupported}
</h5:canvas>
<h5:canvas id="secondPaintingCanvas" width="300px" height="300px"
style="border: thick solid red">
#{msgs.canvasUnsupported}
</h5:canvas>
<h5:canvas id="smileyCanvas" library="application" script="smiley.js"
width="300px" height="300px"
style="border: thin solid red">
#{msgs.canvasUnsupported}
</h5:canvas>
</h:body>
</html>
在清单3中 ,canvas组件导入了适当JavaScript —与清单1不同,在清单1中 ,我手工使用HTML5,并且必须显式导入关联JavaScript。 页面作者可以使用画布组件的可选library
和script
属性来指定画布JavaScript,也可以依赖默认JavaScript。 在清单3中 ,我为笑脸画布使用script
属性。 我在示例中最左边的两个画布使用了默认JavaScript(resources / html5 / canvasDefault.js,它实现了绘画画布)。
清单4显示了canvas复合组件的实现:
清单4. canvas复合组件(resources / html5 / canvas.xhtml)
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface>
<composite:attribute name="id"/>
<composite:attribute name="width"/>
<composite:attribute name="height"/>
<composite:attribute name="library" default="html5"/>
<composite:attribute name="script" default="canvasDefault.js"/>
<composite:attribute name="style" default="border: thin solid blue"/>
<composite:attribute name="penColor" default="#7777FF"/>
<composite:attribute name="lineWidth" default="2"/>
</composite:interface>
<composite:implementation>
<canvas id="#{cc.id}"
width="#{cc.attrs.width}"
height="#{cc.attrs.height}"
style="#{cc.attrs.style}">
<composite:insertChildren/>
</canvas>
<h:outputScript library="#{cc.attrs.library}"
name="#{cc.attrs.script}"/>
<script>
#{cc.attrs.script}.init('#{cc.id}',
'#{cc.attrs.penColor}',
'#{cc.attrs.lineWidth}')
</script>
</composite:implementation>
</html>
在清单4中 ,我为canvas复合组件声明了八个属性,其中五个具有默认值。 组件的实现包含一个HTML5画布,其ID,宽度,高度和样式是从组件的相关属性配置的。 这就满足了我对画布组件的第一个要求(可配置属性)。
canvas复合组件将其子级 (即<h5:canvas>
标记正文中的所有内容)插入HTML5 canvas标记( <canvas>
)。 这意味着,如果浏览器不支持HTML5画布,则将显示标签正文中的所有文本。 这就满足了第二个要求(使用画布不受支持的消息的组件标签的主体)。
画布组件包含一个<h:outputScript>
标记,该标记导入画布JavaScript,该JavaScript是通过画布组件的library
和script
属性指定的。 请注意, library
和script
属性分别默认为html5
和canvasDefault.js
。 这就满足了第三个要求(自动导入画布JavaScript)。
最后,画布组件调用一个名为init()
JavaScript方法,并传递画布的ID,笔颜色和线宽。 init()
方法获取并初始化画布的上下文。 注意,我说的是method而不是function ,因为init()
方法属于一个对象。 该对象的名称是从canvas组件的script
属性派生的。 例如,对于清单3中的笑脸画布,我指定了script
值smiley.js
,因此笑脸画布组件将调用smiley.js.init()
-名为js
的对象的init()
方法,该对象包含在对象名为smiley
。 如果未明确指定script
值,则默认为canvasDefault.js
,因此JavaScript方法为canvasDefault.js.init()
。 调用这些方法而不是全局函数可以满足我的第四个要求:在单个页面中支持多个画布。
清单5显示了canvas组件的默认JavaScript:
清单5.默认的画布JavaScript(resources / html5 / canvasDefault.js)
if (!canvasDefault) var canvasDefault = {}
if (!canvasDefault.js) {
canvasDefault.js = {
init : function(canvasId, penColor, lineWidth) {
var canvas, context, painting;
canvas = document.getElementById(canvasId);
if (canvas == null) {
alert("Canvas " + canvasId + " not found")
}
context = canvas.getContext("2d")
if (context == null)
return;
painting = false;
context.strokeStyle = penColor
context.lineWidth = lineWidth
context.font = "15px Helvetica"
canvas.addEventListener("mousedown", function(ev) {
painting = true
context.beginPath()
context.moveTo(ev.offsetX, ev.offsetY)
}, false)
canvas.addEventListener("mousemove", function(ev) {
updateReadout(ev.offsetX, ev.offsetY)
if (painting) {
paint(ev.offsetX, ev.offsetY)
}
function updateReadout(x, y) {
context.clearRect(0, 0, 100, 20)
context.fillText("x: " + x + ", y: " + y, 5, 15)
}
function paint(x, y) {
context.lineTo(ev.offsetX, ev.offsetY)
context.stroke()
}
}, false)
canvas.addEventListener("mouseup", function() {
painting = false
context.closePath()
}, false)
}
}
}
在清单5中 ,我创建了一个名为canvasDefault
的对象,其中包含一个名为js
的对象,该对象包含一个init()
方法。 我这样做是为了给init()
方法命名空间 ,因此它不会被另一个全局init()
函数覆盖。 这样,我可以在单个页面中拥有多个画布,所有画布都有自己的init()
函数实现。
清单6显示了笑脸画布JavaScript:
清单6.笑脸画布JavaScript(resources / application / smiley.js)
if (!smiley) var smiley = {}
if (!smiley.js) {
smiley.js = {
init : function(canvasId, penColor, lineWidth) {
var canvas, context
canvas = document.getElementById(canvasId);
if (canvas == null) {
alert("Canvas " + canvasId + " not found")
}
context = canvas.getContext("2d");
if (context == null)
return
// smiley face code originally downloaded
// from thinkvitamin.com
// Create the face
context.strokeStyle = "#000000";
context.fillStyle = "#AAAAFF";
context.beginPath();
context.arc(100,100,50,0,Math.PI*2,true);
context.closePath();
context.stroke();
context.fill();
// eyes
context.strokeStyle = "#000000";
context.fillStyle = "#FFFFFF";
context.beginPath();
context.arc(80,80,8,0,Math.PI*2,true);
context.closePath();
context.stroke();
context.fill();
context.fillStyle = "#0000FF";
context.beginPath();
context.arc(80,80,5,0,Math.PI*2,true);
context.closePath();
context.fill();
context.strokeStyle = "#000000";
context.fillStyle = "#FFFFFF";
context.beginPath();
context.arc(120,80,8,0,Math.PI*2,true);
context.closePath();
context.stroke();
context.fill();
context.fillStyle = "#0000FF";
context.beginPath();
context.arc(120,80,5,0,Math.PI*2,true);
context.closePath();
context.fill();
// nose
context.fillStyle = "#000000";
context.beginPath();
context.moveTo(93,100);
context.lineTo(100,93);
context.lineTo(107,100);
context.closePath();
context.fill();
// smile
context.strokeStyle = "#000000";
context.beginPath();
context.moveTo(70,110);
context.quadraticCurveTo(100,150,130,110);
context.closePath();
context.stroke();
}
}
}
清单6遵循与清单5中相同的命名间隔约定。 其他类型的画布的后续JavaScript必须遵循相同的约定。
结论
在本文中,我向您介绍了HTML5,并向您展示了如何实现JSF 2 HTML5 canvas复合组件,该组件使JSF开发人员和页面作者可以轻松使用HTML5 canvas。 我向您展示了如何将从JSF表达式语言获得的信息传递给与复合组件关联JavaScript,以及如何对JavaScript函数进行命名空间,以使名称相同的函数不会相互干扰。 在下一期JSF 2 fu中 ,我将向您展示如何实现另一个HTML5组件,以及如何将多个HTML5组件放入可重用的库中,然后可在JAR文件中分发给其他开发人员。
翻译自: https://www.ibm.com/developerworks/web/library/j-jsf2fu-1010/index.html
react复合组件