HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

使用纯HTML5编写一款网页上的时钟的代码分享

你需要知道的:
canvas标签只是图形容器,您必须使用脚本来绘制图形。默认大小:宽300px,高150px;
getContext() 方法可返回一个对象,该对象提供了用于在画布上绘图的方法和属性。——获取上下文对象。
getContext("2d") 对象属性和方法,可用于在画布上绘制文本、线条、矩形、圆形等等。
fillRect(l,t,w,h):默认颜色是黑色 strokeRect(l,t,w,h):带边框的方块。默认一像素黑色边框
setInterval() 方法可按照指定的周期(以毫秒计)来调用函数或计算表达式。
beginPath():定义开始绘制路径, 它把当前的点设置为 (0,0)。 当一个画布的环境第一次创建,beginPath()
方法会被显式地调用。
closePath():结束绘制路径(将起点与终点进行连接)

绘制圆形:
arc( x,y,半径,起始弧度,结束弧度,旋转方向)
x,y:起始位置
弧度与角度的关系:弧度=角度*Math.PI/180
旋转方向:顺时针(默认:false,逆时针:true)
代码:
XML/HTML Code复制内容到剪贴板
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title></title>
<script>
window.onload = function(){
var oC = document.getElementById('ch1');
var oGC = oC.getContext('2d');

                    function drawClock(){     
                            var x = 200;   //指定坐标     
                            var y = 200;     
                            var r = 150;  //指定钟表半径     

                            oGC.clearRect(0,0,oC.width,oC.height);//清空画布     

                            var oDate = new Date();      //创建日期对象     
                            var oHours = oDate.getHours();//获取时间     
                            var oMin = oDate.getMinutes();     
                            var oSen = oDate.getSeconds();     

                            var oHoursValue = (-90 + oHours*30 + oMin/2)*Math.PI/180; //设置时针的值     
                            var oMinValue = (-90 + oMin*6)*Math.PI/180;     
                            var oSenValue = (-90 + oSen*6)*Math.PI/180;     

                            oGC.beginPath();//开始     

                            for(var i=0;i<60;i++){         //i为60,代表着时钟的60个小刻度     
                                    oGC.moveTo(x,y);     
                                    oGC.arc(x,y,r,6*i*Math.PI/180,6*(i+1)*Math.PI/180,false); //循环从6度到12度     
                            }     
                            oGC.closePath();     
                            oGC.stroke();     

                            oGC.fillStyle ='white'; //覆盖住小刻度的黑色线     
                            oGC.beginPath();     
                            oGC.moveTo(x,y);     
                            oGC.arc(x,y,r*19/20,0,360*(i+1)*Math.PI/180,false);     

                            oGC.closePath();//结束     
                            oGC.fill();     

                            oGC.lineWidth = 3; //设置时钟圆盘大刻度的粗细值     
                            oGC.beginPath();  //开始画大的时钟刻度     

                            for(i=0;i<12;i++){              //i为12,代表着时钟刻度的12大格     
                                    oGC.moveTo(x,y);     
                                    oGC.arc(x,y,r,30*i*Math.PI/180,30*(i+1)*Math.PI/180,false); // 间隔为30度,弧度=角度*Math.PI/180     
                            }     
                            oGC.closePath();     
                            oGC.stroke();     

                            oGC.fillStyle ='white'; //覆盖住大刻度的黑色线     
                            oGC.beginPath();     
                            oGC.moveTo(x,y);     
                            oGC.arc(x,y,r*18/20,360*(i+1)*Math.PI/180,false);     

                            oGC.closePath();     
                            oGC.fill();//表盘完成      

                            oGC.lineWidth = 5;//设置时针宽度     
                            oGC.beginPath();//开始绘制时针     
                            oGC.moveTo(x,y);     

                            oGC.arc(x,y,r*10/20,oHoursValue,oHoursValue,false);//设置时针大小和弧度     
                            oGC.closePath();     
                            oGC.stroke();     

                            oGC.lineWidth = 3;//设置分针宽度     
                            oGC.beginPath();//开始绘制分针     
                            oGC.moveTo(x,y);     

                            oGC.arc(x,y,r*14/20,oMinValue,oMinValue,false);//设置分针大小和弧度     
                            oGC.closePath();     
                            oGC.stroke();     

                            oGC.lineWidth = 1;//设置秒针宽度     
                            oGC.beginPath();//开始绘制秒针     
                            oGC.moveTo(x,y);     

                            oGC.arc(x,y,r*19/20,oSenValue,oSenValue,false);//设置秒针大小和弧度     
                            oGC.closePath();     
                            oGC.stroke();     
                    }     
                    setInterval(drawClock,1000);//设置定时器,让时钟运转起来     
                            drawClock();     
            };     
    </script>    

</head>
<body>
<canvas id = "ch1" width = "400px" height = "400px"></canvas>
</body>
</html>
点击下方result查看演示:www.szyoudun.com

继续阅读 »

你需要知道的:
canvas标签只是图形容器,您必须使用脚本来绘制图形。默认大小:宽300px,高150px;
getContext() 方法可返回一个对象,该对象提供了用于在画布上绘图的方法和属性。——获取上下文对象。
getContext("2d") 对象属性和方法,可用于在画布上绘制文本、线条、矩形、圆形等等。
fillRect(l,t,w,h):默认颜色是黑色 strokeRect(l,t,w,h):带边框的方块。默认一像素黑色边框
setInterval() 方法可按照指定的周期(以毫秒计)来调用函数或计算表达式。
beginPath():定义开始绘制路径, 它把当前的点设置为 (0,0)。 当一个画布的环境第一次创建,beginPath()
方法会被显式地调用。
closePath():结束绘制路径(将起点与终点进行连接)

绘制圆形:
arc( x,y,半径,起始弧度,结束弧度,旋转方向)
x,y:起始位置
弧度与角度的关系:弧度=角度*Math.PI/180
旋转方向:顺时针(默认:false,逆时针:true)
代码:
XML/HTML Code复制内容到剪贴板
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title></title>
<script>
window.onload = function(){
var oC = document.getElementById('ch1');
var oGC = oC.getContext('2d');

                    function drawClock(){     
                            var x = 200;   //指定坐标     
                            var y = 200;     
                            var r = 150;  //指定钟表半径     

                            oGC.clearRect(0,0,oC.width,oC.height);//清空画布     

                            var oDate = new Date();      //创建日期对象     
                            var oHours = oDate.getHours();//获取时间     
                            var oMin = oDate.getMinutes();     
                            var oSen = oDate.getSeconds();     

                            var oHoursValue = (-90 + oHours*30 + oMin/2)*Math.PI/180; //设置时针的值     
                            var oMinValue = (-90 + oMin*6)*Math.PI/180;     
                            var oSenValue = (-90 + oSen*6)*Math.PI/180;     

                            oGC.beginPath();//开始     

                            for(var i=0;i<60;i++){         //i为60,代表着时钟的60个小刻度     
                                    oGC.moveTo(x,y);     
                                    oGC.arc(x,y,r,6*i*Math.PI/180,6*(i+1)*Math.PI/180,false); //循环从6度到12度     
                            }     
                            oGC.closePath();     
                            oGC.stroke();     

                            oGC.fillStyle ='white'; //覆盖住小刻度的黑色线     
                            oGC.beginPath();     
                            oGC.moveTo(x,y);     
                            oGC.arc(x,y,r*19/20,0,360*(i+1)*Math.PI/180,false);     

                            oGC.closePath();//结束     
                            oGC.fill();     

                            oGC.lineWidth = 3; //设置时钟圆盘大刻度的粗细值     
                            oGC.beginPath();  //开始画大的时钟刻度     

                            for(i=0;i<12;i++){              //i为12,代表着时钟刻度的12大格     
                                    oGC.moveTo(x,y);     
                                    oGC.arc(x,y,r,30*i*Math.PI/180,30*(i+1)*Math.PI/180,false); // 间隔为30度,弧度=角度*Math.PI/180     
                            }     
                            oGC.closePath();     
                            oGC.stroke();     

                            oGC.fillStyle ='white'; //覆盖住大刻度的黑色线     
                            oGC.beginPath();     
                            oGC.moveTo(x,y);     
                            oGC.arc(x,y,r*18/20,360*(i+1)*Math.PI/180,false);     

                            oGC.closePath();     
                            oGC.fill();//表盘完成      

                            oGC.lineWidth = 5;//设置时针宽度     
                            oGC.beginPath();//开始绘制时针     
                            oGC.moveTo(x,y);     

                            oGC.arc(x,y,r*10/20,oHoursValue,oHoursValue,false);//设置时针大小和弧度     
                            oGC.closePath();     
                            oGC.stroke();     

                            oGC.lineWidth = 3;//设置分针宽度     
                            oGC.beginPath();//开始绘制分针     
                            oGC.moveTo(x,y);     

                            oGC.arc(x,y,r*14/20,oMinValue,oMinValue,false);//设置分针大小和弧度     
                            oGC.closePath();     
                            oGC.stroke();     

                            oGC.lineWidth = 1;//设置秒针宽度     
                            oGC.beginPath();//开始绘制秒针     
                            oGC.moveTo(x,y);     

                            oGC.arc(x,y,r*19/20,oSenValue,oSenValue,false);//设置秒针大小和弧度     
                            oGC.closePath();     
                            oGC.stroke();     
                    }     
                    setInterval(drawClock,1000);//设置定时器,让时钟运转起来     
                            drawClock();     
            };     
    </script>    

</head>
<body>
<canvas id = "ch1" width = "400px" height = "400px"></canvas>
</body>
</html>
点击下方result查看演示:www.szyoudun.com

收起阅读 »

用HTML5.0制作网页的教程

根据你们询问的人,HTML 5不是迈向创造更语义化的网络的下一 个重要步伐,就是用一系列不完整的标签和标记大杂烩让网络陷入困境的灾难。
争论双方的问题在于,很少的站点在自然环境下使用HTML 5,所以现在所认识到的问题的理论解决方案仍然在很大程度上未经考验。
即便如此,我们不难发现下一代网络标记工具的好处和潜在的问题。
内容

  1. HTML 5有什么不同?
  2. 最终,一个任何人都可以记住的文档类型
  3. 最基本的语义结构
  4. <header>
  5. <nav>
  6. <section>
  7. <article>
  8. <aside>
  9. <footer>
  10. 把他们放在一起
  11. 为新元素编写样式
  12. 兼容老的浏览器
  13. 现在你可以使用HTML 5了,但你会用么?
    HTML 5有什么不同?
    首先,我们通过HTML 5表达什么?First off, what do we mean by HTML 5?理论上,我们表达所有的事——新的语义结构标签,例如canvas或者离线储存等API规范,以及新的内联语义标签。尽管如此,我们把实际的原因 (PS:浏览器支持问题)仅仅局限于结构标签。canvas,离线储存,本地视频或者地理定位API都很绝妙,然而他们还不能被所有浏览器一致的支持。
    “但是等等”你说,“大多数浏览器也都不支持新的结构元素!”这是真的,但他们中的绝大多数将 会很乐意去接受你想要创建的任何标签。甚至连IE6也可以处理新标签,尽管如果你想要使用CSS设置样式,你需要一点JavaScript的帮助。
    当你对新标签设置样式时,你需要记住一件事,那就是未知标签在大部分浏览器中没有默认样式。他 们同时被认为是行级元素。尽管如此,由于大部分HTML 5的新标签可以构造,我们将让他们拥有块级元素的行为。解决方法是确认你在CSS样式中包含了display:block;。
    为了帮助了解当今HTML 5的一些新玩意儿,我们现在就进入正题,开始使用一些新的结构元素。
    最终,一个任何人都可以记住的文档类型
    我们创建HTML 5文档第一件需要做的事情就是使用新的文档类型。现在,如果你还清楚的记得HTML 4或者XHTML 1.x的文档类型,你真是一个比我们更强的淘气鬼。每当我们新建一个页面,我们必须打开一个旧的文件,剪切并粘贴文档类型定义。
    这真是痛苦,也是为什么我们喜欢新的HTML 5文档类型。你准备好了么?他出现了:

