winform 复合组件_HTML5复合组件,第1部分

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
Google Chrome内置的开发者工具随附JavaScript调试器的屏幕截图

图1所示的Chrome调试器中,包含JavaScript代码的面板出现在显示的画布组件下方。

现在您已经有了一个不错JavaScript调试器,您只需要一个具有HTML5功能的浏览器即可。 较流行的浏览器的大多数最新版本都很好地支持HTML5。 (Microsoft在即将发布的Internet Explorer 9中似乎具有良好HTML5支持。)

使用HTML5画布

HTML5画布是成熟的2D绘图表面,其功能足以支持诸如植物大战僵尸和雷神之锤II之类的游戏 。 我对HTML5画布的使用(如图2所示)可能不那么引人注目,但足以满足指导目的:

图2.一个简单HTML5 canvas示例
浏览器的屏幕快照,其中显示了使用使用HTML5画布的绘画应用程序创建的蓝色卡通脸

我已经在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复合组件
运行中的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。 页面作者可以使用画布组件的可选libraryscript属性来指定画布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是通过画布组件的libraryscript属性指定的。 请注意, libraryscript属性分别默认为html5canvasDefault.js 。 这就满足了第三个要求(自动导入画布JavaScript)。

最后,画布组件调用一个名为init()JavaScript方法,并传递画布的ID,笔颜色和线宽。 init()方法获取并初始化画布的上下文。 注意,我说的是method而不是function ,因为init()方法属于一个对象。 该对象的名称是从canvas组件的script属性派生的。 例如,对于清单3中的笑脸画布,我指定了scriptsmiley.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/java/library/j-jsf2fu-1010/index.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值