*purpleendurer修正了原文中的一些错误
你可以通过IE为你的HTML元素添加行为建立面向对象的页面设计方法Phillip Perkins建立了一个<DIV>对象当用户拖动它时它会在限定的<DIV>内继续定向运行
Macromedia Flash可以使开发者免受网络浏览器与互操作解决方案的限制但是局限于Flash让你无法体验到网络浏览器的许多特色
例如你可以通过IE为HTML元素添加行为建立对象面向的页面设计方法在这个例子中我会建立了一个<DIV>对象当用户拖动它时它会在限定的<DIV>内继续定向运行
为HTML添加行为的能力是设计的一个关键部分在IE中这通过相关的样式来实现添加行为的样式特性即behavior你可以通过嵌套的<STYLE>标签来添加行为就像这样
<style>DIVobject { behavior: url(Behaviorhtc);}
从这段脚本中你可以发现一个行为会提及到一个HTC(HTML组件)文件既然我们具有对象化这些HTML元素的基础我们就能建立控制它们的行为脚本
表A中包含了为我们的嵌套<DIV>对象建立行为的所有代码在这一个组件内就有许多的代码
表 A 文件componenthtc的内容
<public:component lightweight=true>
<public:attach event=onmousedown onevent=element_onmousedown()/>
<public:attach event=onmousemove onevent=element_onmousemove()/>
<public:attach event=onmouseup onevent=element_onmouseup()/>
<public:attach event=onmouseout onevent=element_onmouseup()/>
<public:attach event=onselectstart onevent=element_onselectstart()/>
<public:attach event=ondragstart onevent=element_ondragstart()/>
<public:attach event=onload for=window onevent=Init()/>
<public:method name=moveMe/>
<public:property name=clickPoint get=get_clickPoint put=put_clickPoint/>
<public:property name=interval get=get_interval put=put_interval/>
<script language=JScript>
var m_bStarted = false;
var m_bMoving = false;
var m_clickPoint = null;
var m_tStart = ;
var m_tEnd = ;
var m_ptStart = null;
var m_Slope = null;
var m_interval = ;
var m_isMoving = false;
var m_trash = ;
var m_dX = ;
var m_dY = ;
var m_vectX = ;
var m_vectY = ;
var m_pNode = null;
var m_bounds = [];
var BOUNDS = {left:top:right:bottom:};
var m_dimensions = [];
var DIMS = {width:height:};
function Init()
{
elementid = elementdocumentuniqueId;
var m_pNode = elementparentNode;
m_bounds = [
parseInt(m_pNodecurrentStylewidth)
parseInt(m_pNodecurrentStyleheight)
];
m_dimensions = [
Node parseInt(elementoffsetWidth)
parseInt(elementoffsetHeight)
];
}
function element_onmousedown()
{
m_bStarted = true;
m_tStart = new Date();
clearInterval(m_interval);
m_Slope = null;
m_ptStart = null;
m_trash = ;
m_dX = ;
m_dY = ;
m_vectX = ;
m_vectY = ;
m_clickPoint = new Point(eventx eventy);
m_ptStart = new Point(part(elementcurrentStyleleft) parseInt(elementcurrentStyletop));
}
function element_onmouseup()
{
if (!m_bMoving) return;
m_bMoving = false;
m_bStarted = false;
m_tEnd = new Date();
var t = m_tEndvalueOf() m_tStartvalueOf();
var lPoint = new Point(eventx eventy);
m_Slope = Geometryslope(m_clickPoint lPoint);
var ptEnd = m_Slopeadd(m_ptStart);
elementstyleleft = ptEndposX + px;
elementstyletop = ptEndposY + px;
var spd = ;
if (m_SlopedeltaX != && m_SlopedeltaY != )
{
spd = Mathsqrt(Mathpow(m_SlopedeltaX ) + Mathpow(m_SlopedeltaY))/t;
}
else
{
spd = (m_SlopedeltaX + m_SlopedeltaY)/t;
}
if (spd > ) spd = ;
m_dX = m_SlopedeltaX;
m_dY = m_SlopedeltaY;
if (m_dX != ) m_vectX = (m_dX > ) ? : ;
if (m_dY != ) m_vectY = (m_dY > ) ? : ;
startMove(element parseInt(/spd));
}
function element_onmousemove()
{
m_bMoving = m_bStarted;
if (!m_bMoving) return;
var lPoint = new Point(eventx eventy);
var lSlope = Geometryslope(m_clickPoint lPoint);
var ptEnd = lSlopeadd(m_ptStart);
elementstyleleft = ptEndposX + px;
elementstyletop = ptEndposY + px;
}
function element_onselectstart()
{
eventreturnValue = false;
return false;
}
function element_ondragstart()
{
eventreturnValue = false;
return false;
}
function get_clickPoint()
{
return m_clickPoint;
}
function put_clickPoint(o)
{
if (typeof(o) == object && nstructor == Point)
{
m_clickPoint = o;
}
else
{
alert(Expected Point);
}
}
function get_interval()
{
return m_interval;
}
function put_interval(n)
{
m_interval = n;
}
function moveMe()
{
if (m_isMoving) return;
setTimeout(m_isMoving = true; );
var newX = parseInt(elementcurrentStyleleft);
var newY = parseInt(elementcurrentStyletop);
var dXabs = Mathabs(m_dX);
var dYabs = Mathabs(m_dY);
if (dXabs > dYabs)
{
//divide both by deltaX
//each call move X by and Y by Y/X
//if iteration > then move Y by
//and add remainder back on Y
newX += m_vectX;
var l_step = (m_dY/m_dX) * ;
m_trash = m_trash + l_step;
if (m_trash > || m_trash < )
{
newY += m_vectY;
m_trash = m_vectX;
}
}
else
{
//viceversa
newY += m_vectY;
var l_step = (m_dX/m_dY) * ;
m_trash = m_trash + l_step;
if (m_trash > || m_trash < )
{
newX += m_vectX;
m_trash = m_vectX;
}
}
if (newX <= m_bounds[BOUNDSleft])
{
newX = m_bounds[BOUNDSleft] + ;
m_vectX *= ;
}
else if ((newX + m_dimensions[DIMSwidth]) >= m_bounds[BOUNDSright])
{
newX = m_bounds[BOUNDSright] m_dimensions[DIMSwidth] ;
m_vectX *= ;
}
if (newY <= m_bounds[BOUNDStop])
{
newY = m_bounds[BOUNDStop] + ;
m_vectY *= ;
}
else if ((newY + m_dimensions[DIMSheight]) >= m_bounds[BOUNDSbottom])
{
newY = m_bounds[BOUNDSbottom] m_dimensions[DIMSheight] ;
m_vectY *= ;
}
elementstyleleft = newX + px;
elementstyletop = newY + px;
setTimeout(m_isMoving = false; );
}
</script>
</public:component>
如果你注意到了脚本的顶部在那里有一个特殊的标签告诉浏览器该用何种样式呈现特性和包含组件的方法以及将这一组件添加到哪些事件中这些事件都是标准的HTML事件
当组件(在装载事件中)初始化时它获得一个uniqueID将其包含的母体记录在一个数字变量中并为进程计算设定缺省值当你逐句通过这一对象的目标处理器时你会看到每当用户点击对象时 element_onmousedown()一些变量进行了初始化下一步用户应该将对象拖动到另一个位置
当用户在屏幕上拖动对象时— element_onmousemove() —对象的位置发生改变以与鼠标的运动相匹配然后用户应该释放鼠标按钮让对象自行移动
当用户释放鼠标按钮— element_onmouseup() —或是鼠标脱离了对象区域— element_onmouseout() —时释放点即被记录下来并对用户点击对象到释放对象的时间进行计算对象则获得永恆运动通过计算得出点击起始点与释放终止点的斜度这个斜度成为对象新的移动路径通过对象移动的距离与拖动时间可计算出用户拖动对象的速度这个速度再又用来建立对象的移动方式最终速度的倒数被用来建立对象位置更新的时间间隔
在间隔中断事件— moveMe() —中对象的上升(rise)与运动(run)将方向斜度转换成计算的运动路径将较大的方向改变与较小的方向改变区分开来我们就可以做到这点结果是其中一个方向改变总是而另一个则小于在每次中断中两个方向改变中较大的一个由一个向量单元增加可能是或是个像素另一个则增加较小方向改变的两倍(即如果上升为而运动为的话那么上升将增加 *向量而运动每次增加 * 单元)如果较小的改变增量超过向量单元(或)的话
如果对象的新位置位于限定元素之外向量则发生改变以与之相匹配这种方法将对象反弹到限定元素之外
表B是含有这些组件的HTML页面
表 B 的内容
<html>
<head>
<style>
DIVbounds
{
width: px;
height: px;
border: px red solid;
overflow: hidden;
}
DIVobject
{
position:absolute;
left: px;
top: px;
border: px blue solid;
behavior: url(componenthtc);
cursor: hand;
}
</style>
<script language=JavaScript>
function Point(pX pY)
{
thisposX = pX;
thisposY = pY;
}
function CSlope(P P)
{
thisdeltaY = PposY PposY;
thisdeltaX = PposX PposX;
thism = (PposY PposY)/(PposX PposX);
}
function _slopeAdd(P)
{
var lPoint = new Point((PposX + thisdeltaX) (PposY + thisdeltaY));
return lPoint;
}
CSlopeprototypeadd = _slopeAdd;
function CGeometry() {}
function _slope(P P)
{
var lSlope = new CSlope(P P);
return lSlope;
}
CGeometryprototypeslope = _slope;
var Geometry = new CGeometry();
var objStack = [];
function startMove(obj t)
{
var id = objStackpush(obj);
objStack[id]interval = setInterval(objStack[ + (id ) + ]moveMe() t);
}
</script>
</head>
<body >
<center>
<div class=bounds id=divBounds name=divBounds onselectstart=windoweventreturnValue = false;>
<div class=object>dog</div>
</div>
</center>
</body>
</html>
HTML页面不过是包含<DIV>及作为组件元素的嵌套<DIV>在JavaScript内有一些支持对象与功能来帮助进行组件计算值得注意的是有一个对象栈— objStack —变量在间隔中断过程中可以用来帮助管理对组件moveMe()方法的调用
拷贝这些代码并将它粘贴到你自己的文件中记得把你的HTC文件命名为componenthtc特别用于行为样式特性在IE 或更高版本中运行这个例子看着你的对象充满活力