不会太难记。简单并且容易理解。不区分大小写。
这个构想是停止HTML版本化,使向后兼容变得更容易。从长远看是否成功是另外的事情,但至少 他节省了你输入的平均时间。
最基本语义结构
我们已经将我们的页面定义为HTML 5文档。到现在为止,一切都还不错。现在,这些我们已经听说的新标签到底是什么?
在我们钻研新标签前,想想你一般网页的结构,大概像这样:

这对于展示用途很好,但如果我们想要知道一些关于页面元素包含什么的问题,这又怎么办呢?
上面的例子中,我们为我们所有的结构div添加了ID。这在有见识的设计师中是很平常的事。目 的有两个方面,首先,ID提供了可以能用于给页面的特殊段落应用样式的锚,其次,ID充当基本的伪语义结构。高明的解析器将会查看标签的ID属性,并尝试 去猜测他们的含义,但当每个站点的ID名称不同的时候很难。
这就是新结构标签到来的理由。
当认识到这些ID成为了惯例,HTML 5的缔造者们更进一步,使这些元素中的一部分变成他们独立的标签。这儿有一个HTML 5中生效的新标签的快速概要:
<header>
头部标签被设计作为关于一个章节或者一整张网页介绍信息的容器。<header> 标签可以包含从你位于大多数页面顶部的典型标志或者标语,到介绍一个章节的标语和开场白的任何东西。如果你还在你的页面里使用<div id=”header”>,那可以使用<header>替换
<nav>
nav元素非常明显,这是你的导航元素。当然什么被算为导航是有一些争议的,有一个基本的站点 导航,但一些情况下还可能有页面导航元素。HTML5的缔造者WHATWG最近在修改<nav>的解释,来表现怎样在同一个页面使用两次。
更多关于nav的信息以及关于HTML5的激烈争论,参见Jeffrey Zeldman关于nav元素的文章。
如果你还在使用<div id=”nav”>标签来包含你的页面导航,你可以使用简洁的<nav>标签来替换。
<section>
Section可能是新标签中最模糊的。根据HTML 5定义,一个章节是一个内容的主题集合,通常在header标签后,在footer标签前。但是如果 需要,section也可以相互嵌套。
在我们上面的例子里,被“content”标记的div就是一个变为section的很好的选 择。另外在那个section内,根据内容,我们可以增加section。
<article>
根绝WHATWG的注释,article元素可以包含“组成文档或站点独立部分的一段内容;例 如,杂志或者新闻的文章,或者博客条目。”
记住一个页面里可以有多个article标签;例如一个博客首页可能有最新的十篇文章,每一篇 包含在一个article标签内。Article也可以通过使用section标签分为多个段落,然而当你计划你的结构时需要稍微仔细一些,否则你容易引 起以一些难看的标签大杂烩结尾的情况。
<aside>
另一个相当模糊的标签,aside元素用于“与组成文档主要的正文流内容无关的”内容。那表示 一条附加的评论,内联的脚注,引用,注解或者像你看到的在这篇文章右边的更多典型的边栏内容。
根据WHATWG的注释,看起来<aside>可以用于所有的这些情况,尽管你边 栏里的引用和标签云有着很大的不同。
没人说HTML 5是完美的!
<footer>
Footer的用处也应该是很明显的,除了可能你不清楚可以拥有多个脚标。换句话说,除了通常 在大多数页面底部看到的主脚标,段落也可以含有脚标。
把他们放在一起
让我们使用新标签重新编写我们原来的例子:

非常清楚,并且容易理解,不是么?一些注释:我们可以在header标签中包含我们 的<h1>My Article</h1>标题。我没有这样做,因为h1元素已经表达了标题的含义,但如果你还有发布日期,署名或者其他数据在你文章的顶部, 为标签集添加一个header容器标签是一个很好的选择。
同时注意我们可以在article元素下添加第二个footer元素来包含诸如翻页导航,相关 文章或者其他内容。
为新标签编写样式
在大多数浏览器中,所有你需要做的就是像你通常做的那样,为在新标签上应用样式表,简单的定义 你的样式。但请确认为每一个元素添加了display:block;规则,无论如何,从现在开始。经过一段时间后,当浏览器开始标准化,并支持新元素后, 那就不必要了。
例如,让我们在我们的header里应用一些样式:

记住,你仍然可以给这些标签添加类和ID属性。所以,如果你想要单独为一个导航设置样式,你可 以轻易的给这个标签添加一个类或者样式,就象这样:

然后你可以应用一个样式:

兼容老的浏览器
但等一下,IE怎么办?这些样式完全不能在IE6下工作。如果你仍然需要支持像IE6一类遗产 般的浏览器,这儿有一个解决方法。IE6解析和显示这些标签还好,但你不能对他们设置任何CSS。解决方法是使用一点JavaScript。
我们只需要让IE去给我们使用createElement方法创造的的HTML 5标签设置样式。在HTML 5文件的head标签内添加这点东西。或者,你可以把他保存在一个特定的文件里,并用这种方法包含。

我知道你在想什么:“哥,你根本没有为那个脚本标签定义一个MIME类型。”
你根本不需要在HTML 5做这些事情。在HTML 5中,所有的脚本都被假定为type=”text/javascript”,所以没有必要让属性把你的脚本标签搞得乱七八糟(除非你的脚本并不是 JavaScript)。
这解决了IE的问题,但我们并没有摆脱困境。现在被证明Gecko渲染引擎有一个bug,导致 了Firefox2和Camino的一些版本在这些标签上卡住。
这儿有两个方法来处理这个bug,没有一个是理想的。更多的细节请查看HTML5doctor的这篇文章。这篇文章同时附有一个让所有HTML 5元素都生效的方便脚本。
记住,尽管Firefox 2的使用率很快在所有网站流量中降到了10%以下,但单纯忽略这个bug可能还是需要根据你网站的访问者来定。
现在你可以使用HTML 5了,但你会用么?
简短的回答是:我们会。
复杂一点的是:那要看站点了。如果你指责重新制作CNN主页,好吧,你可能会有一点抗拒,直到 浏览器的支持变好些。但如果你要给你的博客改版,我们支持你。这儿还有一些可以帮助你的Wordpress插 件,如果你正在使用这么流行的发布系统。这儿是一个Jeff Starr制作的HTML 5主题。
同时,试试以站点为主的HTML 5美术馆,并且查看源代码,看看他们做了什么。
尽管如此,如果IE的缺点阻止你了,这样考虑吧:就连Google也在他们的主要搜索页面上使 用了HTML 5的文档类型。就算如果你不使用所有新的结构标签,你可以至少利用一下简洁的脚本声明和下次我们会介绍的关于一些非结构的语义标签。www.szyoudun.com

继续阅读 »

根据你们询问的人,HTML 5不是迈向创造更语义化的网络的下一 个重要步伐,就是用一系列不完整的标签和标记大杂烩让网络陷入困境的灾难。
争论双方的问题在于,很少的站点在自然环境下使用HTML 5,所以现在所认识到的问题的理论解决方案仍然在很大程度上未经考验。
即便如此,我们不难发现下一代网络标记工具的好处和潜在的问题。
内容

  1. HTML 5有什么不同?
  2. 最终,一个任何人都可以记住的文档类型
  3. 最基本的语义结构
  4. <header>
  5. <nav>
  6. <section>
  7. <article>
  8. <aside>
  9. <footer>
  10. 把他们放在一起
  11. 为新元素编写样式
  12. 兼容老的浏览器
  13. 现在你可以使用HTML 5了,但你会用么?
    HTML 5有什么不同?
    首先,我们通过HTML 5表达什么?First off, what do we mean by HTML 5?理论上,我们表达所有的事——新的语义结构标签,例如canvas或者离线储存等API规范,以及新的内联语义标签。尽管如此,我们把实际的原因 (PS:浏览器支持问题)仅仅局限于结构标签。canvas,离线储存,本地视频或者地理定位API都很绝妙,然而他们还不能被所有浏览器一致的支持。
    “但是等等”你说,“大多数浏览器也都不支持新的结构元素!”这是真的,但他们中的绝大多数将 会很乐意去接受你想要创建的任何标签。甚至连IE6也可以处理新标签,尽管如果你想要使用CSS设置样式,你需要一点JavaScript的帮助。
    当你对新标签设置样式时,你需要记住一件事,那就是未知标签在大部分浏览器中没有默认样式。他 们同时被认为是行级元素。尽管如此,由于大部分HTML 5的新标签可以构造,我们将让他们拥有块级元素的行为。解决方法是确认你在CSS样式中包含了display:block;。
    为了帮助了解当今HTML 5的一些新玩意儿,我们现在就进入正题,开始使用一些新的结构元素。
    最终,一个任何人都可以记住的文档类型
    我们创建HTML 5文档第一件需要做的事情就是使用新的文档类型。现在,如果你还清楚的记得HTML 4或者XHTML 1.x的文档类型,你真是一个比我们更强的淘气鬼。每当我们新建一个页面,我们必须打开一个旧的文件,剪切并粘贴文档类型定义。
    这真是痛苦,也是为什么我们喜欢新的HTML 5文档类型。你准备好了么?他出现了:

不会太难记。简单并且容易理解。不区分大小写。
这个构想是停止HTML版本化,使向后兼容变得更容易。从长远看是否成功是另外的事情,但至少 他节省了你输入的平均时间。
最基本语义结构
我们已经将我们的页面定义为HTML 5文档。到现在为止,一切都还不错。现在,这些我们已经听说的新标签到底是什么?
在我们钻研新标签前,想想你一般网页的结构,大概像这样:

这对于展示用途很好,但如果我们想要知道一些关于页面元素包含什么的问题,这又怎么办呢?
上面的例子中,我们为我们所有的结构div添加了ID。这在有见识的设计师中是很平常的事。目 的有两个方面,首先,ID提供了可以能用于给页面的特殊段落应用样式的锚,其次,ID充当基本的伪语义结构。高明的解析器将会查看标签的ID属性,并尝试 去猜测他们的含义,但当每个站点的ID名称不同的时候很难。
这就是新结构标签到来的理由。
当认识到这些ID成为了惯例,HTML 5的缔造者们更进一步,使这些元素中的一部分变成他们独立的标签。这儿有一个HTML 5中生效的新标签的快速概要:
<header>
头部标签被设计作为关于一个章节或者一整张网页介绍信息的容器。<header> 标签可以包含从你位于大多数页面顶部的典型标志或者标语,到介绍一个章节的标语和开场白的任何东西。如果你还在你的页面里使用<div id=”header”>,那可以使用<header>替换
<nav>
nav元素非常明显,这是你的导航元素。当然什么被算为导航是有一些争议的,有一个基本的站点 导航,但一些情况下还可能有页面导航元素。HTML5的缔造者WHATWG最近在修改<nav>的解释,来表现怎样在同一个页面使用两次。
更多关于nav的信息以及关于HTML5的激烈争论,参见Jeffrey Zeldman关于nav元素的文章。
如果你还在使用<div id=”nav”>标签来包含你的页面导航,你可以使用简洁的<nav>标签来替换。
<section>
Section可能是新标签中最模糊的。根据HTML 5定义,一个章节是一个内容的主题集合,通常在header标签后,在footer标签前。但是如果 需要,section也可以相互嵌套。
在我们上面的例子里,被“content”标记的div就是一个变为section的很好的选 择。另外在那个section内,根据内容,我们可以增加section。
<article>
根绝WHATWG的注释,article元素可以包含“组成文档或站点独立部分的一段内容;例 如,杂志或者新闻的文章,或者博客条目。”
记住一个页面里可以有多个article标签;例如一个博客首页可能有最新的十篇文章,每一篇 包含在一个article标签内。Article也可以通过使用section标签分为多个段落,然而当你计划你的结构时需要稍微仔细一些,否则你容易引 起以一些难看的标签大杂烩结尾的情况。
<aside>
另一个相当模糊的标签,aside元素用于“与组成文档主要的正文流内容无关的”内容。那表示 一条附加的评论,内联的脚注,引用,注解或者像你看到的在这篇文章右边的更多典型的边栏内容。
根据WHATWG的注释,看起来<aside>可以用于所有的这些情况,尽管你边 栏里的引用和标签云有着很大的不同。
没人说HTML 5是完美的!
<footer>
Footer的用处也应该是很明显的,除了可能你不清楚可以拥有多个脚标。换句话说,除了通常 在大多数页面底部看到的主脚标,段落也可以含有脚标。
把他们放在一起
让我们使用新标签重新编写我们原来的例子:

非常清楚,并且容易理解,不是么?一些注释:我们可以在header标签中包含我们 的<h1>My Article</h1>标题。我没有这样做,因为h1元素已经表达了标题的含义,但如果你还有发布日期,署名或者其他数据在你文章的顶部, 为标签集添加一个header容器标签是一个很好的选择。
同时注意我们可以在article元素下添加第二个footer元素来包含诸如翻页导航,相关 文章或者其他内容。
为新标签编写样式
在大多数浏览器中,所有你需要做的就是像你通常做的那样,为在新标签上应用样式表,简单的定义 你的样式。但请确认为每一个元素添加了display:block;规则,无论如何,从现在开始。经过一段时间后,当浏览器开始标准化,并支持新元素后, 那就不必要了。
例如,让我们在我们的header里应用一些样式:

记住,你仍然可以给这些标签添加类和ID属性。所以,如果你想要单独为一个导航设置样式,你可 以轻易的给这个标签添加一个类或者样式,就象这样:

然后你可以应用一个样式:

兼容老的浏览器
但等一下,IE怎么办?这些样式完全不能在IE6下工作。如果你仍然需要支持像IE6一类遗产 般的浏览器,这儿有一个解决方法。IE6解析和显示这些标签还好,但你不能对他们设置任何CSS。解决方法是使用一点JavaScript。
我们只需要让IE去给我们使用createElement方法创造的的HTML 5标签设置样式。在HTML 5文件的head标签内添加这点东西。或者,你可以把他保存在一个特定的文件里,并用这种方法包含。

我知道你在想什么:“哥,你根本没有为那个脚本标签定义一个MIME类型。”
你根本不需要在HTML 5做这些事情。在HTML 5中,所有的脚本都被假定为type=”text/javascript”,所以没有必要让属性把你的脚本标签搞得乱七八糟(除非你的脚本并不是 JavaScript)。
这解决了IE的问题,但我们并没有摆脱困境。现在被证明Gecko渲染引擎有一个bug,导致 了Firefox2和Camino的一些版本在这些标签上卡住。
这儿有两个方法来处理这个bug,没有一个是理想的。更多的细节请查看HTML5doctor的这篇文章。这篇文章同时附有一个让所有HTML 5元素都生效的方便脚本。
记住,尽管Firefox 2的使用率很快在所有网站流量中降到了10%以下,但单纯忽略这个bug可能还是需要根据你网站的访问者来定。
现在你可以使用HTML 5了,但你会用么?
简短的回答是:我们会。
复杂一点的是:那要看站点了。如果你指责重新制作CNN主页,好吧,你可能会有一点抗拒,直到 浏览器的支持变好些。但如果你要给你的博客改版,我们支持你。这儿还有一些可以帮助你的Wordpress插 件,如果你正在使用这么流行的发布系统。这儿是一个Jeff Starr制作的HTML 5主题。
同时,试试以站点为主的HTML 5美术馆,并且查看源代码,看看他们做了什么。
尽管如此,如果IE的缺点阻止你了,这样考虑吧:就连Google也在他们的主要搜索页面上使 用了HTML 5的文档类型。就算如果你不使用所有新的结构标签,你可以至少利用一下简洁的脚本声明和下次我们会介绍的关于一些非结构的语义标签。www.szyoudun.com

收起阅读 »

基于HTML5的云虚拟主机配置界面

云计算大行其道,上期开源中国的原创会就有好几位云计算专家演讲,从底层的虚拟化技术,到上层的云存储和应用API,耳濡目染,也受益匪浅,算是大势所趋,回头看看Qunee组件,借这个趋势,可以在云计算可视化上发挥作用,最近就有客户用Qunee实现VPC配置图,并对交互做了定制,细节不便多说,本文主要介绍Qunee交互扩展方面的思路

云计算大行其道,上期开源中国的原创会就有好几位云计算专家演讲,从底层的虚拟化技术,到上层的云存储和应用API,耳濡目染,也受益匪浅,算是大势所趋,回头看看Qunee组件,借这个趋势,可以在云计算可视化上发挥作用,最近就有客户用Qunee实现VPC配置图,并对交互做了定制,细节不便多说,本文主要介绍Qunee交互扩展方面的思路

VPC配置图

参考示例 – visualops

云平台可视化这块儿国外做的不错,有不少开放的示例可以学习和参考,客户看中了这家云管理系统http://www.visualops.io/ ,这个系统使用的是SVG技术,体验了一下,效果不错,参照着实现

从界面上看,一个云节点上有多个子网,每个子网内有多台虚拟主机,然后每个云节点有统一的路由Router管理(或者网关Gateway)

visualops

界面呈现

参照原型实现,使用Q.Path描出子网和云节点范围,虚拟机则用普通节点,连线使用正交连线类型,此外还有些外观配置,比如虚线,背景颜色,网格等,设置style或者css即可

创建矩形元素(子网、云节点)

function createRect(name, left, top, width, height, fillColor) {
var rect = graph.createNode(name, left, top);
rect.type = "rectGroup";
rect.anchorPosition = Q.Position.LEFT_TOP;
rect.image = Q.Shapes.getRect(0, 0, 100, 100);
rect.size = {width: width, height: height};
rect.setStyle(Q.Styles.IMAGE_BACKGROUND_COLOR, fillColor || Q.toColor(0x88FFFFFF));
rect.setStyle(Q.Styles.SHAPE_STROKE, 0);
rect.setStyle(Q.Styles.BORDER, 1);
rect.setStyle(Q.Styles.BORDER_COLOR, "#32c02f");
rect.setStyle(Q.Styles.BORDER_LINE_DASH, [5, 6]);
rect.setStyle(Q.Styles.LABEL_PADDING, 5);
rect.setStyle(Q.Styles.LABEL_ANCHOR_POSITION, Q.Position.LEFT_TOP);
rect.setStyle(Q.Styles.LABEL_POSITION, Q.Position.LEFT_TOP);
rect.setBounds = function (bounds) {
this.x = bounds.x;
this.y = bounds.y;
this.size = new Q.Size(bounds.width, bounds.height);
}
rect.getBounds = function () {
return new Q.Rect(this.x, this.y, this.size.width, this.size.height);
}
rect.inBounds = function (x, y) {
return this.getBounds().contains(x, y);
}
rect.intersectsRect = function (rect) {
return rect.intersectsRect(this.x, this.y, this.size.width, this.size.height);
}
rect.containsRect = function (rect) {
return Q.containsRect(this.x, this.y, this.size.width, this.size.height, rect.x, rect.y, rect.width, rect.height);
}
rect.updateBoundsByChildren = function () {
var bounds = new Q.Rect();
Q.forEachChild(this, function (child) {
bounds.add(graph.getUIBounds(child));
});
this.location = new Q.Point(bounds.x, bounds.y - 15);
this.size = new Q.Size(Math.max(200, bounds.width), Math.max(70, bounds.height + 15));
}
return rect;
}
注意到对Rect增加了一些标定节点范围、计算自身大小的方法,后面交互时会用到

创建虚拟主机

function createPC(name, x, y, parent) {
var node = graph.createNode(name, x, y);
node.image = Q.Graphs.server;
node.parent = node.host = parent;
node.zIndex = 10;
return node;
}
创建连接关系

function createEdge(from, to) {
var name = from.name + "->" + to.name;
var edge = graph.createEdge(name, from, to);
edge.edgeType = Q.Consts.EDGE_TYPE_VERTICAL_HORIZONTAL;
edge.setStyle(Q.Styles.EDGE_FROM_OFFSET, {x: 20});
edge.setStyle(Q.Styles.EDGE_CORNER_RADIUS, 0);
return edge;
}
定制交互

呈现出来不难,业务的体现在于交互,客户需求要求虚拟主机不得超出云节点范围,超出时需要回撤操作,此外可以将一台虚拟机从一个子网移到另一个子网,另外还要控制路由的移动范围,限定在云节点的左边框上……

实现思路是通过交互监听,分别对移动(ELEMENT_MOVING),调整大小(RESIZING)等情况做处理,Qunee交互事件通常有三个状态:开始、进行时、结束,比如移动交互的三个过程:开始移动(ELEMENT_MOVE_START),移动中(ELEMENT_MOVING),完成移动(ELEMENT_MOVE_END),我们可以在开始时记录节点原始位置,结束时判断节点位置是否允许,如果不允许则作调整

var oldLocation = {};
graph.interactionDispatcher.addListener(function (evt) {
var data = evt.data;
if (evt.kind == Q.InteractionEvent.RESIZE_START) {
oldLocation[data.id] = {x: data.x, y: data.y, width: data.size.width, height: data.size.height};
}
if (evt.kind == Q.InteractionEvent.RESIZING) {
if (data == mainNode) {
label.updateLocation();
}
return;
}
if (evt.kind == Q.InteractionEvent.RESIZE_END) {
var oldBounds = oldLocation[data.id];
oldLocation = {};
if ((data != mainNode && isGroup(data) && groupIntersected(data)) || childrenOutParent(data)) {
data.setBounds(oldBounds);
}
if (data == mainNode) {
label.updateLocation();
}
return;
}
if (data.atLeft) {
if (evt.kind == Q.InteractionEvent.ELEMENT_MOVING) {
data.updateLocation();
}
return;
}

if (evt.kind == Q.InteractionEvent.ELEMENT_MOVE_START) {  
    oldLocation[data.id] = {x: data.x, y: data.y};  
    return;  
}  
if (evt.kind == Q.InteractionEvent.ELEMENT_MOVING) {  
    if (!isGroup(data)) {  
        var g = findGroup(evt.event);  
        highlight(g);  
    }  
    return;  
}  
if (evt.kind == Q.InteractionEvent.ELEMENT_MOVE_END) {  
    highlight();  
    if (isGroup(data)) {  
        if (groupIntersected(data)) {  
            var old = oldLocation[data.id];  
            graph.moveElements([data], old.x - data.x, old.y - data.y);  
        }  
        return;  
    }  
    var g = findGroup(evt.event);  
    if (g) {  
        data.parent = data.host = g;  
        fixNode(data);  
    } else {  
        data.location = oldLocation[data.id];  
    }  
    oldLocation = {};  
}  

})
最终效果

VPC配置图www.szyoudun.com

继续阅读 »

云计算大行其道,上期开源中国的原创会就有好几位云计算专家演讲,从底层的虚拟化技术,到上层的云存储和应用API,耳濡目染,也受益匪浅,算是大势所趋,回头看看Qunee组件,借这个趋势,可以在云计算可视化上发挥作用,最近就有客户用Qunee实现VPC配置图,并对交互做了定制,细节不便多说,本文主要介绍Qunee交互扩展方面的思路

云计算大行其道,上期开源中国的原创会就有好几位云计算专家演讲,从底层的虚拟化技术,到上层的云存储和应用API,耳濡目染,也受益匪浅,算是大势所趋,回头看看Qunee组件,借这个趋势,可以在云计算可视化上发挥作用,最近就有客户用Qunee实现VPC配置图,并对交互做了定制,细节不便多说,本文主要介绍Qunee交互扩展方面的思路

VPC配置图

参考示例 – visualops

云平台可视化这块儿国外做的不错,有不少开放的示例可以学习和参考,客户看中了这家云管理系统http://www.visualops.io/ ,这个系统使用的是SVG技术,体验了一下,效果不错,参照着实现

从界面上看,一个云节点上有多个子网,每个子网内有多台虚拟主机,然后每个云节点有统一的路由Router管理(或者网关Gateway)

visualops

界面呈现

参照原型实现,使用Q.Path描出子网和云节点范围,虚拟机则用普通节点,连线使用正交连线类型,此外还有些外观配置,比如虚线,背景颜色,网格等,设置style或者css即可

创建矩形元素(子网、云节点)

function createRect(name, left, top, width, height, fillColor) {
var rect = graph.createNode(name, left, top);
rect.type = "rectGroup";
rect.anchorPosition = Q.Position.LEFT_TOP;
rect.image = Q.Shapes.getRect(0, 0, 100, 100);
rect.size = {width: width, height: height};
rect.setStyle(Q.Styles.IMAGE_BACKGROUND_COLOR, fillColor || Q.toColor(0x88FFFFFF));
rect.setStyle(Q.Styles.SHAPE_STROKE, 0);
rect.setStyle(Q.Styles.BORDER, 1);
rect.setStyle(Q.Styles.BORDER_COLOR, "#32c02f");
rect.setStyle(Q.Styles.BORDER_LINE_DASH, [5, 6]);
rect.setStyle(Q.Styles.LABEL_PADDING, 5);
rect.setStyle(Q.Styles.LABEL_ANCHOR_POSITION, Q.Position.LEFT_TOP);
rect.setStyle(Q.Styles.LABEL_POSITION, Q.Position.LEFT_TOP);
rect.setBounds = function (bounds) {
this.x = bounds.x;
this.y = bounds.y;
this.size = new Q.Size(bounds.width, bounds.height);
}
rect.getBounds = function () {
return new Q.Rect(this.x, this.y, this.size.width, this.size.height);
}
rect.inBounds = function (x, y) {
return this.getBounds().contains(x, y);
}
rect.intersectsRect = function (rect) {
return rect.intersectsRect(this.x, this.y, this.size.width, this.size.height);
}
rect.containsRect = function (rect) {
return Q.containsRect(this.x, this.y, this.size.width, this.size.height, rect.x, rect.y, rect.width, rect.height);
}
rect.updateBoundsByChildren = function () {
var bounds = new Q.Rect();
Q.forEachChild(this, function (child) {
bounds.add(graph.getUIBounds(child));
});
this.location = new Q.Point(bounds.x, bounds.y - 15);
this.size = new Q.Size(Math.max(200, bounds.width), Math.max(70, bounds.height + 15));
}
return rect;
}
注意到对Rect增加了一些标定节点范围、计算自身大小的方法,后面交互时会用到

创建虚拟主机

function createPC(name, x, y, parent) {
var node = graph.createNode(name, x, y);
node.image = Q.Graphs.server;
node.parent = node.host = parent;
node.zIndex = 10;
return node;
}
创建连接关系

function createEdge(from, to) {
var name = from.name + "->" + to.name;
var edge = graph.createEdge(name, from, to);
edge.edgeType = Q.Consts.EDGE_TYPE_VERTICAL_HORIZONTAL;
edge.setStyle(Q.Styles.EDGE_FROM_OFFSET, {x: 20});
edge.setStyle(Q.Styles.EDGE_CORNER_RADIUS, 0);
return edge;
}
定制交互

呈现出来不难,业务的体现在于交互,客户需求要求虚拟主机不得超出云节点范围,超出时需要回撤操作,此外可以将一台虚拟机从一个子网移到另一个子网,另外还要控制路由的移动范围,限定在云节点的左边框上……

实现思路是通过交互监听,分别对移动(ELEMENT_MOVING),调整大小(RESIZING)等情况做处理,Qunee交互事件通常有三个状态:开始、进行时、结束,比如移动交互的三个过程:开始移动(ELEMENT_MOVE_START),移动中(ELEMENT_MOVING),完成移动(ELEMENT_MOVE_END),我们可以在开始时记录节点原始位置,结束时判断节点位置是否允许,如果不允许则作调整

var oldLocation = {};
graph.interactionDispatcher.addListener(function (evt) {
var data = evt.data;
if (evt.kind == Q.InteractionEvent.RESIZE_START) {
oldLocation[data.id] = {x: data.x, y: data.y, width: data.size.width, height: data.size.height};
}
if (evt.kind == Q.InteractionEvent.RESIZING) {
if (data == mainNode) {
label.updateLocation();
}
return;
}
if (evt.kind == Q.InteractionEvent.RESIZE_END) {
var oldBounds = oldLocation[data.id];
oldLocation = {};
if ((data != mainNode && isGroup(data) && groupIntersected(data)) || childrenOutParent(data)) {
data.setBounds(oldBounds);
}
if (data == mainNode) {
label.updateLocation();
}
return;
}
if (data.atLeft) {
if (evt.kind == Q.InteractionEvent.ELEMENT_MOVING) {
data.updateLocation();
}
return;
}

if (evt.kind == Q.InteractionEvent.ELEMENT_MOVE_START) {  
    oldLocation[data.id] = {x: data.x, y: data.y};  
    return;  
}  
if (evt.kind == Q.InteractionEvent.ELEMENT_MOVING) {  
    if (!isGroup(data)) {  
        var g = findGroup(evt.event);  
        highlight(g);  
    }  
    return;  
}  
if (evt.kind == Q.InteractionEvent.ELEMENT_MOVE_END) {  
    highlight();  
    if (isGroup(data)) {  
        if (groupIntersected(data)) {  
            var old = oldLocation[data.id];  
            graph.moveElements([data], old.x - data.x, old.y - data.y);  
        }  
        return;  
    }  
    var g = findGroup(evt.event);  
    if (g) {  
        data.parent = data.host = g;  
        fixNode(data);  
    } else {  
        data.location = oldLocation[data.id];  
    }  
    oldLocation = {};  
}  

})
最终效果

VPC配置图www.szyoudun.com

收起阅读 »

php 建造者生成器模式学习笔记

适用场景:
1、 需要生成的产品对象有复杂的内部结构。
2、 需要生成的产品对象的属性相互依赖,生成器模式可以强迫生成顺序。
3、 在对象创建过程中会使用到系统中的一些其它对象,这些对象在产品对象的创建过程中不易得到。
使用效果:
1、 生成器模式的使用使得产品的内部表象可以独立的变化。使用生成器模式可以使客户端不必知道产品内部组成的细节。
2、 每一个Builder都相对独立,而与其它的Builder无关。
3、 模式所建造的最终产品更易于控制。

<?php
/**

  • Created by PhpStorm.
    */

/**具体产品角色 车

  • Class Car
    */
    class Car
    {
    public $_head;
    public $_engine;//引擎
    public $_tyre;//轮胎

function show()
{
echo "车头的颜色:{$this->_head}<br/>";
echo "引擎的品牌:{$this->_engine}<br/>";
echo "轮胎的品牌:{$this->_tyre}<br/>";
}
}

/**抽象车的建造者(生成器)

  • Class CarBuilder
    */
    abstract class CarBuilder
    {
    protected $_car;

function __construct()
{
$this->_car=new Car();
}

abstract function BuildHead();
abstract function BuildEngine();
abstract function BuildTyre();
abstract function GetCar();
}

/**具体车的建造者(生成器) 宝马

  • Class BMW
    */
    class BMW extends CarBuilder
    {

function BuildHead()
{
// TODO: Implement BuilderHead() method.
$this->_car->_head="Black";
}

function BuildEngine()
{
// TODO: Implement BuildEngine() method.
$this->_car->_engine="BMW";
}

function BuildTyre()
{
// TODO: Implement BuildTyre() method.
$this->_car->_tyre="BMW";
}

function GetCar()
{
// TODO: Implement GetCar() method.
return $this->_car;
}
}

/**别克

  • Class BuickBird
    */
    class BuickBird extends CarBuilder
    {

function BuildHead()
{
// TODO: Implement BuildHead() method.
$this->_car->_head="Red";
}

function BuildEngine()
{
// TODO: Implement BuildEngine() BMmethod.
$this->_car->_engine="Buick";//
}

function BuildTyre()
{
// TODO: Implement BuildTyre() method.
$this->_car->_tyre="Buick";
}

function GetCar()
{
// TODO: Implement GetCar() method.
return $this->_car;
}
}

/**指挥者

  • Class Director
    */
    class Director
    {
    /**
  • @param $_builder 建造者
  • @return mixed 产品类:车
    */
    function Construct($_builder)
    {
    $_builder->BuildHead();
    $_builder->BuildEngine();
    $_builder->BuildTyre();
    return $_builder->GetCar();
    }
    }www.szyoudun.com
继续阅读 »

适用场景:
1、 需要生成的产品对象有复杂的内部结构。
2、 需要生成的产品对象的属性相互依赖,生成器模式可以强迫生成顺序。
3、 在对象创建过程中会使用到系统中的一些其它对象,这些对象在产品对象的创建过程中不易得到。
使用效果:
1、 生成器模式的使用使得产品的内部表象可以独立的变化。使用生成器模式可以使客户端不必知道产品内部组成的细节。
2、 每一个Builder都相对独立,而与其它的Builder无关。
3、 模式所建造的最终产品更易于控制。

<?php
/**

  • Created by PhpStorm.
    */

/**具体产品角色 车

  • Class Car
    */
    class Car
    {
    public $_head;
    public $_engine;//引擎
    public $_tyre;//轮胎

function show()
{
echo "车头的颜色:{$this->_head}<br/>";
echo "引擎的品牌:{$this->_engine}<br/>";
echo "轮胎的品牌:{$this->_tyre}<br/>";
}
}

/**抽象车的建造者(生成器)

  • Class CarBuilder
    */
    abstract class CarBuilder
    {
    protected $_car;

function __construct()
{
$this->_car=new Car();
}

abstract function BuildHead();
abstract function BuildEngine();
abstract function BuildTyre();
abstract function GetCar();
}

/**具体车的建造者(生成器) 宝马

  • Class BMW
    */
    class BMW extends CarBuilder
    {

function BuildHead()
{
// TODO: Implement BuilderHead() method.
$this->_car->_head="Black";
}

function BuildEngine()
{
// TODO: Implement BuildEngine() method.
$this->_car->_engine="BMW";
}

function BuildTyre()
{
// TODO: Implement BuildTyre() method.
$this->_car->_tyre="BMW";
}

function GetCar()
{
// TODO: Implement GetCar() method.
return $this->_car;
}
}

/**别克

  • Class BuickBird
    */
    class BuickBird extends CarBuilder
    {

function BuildHead()
{
// TODO: Implement BuildHead() method.
$this->_car->_head="Red";
}

function BuildEngine()
{
// TODO: Implement BuildEngine() BMmethod.
$this->_car->_engine="Buick";//
}

function BuildTyre()
{
// TODO: Implement BuildTyre() method.
$this->_car->_tyre="Buick";
}

function GetCar()
{
// TODO: Implement GetCar() method.
return $this->_car;
}
}

/**指挥者

  • Class Director
    */
    class Director
    {
    /**
  • @param $_builder 建造者
  • @return mixed 产品类:车
    */
    function Construct($_builder)
    {
    $_builder->BuildHead();
    $_builder->BuildEngine();
    $_builder->BuildTyre();
    return $_builder->GetCar();
    }
    }www.szyoudun.com
收起阅读 »

php反射类 ReflectionClass使用例子

反射类是一个类的映射
namespace News;
class News{
public $newsid;
public function index(){
……
}
}
正常我们实例化一个类是这样: $News = new News\News();
如果我们要实例化News类的反射类是这样:$News = new \ReflectionClass(‘News\News’);
那么通过反射类实例化的类和普通类有什么不同呢?
通过反射类实例化的类我们可以获取这个这个类的详细信息,可以对类进行分析
例如:$News->getProperties()可以获取这个类的所有属性与方法。
array (size=1)
0 => & object(ReflectionProperty)[2]
public 'name' => string 'newsid' (length=6)
public 'class' => string 'News' (length=4)
getShortName() getName() getNamespaceName() 分别可以获得类名,带命名空间的类名,和命名空间的名称 News News\News News
ReflectionClass的一个应用就是在父类中获取子类的名称,从而针对不同的子类做不同的处理:
$reflection = new \ReflectionClass($this);
$class_name = $reflection->getShortName();
// check key
if (!key_exists($class_name, $this->configs)) {
return true;
}
// params
$params = $this->configs[$class_name];
return $this->_handle($params);
反射类的使用应该可以相当灵活,还有相当多的其他用途待发掘。www.qqfarms.cn

继续阅读 »

反射类是一个类的映射
namespace News;
class News{
public $newsid;
public function index(){
……
}
}
正常我们实例化一个类是这样: $News = new News\News();
如果我们要实例化News类的反射类是这样:$News = new \ReflectionClass(‘News\News’);
那么通过反射类实例化的类和普通类有什么不同呢?
通过反射类实例化的类我们可以获取这个这个类的详细信息,可以对类进行分析
例如:$News->getProperties()可以获取这个类的所有属性与方法。
array (size=1)
0 => & object(ReflectionProperty)[2]
public 'name' => string 'newsid' (length=6)
public 'class' => string 'News' (length=4)
getShortName() getName() getNamespaceName() 分别可以获得类名,带命名空间的类名,和命名空间的名称 News News\News News
ReflectionClass的一个应用就是在父类中获取子类的名称,从而针对不同的子类做不同的处理:
$reflection = new \ReflectionClass($this);
$class_name = $reflection->getShortName();
// check key
if (!key_exists($class_name, $this->configs)) {
return true;
}
// params
$params = $this->configs[$class_name];
return $this->_handle($params);
反射类的使用应该可以相当灵活,还有相当多的其他用途待发掘。www.qqfarms.cn

收起阅读 »

PHP中简单工厂模式的学习笔记

简单工厂模式:
①抽象基类:类中定义抽象一些方法,用以在子类中实现
②继承自抽象基类的子类:实现基类中的抽象方法
③工厂类:用以实例化对象
使用工厂模式的目的或目标?
工厂模式的最大优点在于创建对象上面,就是把创建对象的过程封装起来,这样随时可以产生一个新的对象。
减少代码进行复制粘帖,耦合关系重,牵一发动其他部分代码。
通俗的说,以前创建一个对象要使用new,现在把这个过程封装起来了。
假设不使用工厂模式:那么很多地方调用类a,代码就会这样子创建一个实例:new a(),假设某天需要把a类的名称修改,意味着很多调用的代码都要修改。
工厂模式的优点就在创建对象上。

工厂模式的优点就在创建对象上。建立一个工厂(一个函数或一个类方法)来制造新的对象,它的任务就是把对象的创建过程都封装起来,
创建对象不是使用new的形式了。而是定义一个方法,用于创建对象实例。
每个类可能会需要连接数据库。那么就将连接数据库封装在一个类中。以后在其他类中通过类名:
为什么引入抽象的概念?

想一想,在现实生活中,当我们无法确定某个具体的东西的时候,往往把一类东西归于抽象类别。
工厂方法:
比如你的工厂叫做“香烟工厂”,那么可以有“七匹狼工厂”“中华工厂”等,但是,这个工厂只生厂一种商品:香烟;
抽象工厂:无法描述它到底生产什么产品,它生产很多类型的产品(所以抽象工厂就会生成子工厂)。
你的工厂是综合型的,是生产“一系列”产品,而不是“一个”,比如:生产“香烟”,还有“啤酒”等。然后它也可以有派生出来的具体的工厂,但这些工厂都是生产这一系列产品,只是可能因为地域不一样,为了适应当地人口味,味道也不太一样。
工厂模式:理解成只生成一种产品的工厂。比如生产香烟的。
工厂方法:工厂的一种产品生产线 。比如键盘的生成过程。

别人会反驳:吃饱了没事干,一定要修改类名称呢?这个说不定。一般都不会去修改类名称。

其实工厂模式有很多变体,抓住精髓才是关键:只要是可以根据不同的参数生成不同的类实例,那么就符合工厂模式的设计思想。
这样子让我联想到框架中经常会有负责生成具体类实例的方法供调用。
看完文章再回头来看下这张图,效果会比较好

采用封装方式
<?php
class Calc{
/**

  • 计算结果
  • @param int|float $num1
  • @param int|float $num2
  • @param string $operator
  • @return int|float
    /
    public function calculate($num1,$num2,$operator){
    try {
    $result=0;
    switch ($operator){
    case '+':
    $result= $num1+$num2;
    break;
    case '-':
    $result= $num1-$num2;
    break;
    case '
    ':
    $result= $num1*$num2;
    break;
    case '/':
    if ($num2==0) {
    throw new Exception("除数不能为0");
    }
    $result= $num1/$num2;
    break;
    }
    return $result;
    }catch (Exception $e){
    echo "您输入有误:".$e->getMessage();
    }
    }
    }
    $test=new Calc();
    // echo $test->calculate(2,3,'+');//打印:5
    echo $test->calculate(5,0,'/');//打印:您输入有误:除数不能为0
    ?>

优点:以上代码使用了面向对象的封装特性,只要有了include这个类,其他页面就可以随便使用了
缺点:无法灵活的扩展和维护
比如:想要增加一个“求余”运算,需要在switch语句块中添加一个分支语句,代码需要做如下改动
<?php
class Calc{
public function calculate($num1,$num2,$operator){
try {
$result=0;
switch ($operator){
//......省略......
case '%':
$result= $num1%$num2;
break;
//......省略......
}
}catch (Exception $e){
echo "您输入有误:".$e->getMessage();
}
}
}
?>
代码分析:用以上方法实现给计算器添加新的功能运算有以下几个缺点
①需要改动原有的代码块,可能会在为了“添加新功能”而改动原有代码的时候,不小心将原有的代码改错了
②如果要添加的功能很多,比如:‘乘方’,‘开方’,‘对数’,‘三角函数’,‘统计’,或者添加一些程序员专用的计算功能,比如:And, Or, Not, Xor,这样就需要在switch语句中添加N个分支语句。想象下,一个计算功能的函数如果有二三十个case分支语句,代码将超过一屏,不仅令代码的可读性大大降低,关键是,为了添加小功能,还得让其余不相关都参与解释,这令程序的执行效率大大降低
解决途径:采用OOP的继承和多态思想
<?php
/**

  • 操作类
  • 因为包含有抽象方法,所以类必须声明为抽象类
    */
    abstract class Operation{
    //抽象方法不能包含函数体
    abstract public function getValue($num1,$num2);//强烈要求子类必须实现该功能函数
    }
    /**
  • 加法类
    */
    class OperationAdd extends Operation {
    public function getValue($num1,$num2){
    return $num1+$num2;
    }
    }
    /**
  • 减法类
    */
    class OperationSub extends Operation {
    public function getValue($num1,$num2){
    return $num1-$num2;
    }
    }
    /**
  • 乘法类
    /
    class OperationMul extends Operation {
    public function getValue($num1,$num2){
    return $num1
    $num2;
    }
    }
    /**
  • 除法类
    */
    class OperationDiv extends Operation {
    public function getValue($num1,$num2){
    try {
    if ($num2==0){
    throw new Exception("除数不能为0");
    }else {
    return $num1/$num2;
    }
    }catch (Exception $e){
    echo "错误信息:".$e->getMessage();
    }
    }
    }
    ?>

这里采用了面向对象的继承特性,首先声明一个虚拟基类,在基类中指定子类务必实现的方法(getValue())
分析:通过采用面向对象的继承特性,我们可以很容易就能对原有程序进行扩展,比如:‘乘方’,‘开方’,‘对数’,‘三角函数’,‘统计’等等。
<?php
/**

  • 求余类(remainder)
  • */
    class OperationRem extends Operation {
    public function getValue($num1,$num2){
    return $num1%$num12;
    }
    }
    ?>

我们只需要另外写一个类(该类继承虚拟基类),在类中完成相应的功能(比如:求乘方的运算),而且大大的降低了耦合度,方便日后的维护及扩展
现在还有一个问题未解决,就是如何让程序根据用户输入的操作符实例化相应的对象呢?
解决办法:使用一个单独的类来实现实例化的过程,这个类就是工厂
代码如下:
<?php
/**

  • 工程类,主要用来创建对象
  • 功能:根据输入的运算符号,工厂就能实例化出合适的对象
  • /
    class Factory{
    public static function createObj($operate){
    switch ($operate){
    case '+':
    return new OperationAdd();
    break;
    case '-':
    return new OperationSub();
    break;
    case '
    ':
    return new OperationSub();
    break;
    case '/':
    return new OperationDiv();
    break;
    }
    }
    }
    $test=Factory::createObj('/');
    $result=$test->getValue(23,0);
    echo $result;
    ?>

再扩展一些
比如如何根据玩家输入的内容(尽管可以转化为其他字符串),来确定要制造的兵种,玩家不会输入代码:new Marine()。
和星际一样,PHP也没有终极兵种,如果类和接口是兵种的话,那么设计模式就是你的战术和控制,它可以让你靠各种兵种的搭配获胜。
待解决的问题:在人族的兵营,我们靠相应玩家的输入来动态确定要造的兵种,假设是机枪兵和火焰兵。
思路:动态的根据传递的数据,新建相应的类的对象。
简单工厂模式示例:
我们把机枪兵类的代码放入一个文件,Marine.php,它的代码如下:
<?php
class Marine {
//机枪兵攻击的方法
public function attack()
{
echo 'Marine attack';
}
}
?>

我们把火焰兵类的代码放入一个文件,Firebat.php,它的代码如下:
<?php
class Firebat {
//火焰兵攻击的方法
public function attack()
{
echo 'Firebat attack';
}
}
?>

主文件中的内容如下:
<?php
//兵种制造器的类
class BarracksCreator {
//制造兵种的方法
public create($createWhat)
{
//根据输入的参数,动态的把需要的类的定义文件载入
require_once($createWhat.'.php');
//根据输入的参数,动态的返回需要的类的对象
return new $createWhat;
}
}
//新建一个兵种制造器对象
$creator = new BarracksCreator();
//靠接收参数制造一个火焰兵对象
$troop1 = $creator->create('Marine');
$troop1->attack();
//靠接收参数制造一个机枪兵对象
$troop2 = $creator->create('Firebat');
$troop2->attack();
?>

用途总结:简单工厂模式可以将新建对象的任务进行封装,一旦需要增加新的返回类,只要修改负责新建对象的那部分代码。
实现总结:需要一个自动根据参数返回新建对象的工厂,比如上面兵种制造器BarracksCreator,使用的时候只需要将参数传递给他的生产方法create(),无需考虑具体的生产细节。www.szyoudun.com

继续阅读 »

简单工厂模式:
①抽象基类:类中定义抽象一些方法,用以在子类中实现
②继承自抽象基类的子类:实现基类中的抽象方法
③工厂类:用以实例化对象
使用工厂模式的目的或目标?
工厂模式的最大优点在于创建对象上面,就是把创建对象的过程封装起来,这样随时可以产生一个新的对象。
减少代码进行复制粘帖,耦合关系重,牵一发动其他部分代码。
通俗的说,以前创建一个对象要使用new,现在把这个过程封装起来了。
假设不使用工厂模式:那么很多地方调用类a,代码就会这样子创建一个实例:new a(),假设某天需要把a类的名称修改,意味着很多调用的代码都要修改。
工厂模式的优点就在创建对象上。

工厂模式的优点就在创建对象上。建立一个工厂(一个函数或一个类方法)来制造新的对象,它的任务就是把对象的创建过程都封装起来,
创建对象不是使用new的形式了。而是定义一个方法,用于创建对象实例。
每个类可能会需要连接数据库。那么就将连接数据库封装在一个类中。以后在其他类中通过类名:
为什么引入抽象的概念?

想一想,在现实生活中,当我们无法确定某个具体的东西的时候,往往把一类东西归于抽象类别。
工厂方法:
比如你的工厂叫做“香烟工厂”,那么可以有“七匹狼工厂”“中华工厂”等,但是,这个工厂只生厂一种商品:香烟;
抽象工厂:无法描述它到底生产什么产品,它生产很多类型的产品(所以抽象工厂就会生成子工厂)。
你的工厂是综合型的,是生产“一系列”产品,而不是“一个”,比如:生产“香烟”,还有“啤酒”等。然后它也可以有派生出来的具体的工厂,但这些工厂都是生产这一系列产品,只是可能因为地域不一样,为了适应当地人口味,味道也不太一样。
工厂模式:理解成只生成一种产品的工厂。比如生产香烟的。
工厂方法:工厂的一种产品生产线 。比如键盘的生成过程。

别人会反驳:吃饱了没事干,一定要修改类名称呢?这个说不定。一般都不会去修改类名称。

其实工厂模式有很多变体,抓住精髓才是关键:只要是可以根据不同的参数生成不同的类实例,那么就符合工厂模式的设计思想。
这样子让我联想到框架中经常会有负责生成具体类实例的方法供调用。
看完文章再回头来看下这张图,效果会比较好

采用封装方式
<?php
class Calc{
/**

  • 计算结果
  • @param int|float $num1
  • @param int|float $num2
  • @param string $operator
  • @return int|float
    /
    public function calculate($num1,$num2,$operator){
    try {
    $result=0;
    switch ($operator){
    case '+':
    $result= $num1+$num2;
    break;
    case '-':
    $result= $num1-$num2;
    break;
    case '
    ':
    $result= $num1*$num2;
    break;
    case '/':
    if ($num2==0) {
    throw new Exception("除数不能为0");
    }
    $result= $num1/$num2;
    break;
    }
    return $result;
    }catch (Exception $e){
    echo "您输入有误:".$e->getMessage();
    }
    }
    }
    $test=new Calc();
    // echo $test->calculate(2,3,'+');//打印:5
    echo $test->calculate(5,0,'/');//打印:您输入有误:除数不能为0
    ?>

优点:以上代码使用了面向对象的封装特性,只要有了include这个类,其他页面就可以随便使用了
缺点:无法灵活的扩展和维护
比如:想要增加一个“求余”运算,需要在switch语句块中添加一个分支语句,代码需要做如下改动
<?php
class Calc{
public function calculate($num1,$num2,$operator){
try {
$result=0;
switch ($operator){
//......省略......
case '%':
$result= $num1%$num2;
break;
//......省略......
}
}catch (Exception $e){
echo "您输入有误:".$e->getMessage();
}
}
}
?>
代码分析:用以上方法实现给计算器添加新的功能运算有以下几个缺点
①需要改动原有的代码块,可能会在为了“添加新功能”而改动原有代码的时候,不小心将原有的代码改错了
②如果要添加的功能很多,比如:‘乘方’,‘开方’,‘对数’,‘三角函数’,‘统计’,或者添加一些程序员专用的计算功能,比如:And, Or, Not, Xor,这样就需要在switch语句中添加N个分支语句。想象下,一个计算功能的函数如果有二三十个case分支语句,代码将超过一屏,不仅令代码的可读性大大降低,关键是,为了添加小功能,还得让其余不相关都参与解释,这令程序的执行效率大大降低
解决途径:采用OOP的继承和多态思想
<?php
/**

  • 操作类
  • 因为包含有抽象方法,所以类必须声明为抽象类
    */
    abstract class Operation{
    //抽象方法不能包含函数体
    abstract public function getValue($num1,$num2);//强烈要求子类必须实现该功能函数
    }
    /**
  • 加法类
    */
    class OperationAdd extends Operation {
    public function getValue($num1,$num2){
    return $num1+$num2;
    }
    }
    /**
  • 减法类
    */
    class OperationSub extends Operation {
    public function getValue($num1,$num2){
    return $num1-$num2;
    }
    }
    /**
  • 乘法类
    /
    class OperationMul extends Operation {
    public function getValue($num1,$num2){
    return $num1
    $num2;
    }
    }
    /**
  • 除法类
    */
    class OperationDiv extends Operation {
    public function getValue($num1,$num2){
    try {
    if ($num2==0){
    throw new Exception("除数不能为0");
    }else {
    return $num1/$num2;
    }
    }catch (Exception $e){
    echo "错误信息:".$e->getMessage();
    }
    }
    }
    ?>

这里采用了面向对象的继承特性,首先声明一个虚拟基类,在基类中指定子类务必实现的方法(getValue())
分析:通过采用面向对象的继承特性,我们可以很容易就能对原有程序进行扩展,比如:‘乘方’,‘开方’,‘对数’,‘三角函数’,‘统计’等等。
<?php
/**

  • 求余类(remainder)
  • */
    class OperationRem extends Operation {
    public function getValue($num1,$num2){
    return $num1%$num12;
    }
    }
    ?>

我们只需要另外写一个类(该类继承虚拟基类),在类中完成相应的功能(比如:求乘方的运算),而且大大的降低了耦合度,方便日后的维护及扩展
现在还有一个问题未解决,就是如何让程序根据用户输入的操作符实例化相应的对象呢?
解决办法:使用一个单独的类来实现实例化的过程,这个类就是工厂
代码如下:
<?php
/**

  • 工程类,主要用来创建对象
  • 功能:根据输入的运算符号,工厂就能实例化出合适的对象
  • /
    class Factory{
    public static function createObj($operate){
    switch ($operate){
    case '+':
    return new OperationAdd();
    break;
    case '-':
    return new OperationSub();
    break;
    case '
    ':
    return new OperationSub();
    break;
    case '/':
    return new OperationDiv();
    break;
    }
    }
    }
    $test=Factory::createObj('/');
    $result=$test->getValue(23,0);
    echo $result;
    ?>

再扩展一些
比如如何根据玩家输入的内容(尽管可以转化为其他字符串),来确定要制造的兵种,玩家不会输入代码:new Marine()。
和星际一样,PHP也没有终极兵种,如果类和接口是兵种的话,那么设计模式就是你的战术和控制,它可以让你靠各种兵种的搭配获胜。
待解决的问题:在人族的兵营,我们靠相应玩家的输入来动态确定要造的兵种,假设是机枪兵和火焰兵。
思路:动态的根据传递的数据,新建相应的类的对象。
简单工厂模式示例:
我们把机枪兵类的代码放入一个文件,Marine.php,它的代码如下:
<?php
class Marine {
//机枪兵攻击的方法
public function attack()
{
echo 'Marine attack';
}
}
?>

我们把火焰兵类的代码放入一个文件,Firebat.php,它的代码如下:
<?php
class Firebat {
//火焰兵攻击的方法
public function attack()
{
echo 'Firebat attack';
}
}
?>

主文件中的内容如下:
<?php
//兵种制造器的类
class BarracksCreator {
//制造兵种的方法
public create($createWhat)
{
//根据输入的参数,动态的把需要的类的定义文件载入
require_once($createWhat.'.php');
//根据输入的参数,动态的返回需要的类的对象
return new $createWhat;
}
}
//新建一个兵种制造器对象
$creator = new BarracksCreator();
//靠接收参数制造一个火焰兵对象
$troop1 = $creator->create('Marine');
$troop1->attack();
//靠接收参数制造一个机枪兵对象
$troop2 = $creator->create('Firebat');
$troop2->attack();
?>

用途总结:简单工厂模式可以将新建对象的任务进行封装,一旦需要增加新的返回类,只要修改负责新建对象的那部分代码。
实现总结:需要一个自动根据参数返回新建对象的工厂,比如上面兵种制造器BarracksCreator,使用的时候只需要将参数传递给他的生产方法create(),无需考虑具体的生产细节。www.szyoudun.com

收起阅读 »

一个底部选项卡的实现(webview模式)

选项卡

直接上代码吧。
自行修改正确的资源文件路径(此例子直接放在默认目录下,同级目录放tab-*.html)

<!--  main.html 入口文件 -->  
<!DOCTYPE html>  
<html>  

    <head>  
        <meta charset="utf-8">  
        <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />  
        <title>选项卡演示</title>  
        <link href="css/mui.min.css" rel="stylesheet" />  
        <style>  
        </style>  
    </head>  

    <body>  
        <div class="mui-content">  
            <nav id="bar" class="mui-bar mui-bar-tab">  
                <a class="mui-tab-item mui-active" href="tab-main.html" data-id="main">  
                    <span class="mui-icon mui-icon-home"></span>  
                    <span class="mui-tab-label">首页</span>  
                </a>  
                <a class="mui-tab-item" href="tab-message.html" data-id="message">  
                    <span class="mui-icon mui-icon-email"></span>  
                    <span class="mui-tab-label">消息</span>  
                </a>  
                <a class="mui-tab-item" href="tab-contact.html" data-id="contact">  
                    <span class="mui-icon mui-icon-contact"></span>  
                    <span class="mui-tab-label">通讯录</span>  
                </a>  
                <a class="mui-tab-item" href="tab-setting.html" data-id="setting">  
                    <span class="mui-icon mui-icon-gear"></span>  
                    <span class="mui-tab-label">设置</span>  
                </a>  
            </nav>  
        </div>  
        <script src="js/mui.min.js"></script>  
        <script>  
            mui.init();  
            mui.plusReady(function() {  
                var self = plus.webview.currentWebview();  
                var current = '';  
                var styles = {  
                    top: '0',  
                    bottom: '51px'  
                };  
                var tabsConfig = {  
                    main: {  
                        url: 'tab-main.html',  
                        styles: styles,  
                        default: true  
                    },  
                    message: {  
                        url: 'tab-message.html',  
                        styles: styles  
                    },  
                    contact: {  
                        url: 'tab-contact.html',  
                        styles: styles  
                    },  
                    setting: {  
                        url: 'tab-setting.html',  
                        styles: styles  
                    }  
                };  
                var tabs = {};  
                for (id in tabsConfig) {  
                    tabs[id] = plus.webview.create(tabsConfig[id].url, id, tabsConfig[id].styles);  
                    if (tabsConfig[id]['default']) {  
                        self.append(tabs[id]);  
                        current = id;  
                    }  
                }  
                mui('#bar').on('tap', 'a', function(e) {  
                    if (current == this.dataset.id) {  
                        mui.fire(tabs[current], 'scroll2top');  
                        return;  
                    }  
                    tabs[this.dataset.id].show();  
                    tabs[current].hide();  
                    current = this.dataset.id;  
                });  
            });  
        </script>  
    </body>  
</html>
<!-- tab-*.html 举例-->  
<!DOCTYPE html>  
<html>  
<head>  
    <meta charset="UTF-8">  
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />  
    <title>此处就是显示的标题</title>  
    <script src="js/mui.min.js"></script>  
    <link href="css/mui.min.css" rel="stylesheet"/>  
    <script type="text/javascript" charset="UTF-8">  
        mui.init();  
    </script>  
</head>  
<body>  
    <div class="mui-content">  
        <p>示例页面,此页面内容正常写,标题就是标签页的标题。</p>  
    </div>  
</body>  
</html>

更新:上传了一个完整的例子~ 懒人最爱~

继续阅读 »

直接上代码吧。
自行修改正确的资源文件路径(此例子直接放在默认目录下,同级目录放tab-*.html)

<!--  main.html 入口文件 -->  
<!DOCTYPE html>  
<html>  

    <head>  
        <meta charset="utf-8">  
        <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />  
        <title>选项卡演示</title>  
        <link href="css/mui.min.css" rel="stylesheet" />  
        <style>  
        </style>  
    </head>  

    <body>  
        <div class="mui-content">  
            <nav id="bar" class="mui-bar mui-bar-tab">  
                <a class="mui-tab-item mui-active" href="tab-main.html" data-id="main">  
                    <span class="mui-icon mui-icon-home"></span>  
                    <span class="mui-tab-label">首页</span>  
                </a>  
                <a class="mui-tab-item" href="tab-message.html" data-id="message">  
                    <span class="mui-icon mui-icon-email"></span>  
                    <span class="mui-tab-label">消息</span>  
                </a>  
                <a class="mui-tab-item" href="tab-contact.html" data-id="contact">  
                    <span class="mui-icon mui-icon-contact"></span>  
                    <span class="mui-tab-label">通讯录</span>  
                </a>  
                <a class="mui-tab-item" href="tab-setting.html" data-id="setting">  
                    <span class="mui-icon mui-icon-gear"></span>  
                    <span class="mui-tab-label">设置</span>  
                </a>  
            </nav>  
        </div>  
        <script src="js/mui.min.js"></script>  
        <script>  
            mui.init();  
            mui.plusReady(function() {  
                var self = plus.webview.currentWebview();  
                var current = '';  
                var styles = {  
                    top: '0',  
                    bottom: '51px'  
                };  
                var tabsConfig = {  
                    main: {  
                        url: 'tab-main.html',  
                        styles: styles,  
                        default: true  
                    },  
                    message: {  
                        url: 'tab-message.html',  
                        styles: styles  
                    },  
                    contact: {  
                        url: 'tab-contact.html',  
                        styles: styles  
                    },  
                    setting: {  
                        url: 'tab-setting.html',  
                        styles: styles  
                    }  
                };  
                var tabs = {};  
                for (id in tabsConfig) {  
                    tabs[id] = plus.webview.create(tabsConfig[id].url, id, tabsConfig[id].styles);  
                    if (tabsConfig[id]['default']) {  
                        self.append(tabs[id]);  
                        current = id;  
                    }  
                }  
                mui('#bar').on('tap', 'a', function(e) {  
                    if (current == this.dataset.id) {  
                        mui.fire(tabs[current], 'scroll2top');  
                        return;  
                    }  
                    tabs[this.dataset.id].show();  
                    tabs[current].hide();  
                    current = this.dataset.id;  
                });  
            });  
        </script>  
    </body>  
</html>
<!-- tab-*.html 举例-->  
<!DOCTYPE html>  
<html>  
<head>  
    <meta charset="UTF-8">  
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />  
    <title>此处就是显示的标题</title>  
    <script src="js/mui.min.js"></script>  
    <link href="css/mui.min.css" rel="stylesheet"/>  
    <script type="text/javascript" charset="UTF-8">  
        mui.init();  
    </script>  
</head>  
<body>  
    <div class="mui-content">  
        <p>示例页面,此页面内容正常写,标题就是标签页的标题。</p>  
    </div>  
</body>  
</html>

更新:上传了一个完整的例子~ 懒人最爱~

收起阅读 »

CSS 自动验证格式化排序 一行一条 [新]

css 格式化

HBuilderX 的 CSS格式化使用 js-beautify 插件, 这玩意不能格式化成一行,现提供新的的方法。

官方插件市场安装插件 validate-stylelint
该插件在 保存时 进行语法校验,提示错误,自动修复 。我们可借助 [一行规则+自动修复]来自动格式化,并增加一个排序功能。
截至 v1.0.6 版本 没有开启【自动修复】,暂需自行修改插件。若插件更新并开启自动修复,可忽略修改步骤。

安装后 ,插件文件夹 x:\HBuilderX\plugins\validate-stylelint

1、改造插件,开启自动修复,添加排序插件
修改文件 package.json
1-1、在命令数组最后添加个 "--fix" 参数 开启修复

 "command": [  
    ....  
    "${pluginPath}",  
    "${file}", // 逗号分隔  
    "--fix"  // 这里添加    
]

1-2、添加排序插件

"dependencies": {  
    .....  
    "stylelint-config-standard": "^18.2.0",  
    "stylelint-config-recess-order": "^2.4.0"  // 添加  
}

validate-stylelint 文件夹下执行 [ npm up ] 更新依赖

2、新增排序扩展 和 一行 规则

修改规则文件 .stylelintrc.js

"extends": [  
    "stylelint-config-recommended",  
    "stylelint-config-recess-order"  // 添加  
],  
"rules": {  
     // 自定义一行规则 见附件  
}
h1,  
h2{  
    color:#fff;  
    margin-top: 0;  
    top: 10px;  
}  
// 自动格式化+排序  
h1, h2{ top: 10px; margin-top: 0; color:#fff;}
继续阅读 »

HBuilderX 的 CSS格式化使用 js-beautify 插件, 这玩意不能格式化成一行,现提供新的的方法。

官方插件市场安装插件 validate-stylelint
该插件在 保存时 进行语法校验,提示错误,自动修复 。我们可借助 [一行规则+自动修复]来自动格式化,并增加一个排序功能。
截至 v1.0.6 版本 没有开启【自动修复】,暂需自行修改插件。若插件更新并开启自动修复,可忽略修改步骤。

安装后 ,插件文件夹 x:\HBuilderX\plugins\validate-stylelint

1、改造插件,开启自动修复,添加排序插件
修改文件 package.json
1-1、在命令数组最后添加个 "--fix" 参数 开启修复

 "command": [  
    ....  
    "${pluginPath}",  
    "${file}", // 逗号分隔  
    "--fix"  // 这里添加    
]

1-2、添加排序插件

"dependencies": {  
    .....  
    "stylelint-config-standard": "^18.2.0",  
    "stylelint-config-recess-order": "^2.4.0"  // 添加  
}

validate-stylelint 文件夹下执行 [ npm up ] 更新依赖

2、新增排序扩展 和 一行 规则

修改规则文件 .stylelintrc.js

"extends": [  
    "stylelint-config-recommended",  
    "stylelint-config-recess-order"  // 添加  
],  
"rules": {  
     // 自定义一行规则 见附件  
}
h1,  
h2{  
    color:#fff;  
    margin-top: 0;  
    top: 10px;  
}  
// 自动格式化+排序  
h1, h2{ top: 10px; margin-top: 0; color:#fff;}
收起阅读 »

在哪里可以学习整套的MUI 和Hbuilder 课程?

mui HBuilder

推荐国内首推的跨平台移动APP开发专业培训机构-东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!咨询报名QQ:410355878 网址:http://www.dongyixueyuan.com/ 欢迎有意向学习的朋友加好友咨询!谢谢Dcloud提供这么好的平台!

学习前常见的问题有哪些,下面做了详细的介绍!
1.VIP课时时间多久?
2.学费多少?
3.线上线下?
4.能够给予实践指导吗?
5.需要什么基础吗?(我现在是前端开发,有JAVA基础)
6.有什么优惠吗?
7.上课时间?
8.一遍听不会,可以重复看吗?
9.有问题有专们的老师解答吗,还是留言等老师解答?
10.如果老师回答问题,一般多久会回复,这么多人能顾得上回答我的问题吗?

1.vip课程报名后终身学习,循环开班,每一期周期是1-2个月,根据学员掌握情况和APP开发实战项目教学进行微调(每一期都会讲一个不一样的APP开发项目)
2.学费3800元 这一期报名有求职季活动,减300 并且有相关福利赠送
3.线上学习,在腾讯课堂教学
4.可以的 实战项目开发 在高级课程部分
5.零基础可以学习 不需要太高的编程基础
6.优惠在第2条已说明了哦
7.每周一至周六 晚上8点-10点 突发情况或节假日顺延或者微调
8.无限重修
9.有专门老师解答 分为前端课程 UI课程 高级实战课程 分别有两位专业老师解答 工作日上午10点-下午6点 晚上上课可以在课堂直接提问
10.小班授课,保证每一位同学都可以得到老师的辅导,每一期我们在10人左右 ,一位老师辅导5位同学。

继续阅读 »

推荐国内首推的跨平台移动APP开发专业培训机构-东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!咨询报名QQ:410355878 网址:http://www.dongyixueyuan.com/ 欢迎有意向学习的朋友加好友咨询!谢谢Dcloud提供这么好的平台!

学习前常见的问题有哪些,下面做了详细的介绍!
1.VIP课时时间多久?
2.学费多少?
3.线上线下?
4.能够给予实践指导吗?
5.需要什么基础吗?(我现在是前端开发,有JAVA基础)
6.有什么优惠吗?
7.上课时间?
8.一遍听不会,可以重复看吗?
9.有问题有专们的老师解答吗,还是留言等老师解答?
10.如果老师回答问题,一般多久会回复,这么多人能顾得上回答我的问题吗?

1.vip课程报名后终身学习,循环开班,每一期周期是1-2个月,根据学员掌握情况和APP开发实战项目教学进行微调(每一期都会讲一个不一样的APP开发项目)
2.学费3800元 这一期报名有求职季活动,减300 并且有相关福利赠送
3.线上学习,在腾讯课堂教学
4.可以的 实战项目开发 在高级课程部分
5.零基础可以学习 不需要太高的编程基础
6.优惠在第2条已说明了哦
7.每周一至周六 晚上8点-10点 突发情况或节假日顺延或者微调
8.无限重修
9.有专门老师解答 分为前端课程 UI课程 高级实战课程 分别有两位专业老师解答 工作日上午10点-下午6点 晚上上课可以在课堂直接提问
10.小班授课,保证每一位同学都可以得到老师的辅导,每一期我们在10人左右 ,一位老师辅导5位同学。

收起阅读 »

修改PopPicker 增加动态级联能力。

mui

主要思路是增加一个change入口, 当选项发生改变时可以触发自己的级联逻辑。

var province = new mui.PopPicker(  
            {layer: 3,  
                //change  
                changeFn:function(even){  
                    //change 自己的逻辑  
                                       var nextPickerElement = this.nextSibling;  
                    if (nextPickerElement && nextPickerElement.picker) {  
                        var eventData = event.detail || {};  
                        var preItem = eventData.item || {};  
                        if (preItem.type == 'province'){  
                            nextPickerElement.picker.setItems(getCascadeData("cities", preItem.value));  
                        } else if (preItem.type == 'cities'){  
                            nextPickerElement.picker.setItems(getCascadeData("counties", preItem.value));  
                        }  
                    }  
                }  
            });
var PopPicker = $.PopPicker = $.Class.extend({  
        //构造函数  
        init: function(options) {  
            var self = this;  
            self.options = options || {};  
            self.options.buttons = self.options.buttons || ['取消', '确定'];  
            self.panel = $.dom(panelBuffer)[0];  
            document.body.appendChild(self.panel);  
            self.ok = self.panel.querySelector('.mui-poppicker-btn-ok');  
            self.cancel = self.panel.querySelector('.mui-poppicker-btn-cancel');  
            self.body = self.panel.querySelector('.mui-poppicker-body');  
            self.mask = $.createMask();  
            self.cancel.innerText = self.options.buttons[0];  
            self.ok.innerText = self.options.buttons[1];  
            self.cancel.addEventListener('tap', function(event) {  
                self.hide();  
            }, false);  
            self.ok.addEventListener('tap', function(event) {  
                if (self.callback) {  
                    var rs = self.callback(self.getSelectedItems());  
                    if (rs !== false) {  
                        self.hide();  
                    }  
                }  
            }, false);  

            **self.changeFn = self.options.changeFn || function(event) {  
                var nextPickerElement = this.nextSibling;  
                if (nextPickerElement && nextPickerElement.picker) {  
                    var eventData = event.detail || {};  
                    var preItem = eventData.item || {};  
                    nextPickerElement.picker.setItems(preItem.children);  
                }  
            };**  

            self.mask[0].addEventListener('tap', function() {  
                self.hide();  
            }, false);  
            self._createPicker();  
            //防止滚动穿透  
            self.panel.addEventListener('touchstart', function(event) {  
                event.preventDefault();  
            }, false);  
            self.panel.addEventListener('touchmove', function(event) {  
                event.preventDefault();  
            }, false);  
        },  
        _createPicker: function() {  
            var self = this;  
            var layer = self.options.layer || 1;  
            var width = (100 / layer) + '%';  
            self.pickers = [];  
            for (var i = 1; i <= layer; i++) {  
                var pickerElement = $.dom(pickerBuffer)[0];  
                pickerElement.style.width = width;  
                self.body.appendChild(pickerElement);  
                var picker = $(pickerElement).picker();  
                self.pickers.push(picker);  
                pickerElement.addEventListener('change', self.changeFn, false);  
            }  
        },  
        //填充数据  
        setData: function(data) {  
            var self = this;  
            data = data || [];  
            self.pickers[0].setItems(data);  
        },  
        //获取选中的项(数组)  
        getSelectedItems: function() {  
            var self = this;  
            var items = [];  
            for (var i in self.pickers) {  
                var picker = self.pickers[i];  
                items.push(picker.getSelectedItem() || {});  
            }  
            return items;  
        },  
        //显示  
        show: function(callback) {  
            var self = this;  
            self.callback = callback;  
            self.mask.show();  
            document.body.classList.add($.className('poppicker-active-for-page'));  
            self.panel.classList.add($.className('active'));  
            //处理物理返回键  
            self.__back = $.back;  
            $.back = function() {  
                self.hide();  
            };  
        },  
        //隐藏  
        hide: function() {  
            var self = this;  
            if (self.disposed) return;  
            self.panel.classList.remove($.className('active'));  
            self.mask.close();  
            document.body.classList.remove($.className('poppicker-active-for-page'));  
            //处理物理返回键  
            $.back=self.__back;  
        },  
        dispose: function() {  
            var self = this;  
            self.hide();  
            setTimeout(function() {  
                self.panel.parentNode.removeChild(self.panel);  
                for (var name in self) {  
                    self[name] = null;  
                    delete self[name];  
                };  
                self.disposed = true;  
            }, 300);  
        }  
    });
继续阅读 »

主要思路是增加一个change入口, 当选项发生改变时可以触发自己的级联逻辑。

var province = new mui.PopPicker(  
            {layer: 3,  
                //change  
                changeFn:function(even){  
                    //change 自己的逻辑  
                                       var nextPickerElement = this.nextSibling;  
                    if (nextPickerElement && nextPickerElement.picker) {  
                        var eventData = event.detail || {};  
                        var preItem = eventData.item || {};  
                        if (preItem.type == 'province'){  
                            nextPickerElement.picker.setItems(getCascadeData("cities", preItem.value));  
                        } else if (preItem.type == 'cities'){  
                            nextPickerElement.picker.setItems(getCascadeData("counties", preItem.value));  
                        }  
                    }  
                }  
            });
var PopPicker = $.PopPicker = $.Class.extend({  
        //构造函数  
        init: function(options) {  
            var self = this;  
            self.options = options || {};  
            self.options.buttons = self.options.buttons || ['取消', '确定'];  
            self.panel = $.dom(panelBuffer)[0];  
            document.body.appendChild(self.panel);  
            self.ok = self.panel.querySelector('.mui-poppicker-btn-ok');  
            self.cancel = self.panel.querySelector('.mui-poppicker-btn-cancel');  
            self.body = self.panel.querySelector('.mui-poppicker-body');  
            self.mask = $.createMask();  
            self.cancel.innerText = self.options.buttons[0];  
            self.ok.innerText = self.options.buttons[1];  
            self.cancel.addEventListener('tap', function(event) {  
                self.hide();  
            }, false);  
            self.ok.addEventListener('tap', function(event) {  
                if (self.callback) {  
                    var rs = self.callback(self.getSelectedItems());  
                    if (rs !== false) {  
                        self.hide();  
                    }  
                }  
            }, false);  

            **self.changeFn = self.options.changeFn || function(event) {  
                var nextPickerElement = this.nextSibling;  
                if (nextPickerElement && nextPickerElement.picker) {  
                    var eventData = event.detail || {};  
                    var preItem = eventData.item || {};  
                    nextPickerElement.picker.setItems(preItem.children);  
                }  
            };**  

            self.mask[0].addEventListener('tap', function() {  
                self.hide();  
            }, false);  
            self._createPicker();  
            //防止滚动穿透  
            self.panel.addEventListener('touchstart', function(event) {  
                event.preventDefault();  
            }, false);  
            self.panel.addEventListener('touchmove', function(event) {  
                event.preventDefault();  
            }, false);  
        },  
        _createPicker: function() {  
            var self = this;  
            var layer = self.options.layer || 1;  
            var width = (100 / layer) + '%';  
            self.pickers = [];  
            for (var i = 1; i <= layer; i++) {  
                var pickerElement = $.dom(pickerBuffer)[0];  
                pickerElement.style.width = width;  
                self.body.appendChild(pickerElement);  
                var picker = $(pickerElement).picker();  
                self.pickers.push(picker);  
                pickerElement.addEventListener('change', self.changeFn, false);  
            }  
        },  
        //填充数据  
        setData: function(data) {  
            var self = this;  
            data = data || [];  
            self.pickers[0].setItems(data);  
        },  
        //获取选中的项(数组)  
        getSelectedItems: function() {  
            var self = this;  
            var items = [];  
            for (var i in self.pickers) {  
                var picker = self.pickers[i];  
                items.push(picker.getSelectedItem() || {});  
            }  
            return items;  
        },  
        //显示  
        show: function(callback) {  
            var self = this;  
            self.callback = callback;  
            self.mask.show();  
            document.body.classList.add($.className('poppicker-active-for-page'));  
            self.panel.classList.add($.className('active'));  
            //处理物理返回键  
            self.__back = $.back;  
            $.back = function() {  
                self.hide();  
            };  
        },  
        //隐藏  
        hide: function() {  
            var self = this;  
            if (self.disposed) return;  
            self.panel.classList.remove($.className('active'));  
            self.mask.close();  
            document.body.classList.remove($.className('poppicker-active-for-page'));  
            //处理物理返回键  
            $.back=self.__back;  
        },  
        dispose: function() {  
            var self = this;  
            self.hide();  
            setTimeout(function() {  
                self.panel.parentNode.removeChild(self.panel);  
                for (var name in self) {  
                    self[name] = null;  
                    delete self[name];  
                };  
                self.disposed = true;  
            }, 300);  
        }  
    });
收起阅读 »

指令集支持

建议指令集支持到armv7s,方便使用,否则工程本身需要支持到armv7s时,导入sdk很是不方便

建议指令集支持到armv7s,方便使用,否则工程本身需要支持到armv7s时,导入sdk很是不方便

边改边看、浏览器运行如何查看asp、jsp文件

浏览器运行 边改边看 JSP ASP

在HBuilde里运行asp、jsp文件需要设置这些文件使用何种服务器打开
配置如下:
工具-选项-HBuilder-web服务器,选择asp类文件、jsp类文件使用服务器类型


也可以在边改边看最左边设置处修改,如下图

继续阅读 »

在HBuilde里运行asp、jsp文件需要设置这些文件使用何种服务器打开
配置如下:
工具-选项-HBuilder-web服务器,选择asp类文件、jsp类文件使用服务器类型


也可以在边改边看最左边设置处修改,如下图

收起阅读 »